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
TL;DR: The MCP go-sdk is deeply and thoughtfully integrated across 27 files. The project is running v1.4.1 while v1.5.0 is available. Two structural concerns merit attention: a fragile reliance on SDK internals for schema-validation bypass, and string-matching for session-expiry detection.
Module Overview
github.com/modelcontextprotocol/go-sdk is the official Go SDK for the Model Context Protocol (MCP). It provides client and server primitives for JSON-RPC 2.0 communication over three transports: stdio (via CommandTransport), StreamableHTTP (2025-03-26 spec), and SSE (2024-11-05 spec, deprecated). It is the foundational dependency — everything this gateway does flows through it.
The extra state and second return value thread data through the jq middleware pipeline and DIFC write-sink logger. This is well-documented in registerToolWithoutValidation. It's non-idiomatic but clearly justified.
Transport Fallback Chain
NewHTTPConnection implements a robust three-tier fallback: StreamableHTTP → SSE → plain JSON-RPC. Each tier uses dedicated reconnection logic. This is excellent resilience engineering.
Pagination Safety
A custom generic paginateAll[T] wraps SDK list methods with a 100-page hard cap to guard against runaway backends. This is a practical defensive pattern.
Improvement Opportunities
🏃 Quick Wins
Upgrade to v1.5.0 (go.mod bump from v1.4.1 → v1.5.0)
Candidate improvements: updated protocol support, new APIs, potential bug fixes
Risk: the registerToolWithoutValidation approach (see below) must be re-verified post-upgrade
Action: review the SDK's CHANGELOG / release notes for breaking changes before upgrading
Tighten the registerToolWithoutValidation comment
Current comment says: "The Server.AddTool method (used here) skips JSON Schema validation whereas the sdk.AddTool function validates the schema. This distinction relies on internal SDK behaviour and must be re-verified on every SDK upgrade."
Improvement: add a reference test or assertion that confirms the bypass still works after upgrade, rather than relying on a code comment reminder alone
✨ Feature Opportunities
Check v1.5.0 for a public schema-bypass API
registerToolWithoutValidation (internal/server/tool_registry.go:51) relies on a behavioral difference between calling server.AddTool (the method on *sdk.Server) vs sdk.AddTool (the package-level function). The method bypasses JSON Schema validation; the function does not. This is an undocumented SDK internal behavior. If v1.5.0 adds an explicit SkipValidation option to server.AddTool, this fragility can be eliminated.
Check v1.5.0 for typed session-expiry errors
isSessionNotFoundError (internal/mcp/http_transport.go:72) detects session expiry by string-matching "session not found" against the error message. If the SDK added a typed sentinel error (e.g., sdk.ErrSessionNotFound) in v1.5.0, the reconnect logic can be made robust against error message changes:
// Current (fragile):funcisSessionNotFoundError(errerror) bool {
returnstrings.Contains(strings.ToLower(err.Error()), "session not found")
}
// Preferred (if SDK provides it):iferrors.Is(err, sdk.ErrSessionNotFound) { ... }
Check v1.5.0 for built-in pagination helpers
The custom paginateAll[T] generic function (internal/mcp/connection.go:555) is clean and correct, but if the SDK now provides built-in auto-pagination for ListTools, ListResources, and ListPrompts, the custom implementation could be removed, reducing maintenance surface.
📐 Best Practice Alignment
MCPProtocolVersion in the plain-JSON fallback
MCPProtocolVersion = "2025-11-25" (internal/mcp/http_transport.go:37) is used in the manual plain-JSON-RPC initialize request. This value is hardcoded and separate from the SDK's own protocol negotiation (which handles its version automatically). Verify that this matches the SDK's negotiated version so backends receive a consistent protocol version regardless of transport tier.
StreamableHTTPOptions.Stateless is correctly set to false for both routed and unified handlers. Confirm the default has not changed to true in v1.5.0, which would break session continuity silently.
🔧 General Improvements
SSE deprecation warning placement
When an SSE connection succeeds, a multi-line ⚠️ WARNING is written via log.Printf (standard library logger) rather than logger.LogWarn (the project's structured logger). This means the SSE deprecation warning bypasses the structured logging pipeline and won't appear in mcp-gateway.log. Consider routing it through logger.LogWarn for consistent log capture.
ClientSession reuse on tool registry refresh
During parallel tool registration, each registerToolsFromBackend call creates a fresh SDK session via launcher.GetOrLaunch. If a backend refreshes its tool list and the cursor from a previous paginated response is stale, paginateAll may emit a spurious error. The current code fetches all pages in a single call, so this is low risk — but worth a note in the code.
Recommendations (Prioritized)
Priority
Item
Effort
🔴 High
Upgrade to v1.5.0 and verify registerToolWithoutValidation still bypasses schema validation
Medium
🟠 Medium
Check v1.5.0 for typed ErrSessionNotFound → replace string matching in isSessionNotFoundError
Small
🟠 Medium
Route SSE deprecation log.Printf warnings through logger.LogWarn for structured logging
Small
🟡 Low
Check v1.5.0 for public SkipValidation API → remove fragile method-vs-function distinction
Medium
🟡 Low
Check v1.5.0 for built-in pagination → potentially remove custom paginateAll
Medium
Next Steps
go get github.com/modelcontextprotocol/go-sdk@v1.5.0 — review diff, run make agent-finished
Post-upgrade: confirm registerToolWithoutValidation still bypasses JSON Schema validation (add a regression test)
File a follow-up on each "check v1.5.0" item once the upgrade is done
Generated by Go Fan 🐹 · Run §24178458284 Module summary saved to: specs/mods/go-sdk.md (note: directory needs creation)
Note
🔒 Integrity filter blocked 8 items
The following items were blocked because they don't meet the GitHub integrity level.
🐹 Go Fan Report: modelcontextprotocol/go-sdk
Module Overview
github.com/modelcontextprotocol/go-sdkis the official Go SDK for the Model Context Protocol (MCP). It provides client and server primitives for JSON-RPC 2.0 communication over three transports:stdio(viaCommandTransport), StreamableHTTP (2025-03-26 spec), and SSE (2024-11-05 spec, deprecated). It is the foundational dependency — everything this gateway does flows through it.sdk "github.com/modelcontextprotocol/go-sdk/mcp"Current Usage in gh-aw
The SDK is imported in 27 files across production and test code.
internal/mcp/connection.go,http_transport.go,tool_result.gointernal/server/unified.go,routed.go,transport.go,tool_registry.gointernal/testutil/mcptest/server.go,driver.go,validator.gotest/integration/Key APIs Used
sdk.CallToolResult/sdk.CallToolRequestsdk.TextContent/sdk.Contentsdk.Server/sdk.NewServersdk.Transportsdk.NewStreamableHTTPHandler/mcpand/mcp/{id}endpointssdk.StreamableClientTransportsdk.SSEClientTransportsdk.NewInMemoryTransportssdk.ToolAnnotationsResearch Findings
Architecture: Three-Argument Handler Pattern
The project introduces a deliberate extension of the SDK's two-argument handler contract:
The extra
stateand second return value thread data through the jq middleware pipeline and DIFC write-sink logger. This is well-documented inregisterToolWithoutValidation. It's non-idiomatic but clearly justified.Transport Fallback Chain
NewHTTPConnectionimplements a robust three-tier fallback: StreamableHTTP → SSE → plain JSON-RPC. Each tier uses dedicated reconnection logic. This is excellent resilience engineering.Pagination Safety
A custom generic
paginateAll[T]wraps SDK list methods with a 100-page hard cap to guard against runaway backends. This is a practical defensive pattern.Improvement Opportunities
🏃 Quick Wins
Upgrade to v1.5.0 (
go.modbump from v1.4.1 → v1.5.0)registerToolWithoutValidationapproach (see below) must be re-verified post-upgradeTighten the
registerToolWithoutValidationcomment✨ Feature Opportunities
Check v1.5.0 for a public schema-bypass API
registerToolWithoutValidation(internal/server/tool_registry.go:51) relies on a behavioral difference between callingserver.AddTool(the method on*sdk.Server) vssdk.AddTool(the package-level function). The method bypasses JSON Schema validation; the function does not. This is an undocumented SDK internal behavior. If v1.5.0 adds an explicitSkipValidationoption toserver.AddTool, this fragility can be eliminated.Check v1.5.0 for typed session-expiry errors
isSessionNotFoundError(internal/mcp/http_transport.go:72) detects session expiry by string-matching"session not found"against the error message. If the SDK added a typed sentinel error (e.g.,sdk.ErrSessionNotFound) in v1.5.0, the reconnect logic can be made robust against error message changes:Check v1.5.0 for built-in pagination helpers
The custom
paginateAll[T]generic function (internal/mcp/connection.go:555) is clean and correct, but if the SDK now provides built-in auto-pagination forListTools,ListResources, andListPrompts, the custom implementation could be removed, reducing maintenance surface.📐 Best Practice Alignment
MCPProtocolVersion in the plain-JSON fallback
MCPProtocolVersion = "2025-11-25"(internal/mcp/http_transport.go:37) is used in the manual plain-JSON-RPCinitializerequest. This value is hardcoded and separate from the SDK's own protocol negotiation (which handles its version automatically). Verify that this matches the SDK's negotiated version so backends receive a consistent protocol version regardless of transport tier.StreamableHTTPOptions.Statelessis correctly set tofalsefor both routed and unified handlers. Confirm the default has not changed totruein v1.5.0, which would break session continuity silently.🔧 General Improvements
SSE deprecation warning placement
When an SSE connection succeeds, a multi-line
⚠️ WARNINGis written vialog.Printf(standard library logger) rather thanlogger.LogWarn(the project's structured logger). This means the SSE deprecation warning bypasses the structured logging pipeline and won't appear inmcp-gateway.log. Consider routing it throughlogger.LogWarnfor consistent log capture.ClientSessionreuse on tool registry refreshDuring parallel tool registration, each
registerToolsFromBackendcall creates a fresh SDK session vialauncher.GetOrLaunch. If a backend refreshes its tool list and the cursor from a previous paginated response is stale,paginateAllmay emit a spurious error. The current code fetches all pages in a single call, so this is low risk — but worth a note in the code.Recommendations (Prioritized)
registerToolWithoutValidationstill bypasses schema validationErrSessionNotFound→ replace string matching inisSessionNotFoundErrorlog.Printfwarnings throughlogger.LogWarnfor structured loggingSkipValidationAPI → remove fragile method-vs-function distinctionpaginateAllNext Steps
go get github.com/modelcontextprotocol/go-sdk@v1.5.0— review diff, runmake agent-finishedregisterToolWithoutValidationstill bypasses JSON Schema validation (add a regression test)Generated by Go Fan 🐹 · Run §24178458284
Module summary saved to: specs/mods/go-sdk.md (note: directory needs creation)
Note
🔒 Integrity filter blocked 8 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".list_commits: 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".To allow these resources, lower
min-integrityin your GitHub frontmatter: