Skip to content

tracking: MCP 2026-07-28 spec — stateless protocol migration #252

Description

@ifsantana

What changed upstream

The MCP steering group published the 2026-07-28 specification (changelog). Headline change: MCP moves from a bidirectional, session-stateful protocol to a stateless request/response protocol.

  • Mcp-Session-Id and the initialize/notifications/initialized handshake are removed. Every request now carries its own protocol version + capabilities in _meta.
  • Server-initiated round trips (sampling, elicitation, roots) are replaced by a stateless Multi Round-Trip Requests (MRTR) pattern: server returns resultType: "input_required" + inputRequests, client retries the original call with inputResponses.
  • Legacy HTTP+SSE transport is formally reclassified as Deprecated in favor of Streamable HTTP.
  • tools/list / prompts/list / resources/list responses now require ttlMs + cacheScope caching metadata, and servers SHOULD return tools in deterministic order.
  • Roots, Sampling, and Logging features are deprecated.
  • OAuth hardening: RFC 9207 issuer validation, Client ID Metadata Documents (CIMD) replacing Dynamic Client Registration.
  • New required headers Mcp-Method / Mcp-Name on Streamable HTTP POSTs; JSON-RPC error codes renumbered into an allocated range.

Why it matters to us

Our mcp module (spring-ai-starter-mcp-server-webmvc, Spring AI 1.0.0 / MCP Java SDK 0.10.0) runs on exactly the transport being deprecated — legacy HTTP+SSE (GET /sse + POST /mcp/messages?sessionId=<uuid>), configured via transport: sse.

To compensate for that transport's statefulness, we built a documented workaround (see docs/mcp-server.md "Known limitations", and the classes below) that a stateless transport makes entirely unnecessary:

  • infrastructure/security/McpSseAuthBridgeFilter.kt — regex-scrapes raw SSE bytes to extract the session ID Spring AI assigns, because mcp-remote only sends X-API-Key on GET /sse, not on the following POST /mcp/messages.
  • infrastructure/security/McpSseSessionAuthStore.kt — an in-process ConcurrentHashMap<sessionId, Authentication>. Requires GKE session affinity in multi-replica deployments, and leaks one entry per historical session forever (remove() is defined but never called).
  • infrastructure/security/McpReactorSecurityConfig.kt — Reactor thread-local context propagation needed only because of the async SSE dispatch model.

Other current-state notes:

  • All 7 tools on IdemMcpServer.kt are synchronous request→response @Tool methods; no use of sampling, elicitation, or roots anywhere, so MRTR migration would be new capability, not a port of an existing blocking mechanism.
  • No caching metadata on list output today; tool ordering is not guaranteed deterministic (JVM reflection order).
  • Auth is plain API-key (X-API-Key/Bearer, bcrypt+Redis) — no OAuth/DCR anywhere, so the OAuth-hardening parts of the spec (RFC 9207, CIMD) are not applicable to us today.
  • McpServerIntegrationTest.kt invokes tools in-process via ToolCallbackProvider, bypassing HTTP/SSE and the auth bridge — effectively zero test coverage of the transport/session mechanics the new spec eliminates.

Blocker: upstream Java SDK support

Per the MCP blog's SDK-beta announcement, only Python, TypeScript, Go, and C# are Tier 1 SDKs with beta support for 2026-07-28 at launch (Rust got a beta outside Tier 1). The Java SDK (io.modelcontextprotocol.sdk, which Spring AI's MCP server wraps) was not called out with beta support. The latest stable Java SDK release found (v2.0.0) tracks the 2025-11-25 spec — it already deprecates SSE in favor of Streamable HTTP, but does not implement session removal, MRTR, Mcp-Method/Mcp-Name headers, resultType, or ttlMs/cacheScope.

We should not hand-roll spec compliance in application code ahead of SDK support.

Recommended approach, once revisited — two phases

Phase 1 (doable without waiting on the 2026-07-28 SDK): Migrate off legacy HTTP+SSE to Streamable HTTP using Spring AI's STATELESS server mode (spring.ai.mcp.server.protocol=STATELESS, requires bumping Spring AI 1.0.0 → a 2.0.x line). This already targets a spec revision where HTTP+SSE is deprecated, and — independent of full 2026-07-28 compliance — fixes our worst existing defect: delete all three auth-bridge classes and the GKE session-affinity requirement, since stateless mode means every POST /mcp call carries its own auth like any normal REST call. IdemMcpServer.kt's 7 @Tool methods should be largely unaffected, but need a real HTTP-level integration test added (current test bypasses the transport layer entirely).

Phase 2 (blocked on upstream): Full 2026-07-28 compliance — no init handshake, per-request _meta protocol version/capabilities, Mcp-Method/Mcp-Name headers, resultType/MRTR, ttlMs/cacheScope on tools/list, deterministic tool ordering, renumbered error codes. Needs the Java MCP SDK (and therefore Spring AI's MCP starter) to ship support first. Track modelcontextprotocol/java-sdk releases and the Spring AI MCP starter changelog.

Explicitly out of scope

  • OAuth hardening (RFC 9207, CIMD vs. DCR) — not applicable, we don't use OAuth for MCP.
  • Sampling/Elicitation/Roots deprecation — never implemented, nothing to remove.
  • MRTR-based human-in-the-loop confirmation for postTransaction/rollbackWorkflow (e.g. confirm-before-commit on large transactions) — a genuinely new capability the new pattern enables, but it's a product decision depending on Phase 2 SDK support, not required by the migration itself. Worth its own issue/discussion if wanted.

Status

No work scheduled yet. This issue exists to capture the research so it isn't lost — revisit once the Java MCP SDK ships 2026-07-28 support (or sooner, for Phase 1 alone, if prioritized).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions