From 5d2ce0847ddd9c85a9f9a178e4b565f6c8ae341f Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Sun, 5 Jul 2026 04:38:10 +0530 Subject: [PATCH] refactor(mcp): move server scaffolding to shared hawk-mcpkit; release 0.1.2 The MCP server now delegates construction, stdio/streamable-HTTP transports, and argument/result helpers to hawk-mcpkit. Tool names, schemas, and behavior unchanged. Advertised server version now tracks the VERSION file (sight.Version). VERSION bumped to 0.1.2. --- CHANGELOG.md | 9 ++++++- VERSION | 2 +- go.mod | 1 + go.sum | 2 ++ mcp/server.go | 70 +++++++++++++-------------------------------------- 5 files changed, 30 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a538651..5bb9689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,16 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm --- -## [Unreleased] +## [0.1.2] - 2026-07-04 ### Changed +- **MCP server scaffolding moved to the shared + [`hawk-mcpkit`](https://github.com/GrayCodeAI/hawk-mcpkit) module.** + `mcp/server.go` now delegates server construction, the stdio and + streamable-HTTP transports, and argument/result helpers to the kit. + Tool names, schemas, and behavior are unchanged. The advertised MCP + server version now tracks the `VERSION` file (`sight.Version`) + instead of a hardcoded string. - **Version re-baselined to `0.1.0`** across the MCP server advertisement and both SARIF driver-version sites. Aligns sight with the rest of the hawk-eco ecosystem (`hawk`, `tok`, `eyrie`, `yaad`, `trace`, diff --git a/VERSION b/VERSION index 6e8bf73..d917d3e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0 +0.1.2 diff --git a/go.mod b/go.mod index f74fe94..357d76b 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.26.4 require ( github.com/GrayCodeAI/hawk-core-contracts v0.1.2 + github.com/GrayCodeAI/hawk-mcpkit v0.1.0 github.com/mark3labs/mcp-go v0.49.0 golang.org/x/tools v0.45.0 ) diff --git a/go.sum b/go.sum index 59048fc..79a320b 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/GrayCodeAI/hawk-core-contracts v0.1.2 h1:2N6mc6fwIx1zKAi9nD6GoVF6EQ+b3flSrjM+Biioyxo= github.com/GrayCodeAI/hawk-core-contracts v0.1.2/go.mod h1:J+I2YYTS3hDwf01bmo1ejbMzOTdYxGn9rZa8CME0pRM= +github.com/GrayCodeAI/hawk-mcpkit v0.1.0 h1:CXJ7V80eHgrDJ3fytE0Nx60RM5VgKe2YF+c3KcjD+ws= +github.com/GrayCodeAI/hawk-mcpkit v0.1.0/go.mod h1:xQpwS9OZCC8qlvEwFXXOYOWQRbYL/OFSI6/5VGvd0hQ= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= diff --git a/mcp/server.go b/mcp/server.go index 9ebffac..73f87a1 100644 --- a/mcp/server.go +++ b/mcp/server.go @@ -2,13 +2,11 @@ package mcp import ( "context" - "encoding/json" "fmt" - "os" "strings" + mcpkit "github.com/GrayCodeAI/hawk-mcpkit" mcplib "github.com/mark3labs/mcp-go/mcp" - mcpserver "github.com/mark3labs/mcp-go/server" "github.com/GrayCodeAI/sight" ) @@ -16,7 +14,7 @@ import ( // Server wraps the sight library as an MCP server, exposing code review // capabilities to any MCP-compatible agent. type Server struct { - server *mcpserver.MCPServer + kit *mcpkit.Server provider sight.Provider opts []sight.Option } @@ -24,50 +22,45 @@ type Server struct { // New creates a sight MCP server with the given LLM provider and options. func New(provider sight.Provider, opts ...sight.Option) *Server { s := &Server{ + kit: mcpkit.New("sight", sight.Version), provider: provider, opts: opts, } - s.server = mcpserver.NewMCPServer( - "sight", "0.1.0", - mcpserver.WithToolCapabilities(true), - ) s.registerTools() return s } // ServeStdio starts the MCP server on stdin/stdout. func (s *Server) ServeStdio() error { - stdio := mcpserver.NewStdioServer(s.server) - return stdio.Listen(context.Background(), os.Stdin, os.Stdout) + return s.kit.ServeStdio() } // ServeHTTP starts the MCP server on a streamable HTTP endpoint. Clients // connect to http:///mcp. func (s *Server) ServeHTTP(addr string) error { - httpServer := mcpserver.NewStreamableHTTPServer(s.server) - return httpServer.Start(addr) + return s.kit.ServeHTTP(addr) } func (s *Server) registerTools() { - s.server.AddTool(mcplib.NewTool( + s.kit.AddTool(mcplib.NewTool( "sight_review", mcplib.WithDescription("Run AI code review on a unified diff"), mcplib.WithString("diff", mcplib.Required(), mcplib.Description("Unified diff text to review")), ), s.handleReview) - s.server.AddTool(mcplib.NewTool( + s.kit.AddTool(mcplib.NewTool( "sight_describe", mcplib.WithDescription("Generate a PR description from a unified diff"), mcplib.WithString("diff", mcplib.Required(), mcplib.Description("Unified diff text")), ), s.handleDescribe) - s.server.AddTool(mcplib.NewTool( + s.kit.AddTool(mcplib.NewTool( "sight_improve", mcplib.WithDescription("Suggest code improvements (non-bug focused)"), mcplib.WithString("diff", mcplib.Required(), mcplib.Description("Unified diff text")), ), s.handleImprove) - s.server.AddTool(mcplib.NewTool( + s.kit.AddTool(mcplib.NewTool( "sight_taint", mcplib.WithDescription("Run SSA-based cross-function taint analysis on Go packages and return security findings (no LLM required)"), mcplib.WithString("path", mcplib.Required(), mcplib.Description("Filesystem path to the module/directory to analyze")), @@ -76,12 +69,12 @@ func (s *Server) registerTools() { } func (s *Server) handleTaint(ctx context.Context, req mcplib.CallToolRequest) (*mcplib.CallToolResult, error) { - path := strArg(req, "path") + path := mcpkit.StrArg(req, "path") if path == "" { return mcplib.NewToolResultError("path is required"), nil } var patterns []string - if p := strArg(req, "patterns"); p != "" { + if p := mcpkit.StrArg(req, "patterns"); p != "" { for _, part := range strings.Split(p, ",") { if part = strings.TrimSpace(part); part != "" { patterns = append(patterns, part) @@ -94,16 +87,11 @@ func (s *Server) handleTaint(ctx context.Context, req mcplib.CallToolRequest) (* if err != nil { return mcplib.NewToolResultError(fmt.Sprintf("taint analysis failed: %v", err)), nil } - - b, err := json.MarshalIndent(findings, "", " ") - if err != nil { - return nil, err - } - return mcplib.NewToolResultText(string(b)), nil + return mcpkit.JSONResult(findings) } func (s *Server) handleReview(ctx context.Context, req mcplib.CallToolRequest) (*mcplib.CallToolResult, error) { - diff := strArg(req, "diff") + diff := mcpkit.StrArg(req, "diff") if diff == "" { return mcplib.NewToolResultError("diff is required"), nil } @@ -113,16 +101,11 @@ func (s *Server) handleReview(ctx context.Context, req mcplib.CallToolRequest) ( if err != nil { return mcplib.NewToolResultError(fmt.Sprintf("review failed: %v", err)), nil } - - b, err := json.MarshalIndent(result, "", " ") - if err != nil { - return nil, err - } - return mcplib.NewToolResultText(string(b)), nil + return mcpkit.JSONResult(result) } func (s *Server) handleDescribe(ctx context.Context, req mcplib.CallToolRequest) (*mcplib.CallToolResult, error) { - diff := strArg(req, "diff") + diff := mcpkit.StrArg(req, "diff") if diff == "" { return mcplib.NewToolResultError("diff is required"), nil } @@ -132,16 +115,11 @@ func (s *Server) handleDescribe(ctx context.Context, req mcplib.CallToolRequest) if err != nil { return mcplib.NewToolResultError(fmt.Sprintf("describe failed: %v", err)), nil } - - b, err := json.MarshalIndent(desc, "", " ") - if err != nil { - return nil, err - } - return mcplib.NewToolResultText(string(b)), nil + return mcpkit.JSONResult(desc) } func (s *Server) handleImprove(ctx context.Context, req mcplib.CallToolRequest) (*mcplib.CallToolResult, error) { - diff := strArg(req, "diff") + diff := mcpkit.StrArg(req, "diff") if diff == "" { return mcplib.NewToolResultError("diff is required"), nil } @@ -151,17 +129,5 @@ func (s *Server) handleImprove(ctx context.Context, req mcplib.CallToolRequest) if err != nil { return mcplib.NewToolResultError(fmt.Sprintf("improve failed: %v", err)), nil } - - b, err := json.MarshalIndent(result, "", " ") - if err != nil { - return nil, err - } - return mcplib.NewToolResultText(string(b)), nil -} - -func strArg(req mcplib.CallToolRequest, key string) string { - if v, ok := req.GetArguments()[key].(string); ok { - return v - } - return "" + return mcpkit.JSONResult(result) }