-
Notifications
You must be signed in to change notification settings - Fork 20
[go-fan] Go Module Review: modelcontextprotocol/go-sdkΒ #2911
Description
πΉ Go Fan Report: modelcontextprotocol/go-sdk
Module Overview
github.com/modelcontextprotocol/go-sdk (v1.4.1) is the official Go implementation of the Model Context Protocol. It is the single most critical dependency in this repository β the entire gateway is built on top of it. It provides server construction, client management, typed protocol operations (tools, resources, prompts), and multiple transport implementations (stdio, streamable HTTP, SSE, in-memory).
The project imports it under the alias sdk "github.com/modelcontextprotocol/go-sdk/mcp" consistently across 26 files (12 production, 14 test).
Current Usage in gh-aw-mcpg
The SDK is used at every layer of the gateway stack:
- Files: 26 total (12 production, 14 test)
- Import Count: All production usages use a consistent
sdkalias - Key APIs Used:
sdk.NewServer/server.AddToolβ Gateway-side MCP server construction and tool registrationsdk.NewClient/sdk.ClientSession.*β Backend MCP client connections and typed protocol callssdk.NewStreamableHTTPHandlerβ Streamable HTTP transport hosting (both unified and routed modes)sdk.CommandTransport,sdk.StreamableClientTransport,sdk.SSEClientTransportβ Backend transport selectionsdk.NewInMemoryTransportsβ In-memory transport pairs for unit testingsdk.CallToolResult,sdk.TextContent,sdk.ImageContent,sdk.AudioContent,sdk.EmbeddedResourceβ Full MCP content type coveragesdk.ServerOptions/sdk.ClientOptions/sdk.StreamableHTTPOptionsβ Logger integration via slog adapter
Notable Usage Pattern: server.AddTool vs sdk.AddTool
The project consistently uses the method form server.AddTool(tool, handler) instead of the package-level sdk.AddTool(server, input, handler). This is intentional and well-documented: the method form bypasses schema validation, which is necessary because backend MCP servers return tools with JSON Schema draft-07 (or other versions) that the SDK's sdk.AddTool function would reject.
Research Findings
The SDK is at v1.4.1 β on the latest version. The project is well-aligned with the SDK's core patterns and benefits from full MCP 2025-11-25 protocol support.
Recent Updates
- v1.4.x added
StreamableHTTPOptions.Statelessmode for stateless session handling NewInMemoryTransportsenables proper unit testing without external processesslog-based logger integration viaServerOptions.Logger,ClientOptions.Logger, andStreamableHTTPOptions.Logger
Best Practices (observed in project)
- β
Using typed protocol methods (
ListTools,CallTool,ListResources, etc.) over raw JSON-RPC - β
sloglogger integration wired through project's debug logger system - β
NewInMemoryTransportsused for test isolation - β
sdk.ToolAnnotationsmetadata propagated through gateway - β Full content type coverage (text, image, audio, embedded resource)
Improvement Opportunities
π Quick Wins
1. Extract pagination helper in connection.go
listTools, listResources, and listPrompts each implement identical cursor-loop pagination (lines ~545β644), totaling ~45 lines of duplicate boilerplate:
first, err := c.getSDKSession().ListTools(c.ctx, &sdk.ListToolsParams{})
allTools := make([]*sdk.Tool, len(first.Tools), max(len(first.Tools), 1))
copy(allTools, first.Tools)
cursor := first.NextCursor
for cursor != "" {
result, err := c.getSDKSession().ListTools(c.ctx, &sdk.ListToolsParams{Cursor: cursor})
...
cursor = result.NextCursor
}This pattern repeats identically for resources and prompts. A generic helper would eliminate the duplication and make pagination behavior (e.g., max-items guards) easy to apply uniformly.
2. resourceContents intermediate type in tool_result.go
A local resourceContents struct (lines 12β18) mirrors sdk.ResourceContents field-for-field for intermediate JSON unmarshaling. Verify whether sdk.ResourceContents can be used directly in the parse step to eliminate the duplicate type.
3. Test server nil options
mcptest/server.go calls sdk.NewServer(impl, nil). Passing &sdk.ServerOptions{} explicitly is more defensive and documents intent, guarding against future SDK changes that might panic on nil options.
β¨ Feature Opportunities
1. Prompt forwarding through the aggregated gateway server
The unified server correctly forwards listPrompts/getPrompt backend requests via ClientSession, but does not register aggregated prompts on the gateway's own sdk.Server instance. This means MCP clients connected to the gateway cannot discover or invoke prompts from backends β the same gap that was solved for tools via us.server.AddTool. Adding server.AddPrompt registration (mirroring registerAllTools) would bring prompt support to parity with tool support.
2. Configurable session timeouts
Session timeouts are hard-coded:
- Unified mode:
SessionTimeout: 2 * time.Hour(transport.go) - Routed mode:
SessionTimeout: 30 * time.Minute(routed.go)
These are reasonable defaults but not exposed in config. Adding gateway.session_timeout_minutes (or similar) to the TOML/JSON config would give operators control over memory/connection trade-offs.
3. Evaluate Stateless: true for stateless HTTP backends
StreamableHTTPOptions.Stateless is false everywhere. For backends that are themselves stateless (e.g., pure HTTP MCP servers), stateless mode could reduce session overhead on both the gateway and backend. This is worth evaluating when the backend transport type is http.
π Best Practice Alignment
1. filteredServerCache in routed.go grows unboundedly
type filteredServerCache struct {
servers map[string]*sdk.Server // never evicted
mu sync.RWMutex
}The cache accumulates one *sdk.Server per (backendID, sessionID) pair and is never pruned. In long-running deployments with many sessions, this silently grows in memory. Adding TTL-based eviction (matching the SessionTimeout) would align cache lifetime with session lifetime.
2. sdk.Transport ownership documentation
The transportConnector factory type and its return values lack documentation about lifecycle/ownership. Adding a brief comment that the caller owns (and should close) the returned sdk.Transport would improve correctness for future contributors.
π§ General Improvements
Handler signature mismatch complexity: The internal handler type
func(context.Context, *sdk.CallToolRequest, interface{}) (*sdk.CallToolResult, interface{}, error)has an extra interface{} parameter and return value for middleware data. Every registration site must wrap this to the SDK's simpler func(ctx, req) (result, error) signature. This wrapping is correct but adds ceremony. Consider whether the middleware data could be passed via context instead, which would simplify both the type and the wrapping sites.
Recommendations
- [Medium] Add prompt aggregation to the unified server (parity with tool aggregation) β highest user-visible impact
- [Small] Extract pagination helper in
connection.goβ reduces ~45 lines of duplication - [Small] Add cache eviction to
filteredServerCacheinrouted.goβ prevents memory growth - [Small] Make session timeouts configurable via gateway config
- [Investigate] Evaluate stateless mode for HTTP backends
Next Steps
- Open sub-issues for prompt aggregation and
filteredServerCacheeviction if they are prioritized - Consider adding
specs/mods/to the repository for ongoing module review summaries
Generated by Go Fan πΉ | Module: github.com/modelcontextprotocol/go-sdk v1.4.1
Analysis run: Β§23785964845
Note
π Integrity filter blocked 23 items
The following items were blocked because they don't meet the GitHub integrity level.
- https://github.com/BurntSushi/toml/releases/tag/v1.6.0
get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/wazero/wazero/releases/tag/v1.11.0
get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/stretchr/testify/releases/tag/v1.11.1
get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/santhosh-tekuri/jsonschema/releases/tag/v6.0.2
get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/spf13/cobra/releases/tag/v1.10.2
get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/releases/tag/v1.4.1
get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/itchyny/gojq/releases/tag/v0.12.18
get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - get_file_contents
get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/releases/tag/v1.4.1
list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/releases/tag/v1.4.0
list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/releases/tag/v1.3.1
list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/releases/tag/v1.3.0
list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - https://github.com/modelcontextprotocol/go-sdk/releases/tag/v1.3.0-pre.1
list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - modelcontextprotocol/go-sdk@b71a839
list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - modelcontextprotocol/go-sdk@2d43865
list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - modelcontextprotocol/go-sdk@05277f6
list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved". - ... and 7 more items
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | none
- expires on Apr 7, 2026, 7:49 AM UTC