Skip to content

[go-fan] Go Module Review: go-sdk (modelcontextprotocol/go-sdk)Β #3689

@github-actions

Description

@github-actions

🐹 Go Fan Report: modelcontextprotocol/go-sdk

Module Overview

github.com/modelcontextprotocol/go-sdk is the official Go SDK for 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:

  • MCP server and client implementations
  • Streamable HTTP and SSE transport handlers
  • MCP type system (Tool, Content, Resource, Prompt, etc.)
  • In-memory transports for testing
  • Typed error sentinels (e.g., ErrSessionMissing since v1.5.0)

Current Usage in gh-aw-mcpg

  • Files: 29 files (15 production, 14 test)
  • Import Count: 29 imports (all aliased as sdk)
  • Key APIs Used:
    • sdk.NewServer / sdk.NewStreamableHTTPHandler / sdk.StreamableHTTPOptions β€” HTTP server layer
    • sdk.NewClient / client.Connect / session.* β€” backend client connections
    • sdk.CommandTransport, sdk.StreamableClientTransport, sdk.SSEClientTransport β€” transport variants
    • sdk.NewInMemoryTransports β€” in-memory test transports
    • sdk.Tool, sdk.CallToolRequest/Result, sdk.Content subtypes β€” MCP type system
    • sdk.ErrSessionMissing β€” typed session error detection

Research Findings

The project uses this SDK deeply and correctly. The integration covers all major SDK surface areas: server creation, client session lifecycle, transport variants, content types, and error handling.

Notable SDK Usage Pattern

The codebase contains a well-documented workaround (registerToolWithoutValidation) that uses server.AddTool() (the method) instead of the package-level sdk.AddTool[In, Out]() generic function. This deliberately bypasses argument validation to allow backends using JSON Schema draft-07 (which differs from the SDK's expected version) to work correctly. The code includes a comment requiring re-verification on each SDK upgrade β€” verified correct for v1.5.0.

Improvement Opportunities

πŸƒ Quick Wins

  1. ValidatorClient pagination gap (internal/testutil/mcptest/validator.go)

    • ListTools() and ListResources() call the SDK without handling NextCursor
    • Backends with many tools would silently return only the first page
    • Fix: Reuse the project's existing paginateAll / listMCPItems helpers, or add cursor loop inline
    // Current (misses pages 2+):
    result, err := v.session.ListTools(v.ctx, &sdk.ListToolsParams{})
    return result.Tools, nil
    
    // Fix: loop on cursor
    var all []*sdk.Tool
    var cursor string
    for {
        result, err := v.session.ListTools(v.ctx, &sdk.ListToolsParams{Cursor: cursor})
        if err != nil { return nil, err }
        all = append(all, result.Tools...)
        if result.NextCursor == "" { break }
        cursor = result.NextCursor
    }
    return all, nil
  2. Missing logger in ValidatorClient (internal/testutil/mcptest/validator.go:22)

    • sdk.ClientOptions{} has no Logger set, while all production clients pass one
    • Low-effort: pass logger.NewSlogLoggerWithHandler(logger.New("testutil:validator")) for test visibility
  3. filteredServerCache.getOrCreate holds write lock during creator() (internal/server/routed.go:67)

    • creator() builds a new sdk.Server and registers all tools for a backend
    • With many tools, this could block other concurrent session requests under the same lock
    • Fix: Use a double-checked locking pattern (read lock β†’ check β†’ write lock only if missing)

✨ Feature Opportunities

  1. Typed tools for sys tools (internal sys___init, sys___list_servers)

    • These tools have well-known input schemas defined in Go code
    • Using sdk.AddTool[In, Out]() with typed structs would eliminate manual ParseToolArguments calls and provide compile-time safety
    • The bypass is only needed for backend-proxy tools forwarding unknown schemas
  2. Leverage InitializeResult().Capabilities for backend capability detection

    • After client.Connect(), session.InitializeResult() exposes what MCP capabilities (tools, resources, prompts) the backend actually supports
    • Currently the gateway always attempts all three list operations regardless of backend capabilities
    • Checking capabilities at connect time would skip unsupported operations per-backend, reducing startup error noise

πŸ“ Best Practice Alignment

  1. Automate the registerToolWithoutValidation assumption

    • There's a comment saying SDK behavior must be re-verified on every upgrade (tool_registry.go:52)
    • Consider a narrow unit test that asserts the method bypasses schema validation vs the function enforces it
    • This turns a manual process into a compile-time/test-time safety net
  2. Audit the ErrSessionMissing string-match fallback

    • isSessionNotFoundError() (http_transport.go:78) uses both errors.Is(err, sdk.ErrSessionMissing) and a string-match fallback
    • Now that v1.5.0 is in use, document whether the fallback is still exercised (it likely is only for the HTTPTransportPlainJSON path which bypasses the SDK entirely)

πŸ”§ General Improvements

  1. filteredServerCache true LRU at max capacity (internal/server/routed.go:91)
    • When the cache hits 1000 entries, it logs a warning but retains all entries
    • In a high-traffic deployment (1000+ simultaneous sessions), the cache can never evict at capacity
    • Evicting the least-recently-used entry would bound memory reliably without breaking active sessions

Recommendations

Priority order:

  1. πŸ”΄ Fix ValidatorClient pagination β€” silent data loss risk in tests with tool-rich backends (quick fix)
  2. 🟑 Automate registerToolWithoutValidation verification β€” prevents silent breakage on SDK upgrades
  3. 🟑 filteredServerCache LRU improvement β€” prevents memory growth at scale
  4. 🟒 Typed sys tools β€” improves code clarity and catches argument errors at compile time
  5. 🟒 Capability-gated operations β€” cleaner startup, less error noise

Next Steps

  • Fix ValidatorClient.ListTools/ListResources to paginate fully
  • Add a test asserting registerToolWithoutValidation bypass behavior holds for the current SDK version
  • Investigate filteredServerCache LRU eviction strategy
  • Evaluate sdk.AddTool[In, Out] for sys tools (sys___init, sys___list_servers)

Generated by Go Fan 🐹
Module summary saved to: session files/go-sdk.md
Run ID: Β§24331592683

Note

πŸ”’ Integrity filter blocked 77 items

The following items were blocked because they don't meet the GitHub integrity level.

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

Generated by Go Fan Β· ● 3.3M Β· β—·

  • expires on Apr 20, 2026, 7:49 AM UTC

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions