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
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 sdk alias
Key APIs Used:
sdk.NewServer / server.AddTool β Gateway-side MCP server construction and tool registration
sdk.NewStreamableHTTPHandler β Streamable HTTP transport hosting (both unified and routed modes)
sdk.CommandTransport, sdk.StreamableClientTransport, sdk.SSEClientTransport β Backend transport selection
sdk.NewInMemoryTransports β In-memory transport pairs for unit testing
sdk.CallToolResult, sdk.TextContent, sdk.ImageContent, sdk.AudioContent, sdk.EmbeddedResource β Full MCP content type coverage
sdk.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.Stateless mode for stateless session handling
NewInMemoryTransports enables proper unit testing without external processes
slog-based logger integration via ServerOptions.Logger, ClientOptions.Logger, and StreamableHTTPOptions.Logger
Best Practices (observed in project)
β Using typed protocol methods (ListTools, CallTool, ListResources, etc.) over raw JSON-RPC
β slog logger integration wired through project's debug logger system
β NewInMemoryTransports used for test isolation
β sdk.ToolAnnotations metadata 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:
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.
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
typefilteredServerCachestruct {
serversmap[string]*sdk.Server// never evictedmu 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
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 filteredServerCache in routed.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 filteredServerCache eviction 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.
modelcontextprotocol/go-sdk@b71a839list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".
modelcontextprotocol/go-sdk@2d43865list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".
modelcontextprotocol/go-sdk@05277f6list_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:
πΉ 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:
sdkaliassdk.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 adapterNotable Usage Pattern:
server.AddToolvssdk.AddToolThe project consistently uses the method form
server.AddTool(tool, handler)instead of the package-levelsdk.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'ssdk.AddToolfunction 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
StreamableHTTPOptions.Statelessmode for stateless session handlingNewInMemoryTransportsenables proper unit testing without external processesslog-based logger integration viaServerOptions.Logger,ClientOptions.Logger, andStreamableHTTPOptions.LoggerBest Practices (observed in project)
ListTools,CallTool,ListResources, etc.) over raw JSON-RPCsloglogger integration wired through project's debug logger systemNewInMemoryTransportsused for test isolationsdk.ToolAnnotationsmetadata propagated through gatewayImprovement Opportunities
π Quick Wins
1. Extract pagination helper in
connection.golistTools,listResources, andlistPromptseach implement identical cursor-loop pagination (lines ~545β644), totaling ~45 lines of duplicate boilerplate: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.
resourceContentsintermediate type intool_result.goA local
resourceContentsstruct (lines 12β18) mirrorssdk.ResourceContentsfield-for-field for intermediate JSON unmarshaling. Verify whethersdk.ResourceContentscan be used directly in the parse step to eliminate the duplicate type.3. Test server nil options
mcptest/server.gocallssdk.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/getPromptbackend requests viaClientSession, but does not register aggregated prompts on the gateway's ownsdk.Serverinstance. This means MCP clients connected to the gateway cannot discover or invoke prompts from backends β the same gap that was solved for tools viaus.server.AddTool. Addingserver.AddPromptregistration (mirroringregisterAllTools) would bring prompt support to parity with tool support.2. Configurable session timeouts
Session timeouts are hard-coded:
SessionTimeout: 2 * time.Hour(transport.go)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: truefor stateless HTTP backendsStreamableHTTPOptions.Statelessisfalseeverywhere. 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 ishttp.π Best Practice Alignment
1.
filteredServerCacheinrouted.gogrows unboundedlyThe cache accumulates one
*sdk.Serverper(backendID, sessionID)pair and is never pruned. In long-running deployments with many sessions, this silently grows in memory. Adding TTL-based eviction (matching theSessionTimeout) would align cache lifetime with session lifetime.2.
sdk.Transportownership documentationThe
transportConnectorfactory type and its return values lack documentation about lifecycle/ownership. Adding a brief comment that the caller owns (and should close) the returnedsdk.Transportwould improve correctness for future contributors.π§ General Improvements
Handler signature mismatch complexity: The internal handler type
has an extra
interface{}parameter and return value for middleware data. Every registration site must wrap this to the SDK's simplerfunc(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
connection.goβ reduces ~45 lines of duplicationfilteredServerCacheinrouted.goβ prevents memory growthNext Steps
filteredServerCacheeviction if they are prioritizedspecs/mods/to the repository for ongoing module review summariesGenerated by Go Fan πΉ | Module:
github.com/modelcontextprotocol/go-sdkv1.4.1Analysis run: Β§23785964845
Note
π Integrity filter blocked 23 items
The following items were blocked because they don't meet the GitHub integrity level.
get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".To allow these resources, lower
min-integrityin your GitHub frontmatter: