Skip to content

[go-fan] Go Module Review: modelcontextprotocol/go-sdk (v1.6.0 โ€” silent cross-origin regression)ย #32992

Description

@github-actions

๐Ÿน Go Fan Report: github.com/modelcontextprotocol/go-sdk

Module Overview

The official Go SDK for the Model Context Protocol (MCP), maintained by Anthropic in collaboration with Google. It provides typed MCP clients and servers, stdio/command/streamable-HTTP transports, OAuth helpers, JSON-RPC primitives, and middleware hooks.

Current Usage in gh-aw

  • Files: 26 (.go imports across pkg/cli + pkg/parser)
  • Import count: 282 symbol references
  • Current version: v1.6.0
  • Roles: gh-aw both hosts an MCP server (gh aw mcp-server) and acts as an MCP client (gh aw mcp inspect)

Key APIs in use

API Where
mcp.NewServer / mcp.NewClient pkg/cli/mcp_server.go:47, pkg/cli/mcp_inspect_mcp.go:167,233
mcp.AddTool[In, Out] (generic typed tools) pkg/cli/mcp_tools_*.go (10 tools)
mcp.StdioTransport / CommandTransport / StreamableClientTransport pkg/cli/mcp_server_command.go:171, pkg/cli/mcp_inspect_mcp.go:170,240
mcp.NewStreamableHTTPHandler + StreamableHTTPOptions pkg/cli/mcp_server_http.go:68-73
server.AddReceivingMiddleware pkg/cli/mcp_server.go:90 (custom "Did you mean?" middleware)
mcp.ToolAnnotations{ReadOnlyHint, IdempotentHint, OpenWorldHint, DestructiveHint} all tool registrations
mcp.Icon{Source: "๐Ÿ“Š"} every tool
jsonrpc.Error + Code{InternalError,InvalidParams,MethodNotFound} pkg/cli/mcp_error.go, mcp_argument_validation.go
jsonschema.For[T] + AddSchemaDefault (SEP-1024 elicitation) pkg/cli/mcp_schema.go

Research Findings

Recent Updates (v1.6.0 โ€” 2026-05-08)

  • ๐Ÿšจ Behavior change: Cross-Origin Protection no longer enabled by default when StreamableHTTPOptions.CrossOriginProtection is nil. Restore via MCPGODEBUG=enableoriginverification=1 or by setting the field explicitly.
  • โœจ New auth.ClientCredentialsHandler โ€” OAuth 2.0 Client Credentials grant (RFC 6749 ยง4.4) for service-to-service authentication.
  • ๐Ÿ› SetError preserves existing Content (previously clobbered it). Revert via MCPGODEBUG=seterroroverwrite=1.
  • ๐Ÿ”’ DNS rebinding + cross-origin protections added to SSE transport (Rename --workflow-dir to --workflows-dirย #891).
  • ๐Ÿ› Race condition fix in ServerSession.startKeepalive (Add agentic workflow run information to step summaryย #856).
  • ๐Ÿ› Keepalive no longer closes the session when ping returns method-not-found.
  • โœจ Streamable transport now accepts parameterized Content-Type (e.g. application/json; charset=utf-8).
  • โœจ OAuth flow no longer re-prompts after a cancelled Authorize.
  • โžก๏ธ CrossOriginProtection field is now deprecated โ€” wrap the handler with http.NewCrossOriginProtection() middleware instead. Removed in v1.8.0.

Best Practices from the README

  • Tools are added with mcp.AddTool(server, &mcp.Tool{...}, handler) where the handler signature is func(ctx, *CallToolRequest, In) (*CallToolResult, Out, error).
  • Servers run via server.Run(ctx, transport) for stdio or NewStreamableHTTPHandler for HTTP.
  • Layer behavior via AddReceivingMiddleware / AddSendingMiddleware.

Improvement Opportunities

๐Ÿƒ Quick Wins

1. ๐Ÿšจ Restore cross-origin protection on the HTTP MCP server (security regression)

pkg/cli/mcp_server_http.go:64-74 passes CrossOriginProtection: nil in mcp.StreamableHTTPOptions. In v1.4.1โ€“v1.5.0 this meant default protection was enabled. In v1.6.0 it now means NO protection. This regression arrived silently with the dependency bump.

Forward-compatible fix (recommended by the SDK, since the field is deprecated and removed in v1.8.0):

// Wrap the handler with cross-origin protection middleware
handler := mcp.NewStreamableHTTPHandler(getServer, &mcp.StreamableHTTPOptions{
    SessionTimeout: 2 * time.Hour,
    Logger:         logger.NewSlogLoggerWithHandler(mcpLog),
})
protection := http.NewCrossOriginProtection()
handlerWithLogging := loggingHandler(protection.Handler(handler))

2. Audit IdempotentHint: true on tools that mutate state

MCP's IdempotentHint means "calling it again with identical args produces the same result without additional effects". Two current uses don't match that contract:

  • compile (pkg/cli/mcp_tools_readonly.go:104-108) writes .lock.yml files.
  • logs (pkg/cli/mcp_tools_privileged.go:69-73) downloads new artifacts on each call.

Consider dropping IdempotentHint from these tools, or repositioning them as ReadOnlyHint: false.

3. Replace the HTTP loggingHandler with a sending middleware

pkg/cli/mcp_server_http.go:31-61 reimplements request/response logging at the HTTP layer. The SDK already accepts a Logger in StreamableHTTPOptions; an AddSendingMiddleware on the server could log MCP method-level traffic (rather than just HTTP frames).

โœจ Feature Opportunities

1. Expose compiled lock files as MCP Resources

Today the server only exposes tools. The Resource primitive is a natural fit for .lock.yml files: clients could resources/list and resources/read instead of re-running compile. The SDK supports server.AddResource for this.

2. Emit ProgressNotification for long-running tools

compile --zizmor --poutine --actionlint and logs can take minutes. The MCP spec includes progress notifications โ€” clients like Claude Desktop and Cline render them as progress bars. Wiring this up turns opaque blocking calls into interactive feedback.

3. Optional OAuth for the HTTP MCP server

pkg/cli/mcp_server_http.go currently has no auth on the HTTP transport. With v1.6.0's auth.ClientCredentialsHandler (OAuth 2.0 client-credentials grant), gh-aw could optionally require service-to-service auth when serving HTTP โ€” stdio remains naturally guarded by process ownership.

4. DNS rebinding protection if/when SSE is added

PR #891 added DNS rebinding + cross-origin protections to the SSE transport. gh-aw doesn't use SSE today, but it's the right protection for any future long-lived stream.

๐Ÿ“ Best Practice Alignment

  • Migrate off the deprecated StreamableHTTPOptions.CrossOriginProtection field (removed in v1.8.0). The SDK docs explicitly recommend wrapping the handler with http.NewCrossOriginProtection() middleware instead.
  • The mcp-inspect 5-second MCPOperationTimeout (pkg/cli/mcp_inspect_mcp.go:25) is hard-coded โ€” large remote tool lists may time out. Consider a --mcp-timeout flag.
  • Verify that the SDK's new "log out-of-band errors" (PR Rename --workflow-dir to --workflows-dir and add support across all workflow commandsย #887) messages are reaching gh-aw's mcp:server debug stream via the configured Logger.

๐Ÿ”ง General Improvements

  • Tool icons use single emoji glyphs (mcp.Icon{Source: "๐Ÿ“Š"}). Icon.Source supports URLs / data URLs โ€” richer artwork would improve discoverability in MCP tool pickers.
  • Document MCPGODEBUG (the new mechanism for restoring legacy SDK behavior) in docs/ so future debuggers find it.
  • Re-evaluate the manual *mcp.CallToolParamsRaw extraction in pkg/cli/mcp_argument_validation.go:99-103 on the next SDK release โ€” there may be a typed helper.

Recommendations

Prioritized actions:

  1. P0 (security): Restore cross-origin protection on the HTTP MCP server. Wrap the handler with http.NewCrossOriginProtection() โ€” forward-compatible with v1.8.0.
  2. P1: Correct IdempotentHint annotations on compile and logs.
  3. P2: Adopt ProgressNotification for compile and logs.
  4. P3: Expose .lock.yml files as MCP Resources.
  5. P3: Consider OAuth client-credentials for HTTP-served sessions.

Next Steps

  • Open a focused PR fixing the cross-origin protection regression (small, scoped, security-flagged).
  • Add a separate PR auditing IdempotentHint annotations.
  • Track v1.7.0 / 2026-06-30 spec features: automatic application_type (SEP-837), HTTP header standardization for method/name (SEP-2243).

References:


Generated by Go Fan
Module summary saved to: scratchpad/mods/modelcontextprotocol-go-sdk.md

Generated by ๐Ÿน Go Fan ยท โ— 12.3M ยท โ—ท

  • expires on May 19, 2026, 9:06 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions