**Disclaimer:** I am not a native English speaker. This issue was drafted with AI translation assistance. I apologize for any awkward phrasing. ## Bug description After a successful `initialize` handshake where the server negotiates down to an older protocol version (e.g. `2025-06-18`), the subsequent GET request to open the SSE stream still sends the **client's original latest version** (`2025-11-25`) in the `MCP-Protocol-Version` HTTP header rather than the negotiated version. Servers that validate this header (such as [rmcp](https://github.com/aspect-build/rules_mcp/tree/main/rmcp)) reject the request with `400 Bad Request`. ### Root cause In both `WebClientStreamableHttpTransport` and `HttpClientStreamableHttpTransport`, the `MCP-Protocol-Version` header is resolved via Reactor Context: ```java ctx.getOrDefault(McpAsyncClient.NEGOTIATED_PROTOCOL_VERSION, this.latestSupportedProtocolVersion) ``` The negotiated version is written into the Reactor Context by `LifecycleInitializer.withInitialization()`: ```java .flatMap(res -> operation.apply(res) .contextWrite(c -> c.put(McpAsyncClient.NEGOTIATED_PROTOCOL_VERSION, res.initializeResult().protocolVersion()))); ``` However, the GET reconnect is triggered as a **side effect** inside `sendMessage()` when the transport session is first marked as initialized: ```java if (transportSession.markInitialized(response.headers()...getFirst(HttpHeaders.MCP_SESSION_ID))) { reconnect(null).contextWrite(sink.contextView()).subscribe(); } ``` At this point, `sink.contextView()` does **not** yet contain `NEGOTIATED_PROTOCOL_VERSION` because the `contextWrite` in `LifecycleInitializer` has not executed yet — it runs *after* the `initialize` request's `sendMessage()` completes. So the GET reconnect falls back to `latestSupportedProtocolVersion` (`2025-11-25`). **Timeline:** 1. `LifecycleInitializer.doInitialize()` → calls `mcpClientSession.sendRequest("initialize", ...)` → `transport.sendMessage()` 2. `sendMessage()` POSTs to `/mcp` with header `MCP-Protocol-Version: 2025-11-25` ✅ (no negotiation yet, expected) 3. Server responds with `protocolVersion: "2025-06-18"` ✅ 4. Inside `sendMessage()`, `transportSession.markInitialized(sessionId)` returns `true` → **immediately** calls `reconnect(null)` which fires a GET with `MCP-Protocol-Version: 2025-11-25` ❌ 5. *Later*, `LifecycleInitializer.withInitialization()` runs `.contextWrite(c -> c.put(NEGOTIATED_PROTOCOL_VERSION, "2025-06-18"))` — **too late** for the GET in step 4 ## Environment - **Spring AI:** 2.0.0-M3 - **MCP Java SDK (`io.modelcontextprotocol.sdk:mcp-core`):** 1.1.0 - **Spring Boot:** 4.0.4 - **Java:** 25 - **Transport:** `WebClientStreamableHttpTransport` (via `spring-ai-starter-mcp-client-webflux`) - **MCP Server:** rmcp 1.2.0 (Rust, Streamable HTTP, supporting protocol version `2025-06-18`) ## Steps to reproduce 1. Set up an MCP server that supports `protocolVersion: "2025-06-18"` and validates the `MCP-Protocol-Version` HTTP header (rejecting unsupported versions). 2. Configure a Spring AI MCP client with `spring-ai-starter-mcp-client-webflux` using default settings (no custom `supportedProtocolVersions`). 3. Start the application and observe the HTTP traffic. **Observed:** ``` POST /mcp → MCP-Protocol-Version: 2025-11-25 → 200 OK (negotiated to 2025-06-18) GET /mcp → MCP-Protocol-Version: 2025-11-25 → 400 Bad Request ``` ## Expected behavior After the server responds with `protocolVersion: "2025-06-18"`, all subsequent requests (including the GET SSE reconnect) should use `MCP-Protocol-Version: 2025-06-18` in the HTTP header: ``` POST /mcp → MCP-Protocol-Version: 2025-11-25 → 200 OK (negotiated to 2025-06-18) GET /mcp → MCP-Protocol-Version: 2025-06-18 → 200 OK ``` ## Workaround Register a `McpClientCustomizer` bean to remove `2025-11-25` from the supported versions list, so the fallback value aligns with the server: ```java @Component public class McpTransportCustomizer implements McpClientCustomizer<WebClientStreamableHttpTransport.Builder> { @Override public void customize(String name, WebClientStreamableHttpTransport.Builder builder) { builder.supportedProtocolVersions(List.of( ProtocolVersions.MCP_2024_11_05, ProtocolVersions.MCP_2025_03_26, ProtocolVersions.MCP_2025_06_18 )); } } ```