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).
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-Idand theinitialize/notifications/initializedhandshake are removed. Every request now carries its own protocol version + capabilities in_meta.resultType: "input_required"+inputRequests, client retries the original call withinputResponses.tools/list/prompts/list/resources/listresponses now requirettlMs+cacheScopecaching metadata, and servers SHOULD return tools in deterministic order.Mcp-Method/Mcp-Nameon Streamable HTTP POSTs; JSON-RPC error codes renumbered into an allocated range.Why it matters to us
Our
mcpmodule (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 viatransport: 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, becausemcp-remoteonly sendsX-API-KeyonGET /sse, not on the followingPOST /mcp/messages.infrastructure/security/McpSseSessionAuthStore.kt— an in-processConcurrentHashMap<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:
IdemMcpServer.ktare synchronous request→response@Toolmethods; no use of sampling, elicitation, or roots anywhere, so MRTR migration would be new capability, not a port of an existing blocking mechanism.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.ktinvokes tools in-process viaToolCallbackProvider, 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-Nameheaders,resultType, orttlMs/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
STATELESSserver 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 everyPOST /mcpcall carries its own auth like any normal REST call.IdemMcpServer.kt's 7@Toolmethods 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
_metaprotocol version/capabilities,Mcp-Method/Mcp-Nameheaders,resultType/MRTR,ttlMs/cacheScopeontools/list, deterministic tool ordering, renumbered error codes. Needs the Java MCP SDK (and therefore Spring AI's MCP starter) to ship support first. Trackmodelcontextprotocol/java-sdkreleases and the Spring AI MCP starter changelog.Explicitly out of scope
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).