You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
🐹 Go Fan Report: github.com/modelcontextprotocol/go-sdk
The official Go SDK for Model Context Protocol (MCP), maintained jointly by Anthropic and Google. gh-aw uses it both as a server (exposing gh aw CLI commands as MCP tools via gh aw mcp-server) and as a client (inspecting other MCP servers in gh aw mcp inspect). Current pinned version is v1.6.0, the latest release — well within recommended freshness.
The SDK has shipped two minor releases since gh-aw's last bump (v1.5.0 and v1.6.0) and one of those changes silently weakens our HTTP MCP server's security posture, which is the headline finding below.
Summary
Files: 11 non-test files in pkg/cli/ + pkg/parser/ import the SDK
Status: ⚠️ One security-relevant follow-up from the v1.6.0 upgrade; otherwise idiomatic.
Critical Findings
🚨 1. CrossOriginProtection is no longer enabled by default (v1.6.0 behaviour change)
In v1.4.1–v1.5.0 the SDK enabled cross-origin protection whenever CrossOriginProtection in StreamableHTTPOptions was nil. v1.6.0 reversed this: nil now means no protection. The change is documented in the v1.6.0 release notes under "Cross-Origin Protection Default Change".
gh-aw's HTTP MCP server constructs its handler without setting this field:
That means anyone running gh aw mcp-server --port N against pre-v1.6.0 of the SDK was protected by the SDK default; after the v1.6.0 bump they are not. The same change retroactively applies to the SSE transport too (PR #891 added DNS-rebinding/cross-origin protections to SSE in v1.6.0).
Action: explicitly populate CrossOriginProtection with a sensible default (mirror what v1.5.0 did by default), or document that operators should set MCPGODEBUG=enableoriginverification=1. Recommend the former — the env-var route is easy to miss.
Improvement Opportunities
🏃 Quick Wins
Set CrossOriginProtection explicitly in pkg/cli/mcp_server_http.go:70 (see Critical Findings).
Factor the repeated select { case <-ctx.Done(): return newMCPError(...) default: } preamble (~11 occurrences across mcp_tools_readonly.go, mcp_tools_privileged.go, mcp_tools_management.go) into a small SendingMiddleware or wrapper that fails fast on cancelled context. Net: fewer lines, no behavioural change, one place to update.
The reserved , nil, nil extension-slot return at the end of every handler is purely SDK boilerplate. A thin wrapper helper would keep handler bodies focused on the actual result.
✨ Feature Opportunities
HTTP header standardisation (v1.6.0): mirrors JSON-RPC method/name into request headers so load balancers and observability tools can route MCP traffic without deep packet inspection. Useful once we have anything sitting in front of gh aw mcp-server --port.
DNS-rebinding/SSE cross-origin protections (PR Rename --workflow-dir to --workflows-dir #891, v1.6.0): opt-in via the same CrossOriginProtection field — fixing the Quick Win above gets us this for free.
extauth.ClientCredentialsHandler (v1.6.0): new OAuth 2.0 client-credentials grant helper. Worth keeping in mind for any future MCP-client code path where gh-aw needs to talk to a third-party MCP server protected by client-credentials OAuth. (Distinct from the workflow-level AuthStrategyOAuthClientCreds in pkg/workflow/engine_definition.go, which is about engine HTTP auth, not MCP transport auth — not a replacement candidate.)
📐 Best Practice Alignment
The IsError: false JSON-envelope pattern used by audit / audit-diff (pkg/cli/mcp_tools_privileged.go:453,567) aligns with the v1.5.0 direction of returning structured tool results rather than JSON-RPC errors for application-level failures. Correct usage — no change needed.
argumentValidationMiddleware already gates on IsError=true before rewriting (pkg/cli/mcp_argument_validation.go:52). Good defensive coding.
ServerCapabilities{Tools{ListChanged: false}} is correct since gh-aw's tool set is static — avoids unnecessary notifications.
ToolAnnotations (ReadOnlyHint, IdempotentHint, DestructiveHint, OpenWorldHint) are set thoughtfully on every tool. Idiomatic.
🔧 General Improvements
pkg/cli/mcp_inspect_mcp.go swallows errors from session.ListTools / session.ListResources (only logs when verbose). For an inspector this is intentional, but consider surfacing them in the structured MCPServerInfo output so callers know capabilities are partial.
SetError(...) is not used anywhere in gh-aw — handlers construct CallToolResult manually. The v1.6.0 SetError behaviour change (preserves existing Content) therefore does not affect us. ✅
Recommendations (prioritised)
Patch the cross-origin regression by explicitly setting CrossOriginProtection in pkg/cli/mcp_server_http.go.
Extract the ctx.Done() boilerplate into a middleware once rejig docs #1 lands.
Track the v1.6.0 HTTP header standardisation feature for the next time we revisit the HTTP MCP server's deployment model.
Next Steps
Open a small PR addressing rejig docs #1 (security regression) — single-file change with a regression test verifying the option is set.
Open a follow-up issue for the middleware refactor if the team agrees on the direction.
Generated by Go Fan Module summary saved to: scratchpad/mods/modelcontextprotocol-go-sdk.md
🐹 Go Fan Report:
github.com/modelcontextprotocol/go-sdkThe official Go SDK for Model Context Protocol (MCP), maintained jointly by Anthropic and Google. gh-aw uses it both as a server (exposing
gh awCLI commands as MCP tools viagh aw mcp-server) and as a client (inspecting other MCP servers ingh aw mcp inspect). Current pinned version is v1.6.0, the latest release — well within recommended freshness.The SDK has shipped two minor releases since gh-aw's last bump (v1.5.0 and v1.6.0) and one of those changes silently weakens our HTTP MCP server's security posture, which is the headline finding below.
Summary
pkg/cli/+pkg/parser/import the SDKmcp.NewServer,mcp.AddTool[Args],mcp.ToolAnnotations,mcp.NewStreamableHTTPHandler,mcp.CommandTransport,mcp.StreamableClientTransport,server.AddReceivingMiddleware,jsonrpc.ErrorCritical Findings
🚨 1.
CrossOriginProtectionis no longer enabled by default (v1.6.0 behaviour change)In v1.4.1–v1.5.0 the SDK enabled cross-origin protection whenever
CrossOriginProtectioninStreamableHTTPOptionswas nil. v1.6.0 reversed this: nil now means no protection. The change is documented in the v1.6.0 release notes under "Cross-Origin Protection Default Change".gh-aw's HTTP MCP server constructs its handler without setting this field:
That means anyone running
gh aw mcp-server --port Nagainst pre-v1.6.0 of the SDK was protected by the SDK default; after the v1.6.0 bump they are not. The same change retroactively applies to the SSE transport too (PR #891 added DNS-rebinding/cross-origin protections to SSE in v1.6.0).Action: explicitly populate
CrossOriginProtectionwith a sensible default (mirror what v1.5.0 did by default), or document that operators should setMCPGODEBUG=enableoriginverification=1. Recommend the former — the env-var route is easy to miss.Improvement Opportunities
🏃 Quick Wins
CrossOriginProtectionexplicitly inpkg/cli/mcp_server_http.go:70(see Critical Findings).select { case <-ctx.Done(): return newMCPError(...) default: }preamble (~11 occurrences acrossmcp_tools_readonly.go,mcp_tools_privileged.go,mcp_tools_management.go) into a smallSendingMiddlewareor wrapper that fails fast on cancelled context. Net: fewer lines, no behavioural change, one place to update., nil, nilextension-slot return at the end of every handler is purely SDK boilerplate. A thin wrapper helper would keep handler bodies focused on the actual result.✨ Feature Opportunities
gh aw mcp-server --port.CrossOriginProtectionfield — fixing the Quick Win above gets us this for free.extauth.ClientCredentialsHandler(v1.6.0): new OAuth 2.0 client-credentials grant helper. Worth keeping in mind for any future MCP-client code path where gh-aw needs to talk to a third-party MCP server protected by client-credentials OAuth. (Distinct from the workflow-levelAuthStrategyOAuthClientCredsinpkg/workflow/engine_definition.go, which is about engine HTTP auth, not MCP transport auth — not a replacement candidate.)📐 Best Practice Alignment
IsError: falseJSON-envelope pattern used byaudit/audit-diff(pkg/cli/mcp_tools_privileged.go:453,567) aligns with the v1.5.0 direction of returning structured tool results rather than JSON-RPC errors for application-level failures. Correct usage — no change needed.argumentValidationMiddlewarealready gates onIsError=truebefore rewriting (pkg/cli/mcp_argument_validation.go:52). Good defensive coding.ServerCapabilities{Tools{ListChanged: false}}is correct since gh-aw's tool set is static — avoids unnecessary notifications.ToolAnnotations(ReadOnlyHint,IdempotentHint,DestructiveHint,OpenWorldHint) are set thoughtfully on every tool. Idiomatic.🔧 General Improvements
pkg/cli/mcp_inspect_mcp.goswallows errors fromsession.ListTools/session.ListResources(only logs whenverbose). For an inspector this is intentional, but consider surfacing them in the structuredMCPServerInfooutput so callers know capabilities are partial.SetError(...)is not used anywhere in gh-aw — handlers constructCallToolResultmanually. The v1.6.0SetErrorbehaviour change (preserves existingContent) therefore does not affect us. ✅Recommendations (prioritised)
CrossOriginProtectioninpkg/cli/mcp_server_http.go.ctx.Done()boilerplate into a middleware once rejig docs #1 lands.Next Steps
Generated by Go Fan
Module summary saved to:
scratchpad/mods/modelcontextprotocol-go-sdk.md