Repository navigation
[go-fan] Go Module Review: modelcontextprotocol/go-sdk #6981
Description
🐹 Go Fan Report: modelcontextprotocol/go-sdk
Module Overview
github.com/modelcontextprotocol/go-sdk is the official Go SDK for the Model Context Protocol (MCP), maintained by Anthropic and the MCP community. It provides the core building blocks for both MCP clients and servers: transport types (stdio, streamable HTTP, SSE), session management, tool/resource/prompt registration, and type-safe protocol structs.
This is the most critical dependency in the project — it is the protocol layer that gh-aw-mcpg proxies between clients and backend MCP servers.
Current Usage in gh-aw
The SDK is used across 35 files with a single import alias sdk:
sdk "github.com/modelcontextprotocol/go-sdk/mcp"- Files: 35 (26 production + 9 test)
- Import Count: 1 unique import path (
/mcpsubpackage) - Key APIs Used:
sdk.Client/sdk.NewClient— MCP client for connecting to backendssdk.ClientSession/session.Connect()— session lifecyclesdk.Server/sdk.NewServer— MCP server for exposing tools to clientssdk.CommandTransport— stdio backend process communicationsdk.StreamableClientTransport— streamable HTTP (2025-03-26 spec)sdk.SSEClientTransport— legacy SSE transport (2024-11-05 spec)sdk.NewStreamableHTTPHandler— HTTP handler for serving MCP over streamable transportsdk.NewInMemoryTransports— in-memory transport pair for unit testssdk.ErrSessionMissing— typed sentinel for session expiry detectionsdk.CallToolResult,sdk.CallToolRequest— tool invocation typessdk.TextContent,sdk.ImageContent,sdk.AudioContent,sdk.EmbeddedResource— content typessdk.Tool,sdk.Resource,sdk.Prompt— protocol entity typessdk.ClientOptions/sdk.ServerOptions— withLoggerandKeepAlivefields
Research Findings
Architecture Decisions
The project uses the SDK in a sophisticated proxy gateway pattern:
- The gateway itself is an SDK server (exposing tools to upstream clients)
- The gateway is also an SDK client (connecting to downstream MCP backends)
- Multiple transport fallback strategies are implemented (streamable → SSE → plain JSON-RPC)
Notable Usage Patterns
Multi-transport fallback (NewHTTPConnection):
1. Try streamable HTTP (2025-03-26 spec)
2. Try SSE (2024-11-05 spec) with deprecation warning
3. Fall back to plain JSON-RPC HTTP
This is well-architected and spec-compliant.
Session reconnection with sdk.ErrSessionMissing:
if err != nil && isSessionNotFoundError(err) {
// reconnect + retry once
}Proper use of the typed sentinel added in v1.5.0.
MaxRetries sentinel on StreamableClientTransport:
MaxRetries: -1, // Disables SDK retry; gateway manages reconnectionClever — prevents double-retry but depends on SDK internals verified per-version.
In-memory transports for testing:
serverTransport, clientTransport := sdk.NewInMemoryTransports()Excellent — fast, deterministic, no I/O in unit tests.
Recent Updates
- v1.6.1 (latest) vs v1.6.0 (in use) — one patch version behind; likely bug fixes
- v1.6.0 added
DisableStandaloneSSEonStreamableClientTransport(used correctly) - v1.5.0 added
sdk.ErrSessionMissing(used correctly)
Improvement Opportunities
🏃 Quick Wins
-
Bump to v1.6.1 — The project is one patch behind. There's an explicit comment in
tool_registry.gothatregisterToolWithoutValidationmust be re-verified on every SDK upgrade. A patch bump is low-risk and ensures the latest bug fixes.go get github.com/modelcontextprotocol/go-sdk@v1.6.1 go mod tidy
After bumping, re-verify the comment at
tool_registry.go:53still holds for v1.6.1. -
Add a version canary test for
DisableStandaloneSSE— The project already hasTestMaxRetriesSentinelCanaryto guard againstMaxRetries: -1semantics changing. A similar canary forDisableStandaloneSSEfield existence/behavior would prevent silent regressions on future upgrades.
✨ Feature Opportunities
-
sdk.AddTool[In, Out]typed registration (selective use) — The project usesserver.AddTool(tool, handler)everywhere to bypass schema validation (needed for draft-07 backend schemas). However, for internally-defined tools (e.g., DIFCsystools registered directly by the gateway), using typedsdk.AddTool[In, Out](server, tool, handler)would provide compile-time type safety and auto-validation at no cost. The bypass is only needed for proxied backend tools. -
session.Ping()for proactive health checks — If the SDKClientSessionexposes aPing()method, it could be used proactively to detect stale sessions before tool calls arrive, rather than discovering expiry at call time and reconnecting reactively.
📐 Best Practice Alignment
-
Duplicate pagination guards — Both
paginateAll(internal/mcp/pagination.go) andpaginate(internal/testutil/mcptest/validator.go) implement pagination with loop protection. The comment says "keep loop-protection invariants aligned", but divergence could occur over time. Consider exportingpaginateAll(or a shared util) for reuse in the validator to eliminate the duplication risk. -
JSON round-trip in
callParamMethod—unmarshalParamsdoesjson.Marshal(params) + json.Unmarshal(...)for every method call. For plain JSON-RPC backends this chains: receive raw JSON → unmarshal tointerface{}→ re-marshal → unmarshal to typed struct. A future refactor could acceptjson.RawMessagedirectly to save one cycle.
🔧 General Improvements
-
Content type extensibility —
convertContentItemhandlestext,image,audio,resource. As the MCP spec evolves, new content types may appear (e.g.,video). Thedefaultunknown-type fallback is graceful, but elevating the existing log warning to a structured metric/counter would improve observability for new content types in production. -
InitializeResult()nil guards — Bothconnection.go:ServerInfo()andvalidator.go:GetServerInfo()correctly guard for nilInitializeResult(). Adding a comment cross-referencing the SDK contract (nil beforeConnectcompletes) would improve future maintainability.
Module Summary
| Field | Value |
|---|---|
| Module | github.com/modelcontextprotocol/go-sdk |
| Version | v1.6.0 |
| Repository | https://github.com/modelcontextprotocol/go-sdk |
| Latest Release | v1.6.1 |
| Last Reviewed | 2026-06-04 |
Key Features
- Official MCP Go SDK from the MCP project
- Supports stdio, streamable HTTP (2025-03-26), and SSE (2024-11-05) transports
- Client + server in one package
- In-memory transport pair for hermetic testing
- Typed error sentinel
ErrSessionMissingfor session lifecycle - Typed generic
AddTool[In, Out]for schema-validated tool registration KeepAlivesupport viaClientOptions.KeepAliveslog.Loggerintegration
References
- Repository: https://github.com/modelcontextprotocol/go-sdk
- MCP Spec: (modelcontextprotocol.io/redacted)
Recommendations
- 🔴 [High] Bump
go-sdkto v1.6.1 and re-verifyregisterToolWithoutValidationSDK behavior - 🟡 [Medium] Use typed
sdk.AddTool[In, Out]for internally-defined gateway tools (DIFC sys tools) - 🟡 [Medium] Consolidate the two pagination helpers (
paginateAll+paginate) to eliminate drift risk - 🟢 [Low] Add a
DisableStandaloneSSEbehavior canary test alongsideTestMaxRetriesSentinelCanary - 🟢 [Low] Investigate
session.Ping()availability for proactive session health checks - 🟢 [Low] Consider direct
json.RawMessagepath inunmarshalParamsto reduce marshal overhead
Next Steps
- Run
go get github.com/modelcontextprotocol/go-sdk@v1.6.1 && go mod tidyand verify tests pass - Audit
tool_registry.go:53comment validity against v1.6.1 SDK source - Check if typed
AddTool[In, Out]could replace anyregisterToolWithoutValidationcalls for DIFC sys tools
Generated by Go Fan 🐹 · Run §26940372029
Note
🔒 Integrity filter blocked 36 items
The following items were blocked because they don't meet the GitHub integrity level.
- open-telemetry/opentelemetry-go@c221f3e
list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - modelcontextprotocol/go-sdk@c60a318
list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/tree/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/.agents
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/tree/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/.devcontainer
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/tree/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/.github
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/blob/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/.gitignore
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/blob/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/AGENTS.md
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/blob/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/CONTRIBUTING.md
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/blob/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/LICENSE
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/blob/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/README.md
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/blob/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/ROADMAP.md
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/blob/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/SECURITY.md
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/tree/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/auth
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/tree/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/conformance
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/blob/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/copyright_test.go
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/tree/c60a318d223cb6a9d0c25b04963b0e9ea54ff6ae/design
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - ... and 20 more items
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | noneGenerated by Go Fan · sonnet46 2M · ◷
- expires on Jun 11, 2026, 8:36 AM UTC
Activity
github-actions commentedon Jun 4, 2026
🤖 This is an automated response from Repo Assist.
Good analysis from Go Fan. A few notes on the recommendations:
Rec 1 (bump go-sdk to v1.6.1) — This is the clearest quick win. The existing comment at
tool_registry.go:53explicitly calls out the need to re-verifyregisterToolWithoutValidationon every SDK upgrade, so a patch bump is exactly the kind of change that should be done promptly with a targeted review of that function against the v1.6.1 source. Worth doing soon.Rec 4 (add
DisableStandaloneSSEcanary test) — The existingTestMaxRetriesSentinelCanaryis a good pattern. A companion canary forDisableStandaloneSSEfield existence would be a low-effort, high-value addition to prevent silent regressions on future upgrades.Rec 3 (consolidate
paginateAll+paginate) — The loop-protection drift risk is real but low-frequency. Worth tracking as a future clean-up rather than rushing.Rec 6 (direct
json.RawMessageinunmarshalParams) — Agreed this is a valid micro-optimisation for the hot path, but the current double-marshal approach is at least correct and obvious. Fine to defer.Recs 2 and 5 (typed
AddTool[In, Out]for internal tools,session.Ping()) are more speculative — worth investigating but no urgency.The SDK bump (Rec 1) is the most actionable item here.
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
proxy.golang.orgSee Network Configuration for more information.
Add this agentic workflows to your repo
To install this agentic workflow, run