-
Notifications
You must be signed in to change notification settings - Fork 15
Description
πΉ Go Fan Report: modelcontextprotocol/go-sdk
Module Overview
The official Go SDK for the Model Context Protocol (github.com/modelcontextprotocol/go-sdk v1.4.0). This is the most critical direct dependency in the project β it provides the protocol backbone for the entire gateway: typed MCP server/client implementations, all transport types (stdio, streamable HTTP, SSE, in-memory), and session management.
Current Usage in gh-aw
The SDK is imported in 22 files across server, client, middleware, and test utilities, making it the most pervasive dependency in the codebase.
- Files: 22 files
- Import alias:
sdk "github.com/modelcontextprotocol/go-sdk/mcp" - Key APIs Used:
- Server side:
sdk.NewServer,server.AddTool,sdk.NewStreamableHTTPHandler,sdk.StreamableHTTPOptions - Client side:
sdk.NewClient,client.Connect,session.ListTools/CallTool/ListResources/ReadResource/ListPrompts/GetPrompt - Transports:
sdk.CommandTransport(stdio),sdk.StreamableClientTransport,sdk.SSEClientTransport,sdk.NewInMemoryTransports(tests) - Types:
sdk.Tool,sdk.Resource,sdk.CallToolResult,sdk.TextContent,sdk.Content,sdk.Implementation
- Server side:
Research Findings
Architecture
The gateway acts as a proxy: it uses the SDK as a client to connect to backend MCP servers (via CommandTransport for Docker stdio containers, or HTTP transports), and as a server to expose aggregated tools to agents. The transport fallback chain for HTTP backends is: Streamable HTTP (2025-03-26 spec) β SSE (deprecated) β plain JSON-RPC.
Notable Design Decisions
server.AddTooloversdk.AddTool: The method form is used intentionally to bypass SDK schema validation, enabling support for backend tools that use JSON Schema draft-07 (incompatible with the SDK's schema validator). Well-documented in comments.- slog integration: SDK logging is correctly wired through the project's
logger.NewSlogLoggerWithHandleradapter in bothServerOptions.LoggerandClientOptions.Logger. - Protocol version: Uses
2025-11-25(latest draft) in initialize handshakes. - Session timeout: 30 minutes for
StreamableHTTPOptions.SessionTimeoutβ reasonable for preventing resource leaks.
Recent Updates (v1.4.0)
Protocol version 2025-11-25, full streamable HTTP support, in-memory transport pairs for testing, session ID tracking via session.ID().
Improvement Opportunities
π Quick Wins
1. Missing pagination in tool/resource/prompt discovery
All three list operations use empty params with no cursor:
// internal/mcp/connection.go
result, err := c.session.ListTools(c.ctx, &sdk.ListToolsParams{})
result, err := c.session.ListResources(c.ctx, &sdk.ListResourcesParams{})
result, err := c.session.ListPrompts(c.ctx, &sdk.ListPromptsParams{})The MCP spec supports cursor-based pagination. Backends with more tools than a single page will have tools silently dropped at gateway startup. A pagination loop (checking result.NextCursor until empty) should be added for robustness:
var allTools []*sdk.Tool
var cursor string
for {
params := &sdk.ListToolsParams{}
if cursor != "" {
params.Cursor = cursor
}
result, err := c.session.ListTools(c.ctx, params)
if err != nil { return nil, err }
allTools = append(allTools, result.Tools...)
if result.NextCursor == "" { break }
cursor = result.NextCursor
}2. ValidatorClient missing logger in test options
internal/testutil/mcptest/validator.go:22 creates &sdk.ClientOptions{} with no logger. Test failures become harder to diagnose. A test-appropriate logger should be passed:
}, &sdk.ClientOptions{
Logger: logger.NewSlogLoggerWithHandler(log), // add debug visibility
})β¨ Feature Opportunities
3. MCP Notification forwarding (notifications/tools/list_changed)
The gateway currently only proxies tool calls β it does not forward MCP notifications from backends to clients. When a backend reloads its tool list at runtime, connected clients see a stale tool list until they reconnect. The SDK's client session exposes SetNotificationHandler; wiring this up would enable the gateway to:
- Receive
notifications/tools/list_changedfrom a backend - Re-fetch that backend's tools
- Push
notifications/tools/list_changedto all connected gateway clients
This would give clients live tool list updates without reconnection.
4. Connection health / keepalive probing
The gateway has no heartbeat mechanism for backend connections. A stale connection (e.g., Docker container restarted) is only detected when a tool call fails. Implementing a lightweight periodic ping (if the SDK exposes a ping/pong mechanism) or checking session liveness would allow proactive reconnection.
π Best Practice Alignment
5. Simplify custom 3-parameter handler type
The gateway uses a custom 3-parameter handler signature throughout:
func(context.Context, *sdk.CallToolRequest, interface{}) (*sdk.CallToolResult, interface{}, error)The third parameter (interface{}) is always nil when called, and the second return value (interface{}) is used only for middleware data extraction (the actual payload). The SDK-native signature is:
func(context.Context, *sdk.CallToolRequest) (*sdk.CallToolResult, error)Consider whether the middleware pattern could be redesigned to use context values instead of a custom handler type, which would eliminate the wrapper boilerplate and align with the SDK's API contract.
π§ General Improvements
6. filteredServerCache memory leak in routed mode
internal/server/routed.go's filteredServerCache stores one *sdk.Server per (backendID, sessionID) pair and never evicts entries:
type filteredServerCache struct {
servers map[string]*sdk.Server
mu sync.RWMutex
}In deployments where the Authorization header varies per request (e.g., user tokens), this grows unboundedly. Each sdk.Server holds registered tools with closures β a non-trivial allocation. A max-size LRU eviction or TTL-based cleanup should be added.
Recommendations (Priority Order)
- [High] Implement pagination for
ListTools,ListResources,ListPromptsβ silent data loss risk - [Medium] Fix
filteredServerCacheeviction β memory leak in multi-user deployments - [Medium] Add notification forwarding for
tools/list_changedβ improves live refresh UX - [Low] Add logger to
ValidatorClientβ better test debuggability - [Low] Explore simplifying custom handler type β reduces SDK abstraction overhead
Next Steps
- Add pagination loop in
connection.golistTools,listResources,listPrompts - Audit
filteredServerCachefor eviction strategy - Investigate
session.SetNotificationHandleravailability in v1.4.0 for notification forwarding
Generated by Go Fan β Β§23233789121
Module summary saved to: session-state/files/go-sdk-module-review.md
(Note: specs/mods/ directory write was blocked by sandbox; summary stored in session files)
- expires on Mar 25, 2026, 7:39 AM UTC