Plan the mcptools migration to the stateless MCP spec revision (SEP-2575 / SEP-2567)
What changed upstream
The next MCP spec revision makes the protocol stateless. Both SEPs are accepted (labeled final) and merged into the spec's draft changelog; the Go SDK is implementing against it as protocol version 2026-07-28. As of filing, the revision is still draft with a 2026-07-28-RC prerelease tagged, not yet a published revision directory.
- SEP-2567 removes protocol-level sessions and the
Mcp-Session-Idheader. Cross-call state moves to explicit server-minted handles passed as ordinary tool arguments, and list endpoints no longer vary per-connection. - SEP-2575 removes the
initialize/notifications/initializedhandshake. Protocol version and client capabilities travel per-request in_meta. Servers MUST implement a newserver/discoverRPC advertising supported versions, capabilities, and identity; theDiscoverResultschema also carries optionalinstructions. Clients MAY call it.
modelcontextprotocol/go-sdk support is in flight: #1111 (stateful servers rejecting SEP-2575 requests), #1025, #1095 (restricting advertised versions), and fixes are already landing (#1116 closed today).
What it touches in Jaeger (at current main)
| Spec change | Jaeger surface |
|---|---|
| initialize removed | mcptools/server.go delivers the embedded INSTRUCTIONS.md as ServerOptions.Instructions, which ships in the initialize response today. The draft moves instructions to DiscoverResult.instructions, and since clients MAY skip server/discover, delivery becomes best-effort |
| sessions removed | mcptools/server.go runs the streamable handler with Stateless: false and a 5 minute SessionTimeout (config.go) |
| list endpoints must not vary per-connection | the jaegerai turn-scoped endpoint advertises per-turn UI tools in tools/list via receiving middleware (jaegerai/endpoint_turn_mcp.go). The variation is keyed by URL route id rather than the session header, so it may remain conformant, but that needs a read of the final text |
| unaffected | tenancy extraction is transport-level (tenancy.ExtractTenantHTTPHandler in WrapHTTP) and independent of MCP sessions |
Tests are mostly indirectly affected: the suites drive the SDK client through Connect, which performs the handshake and session management internally, so the harness follows whatever the SDK ships. The exception is mcptools/middleware_test.go, which references mcp.InitializeParams and the initialize method name directly.
Open questions
- Instructions delivery. Is
DiscoverResult.instructionsenough guidance surface for LLM clients, or should the key usage notes move into tool descriptions, which every client sees? Related: #8897 reports the Gemini sidecar already missing server instructions today, so this delivery gap predates the spec change. The draft also asks servers to returntools/listin deterministic order for prompt caching, which we already do. - The turn-scoped UI-tools endpoint: keep per-URL variation, or move to the explicit state-handle pattern SEP-2567 describes?
- Timing. The SDK is mid-flight on exactly the behaviors we depend on. Migrating before it settles risks churn; waiting too long means running a stateful server against clients that have moved.
Plan
I'd like to drive this. Proposed sequence, gated on the go-sdk shipping stable 2026-07-28 support:
- Move key usage guidance from
INSTRUCTIONS.mdinto tool descriptions (valid under both revisions, useful now; PR to follow shortly) - Flip the streamable handler to stateless and drop the session timeout once the SDK settles
- Wire instructions into
server/discover - Rework the turn-scoped endpoint per the answer to question 2
- Update the integration harness to whatever
Connectbecomes
Later phases land on top of #9125's in-progress refactor of the shared MCP server construction, so I would sequence behind it rather than conflict with it.
Questions 1 and 2 above are the direction calls I'd want input on before the later phases. @yurishkuro could you assign this to me?
Source: jaegertracing/jaeger