Summary
HttpServletStreamableServerTransportProvider intermittently answers -32603 "Stream unavailable for session <id>" (wrapped as JSON-RPC internal error / HTTP 500) when it attempts to push a server-initiated request (e.g. roots/list) to a client whose GET /mcp SSE stream has not been registered yet.
Observed failure
- Test:
HttpServletStreamableIntegrationTests.testRootsNotificationWithEmptyRootsList(String)[1]
- CI run: https://github.com/modelcontextprotocol/java-sdk/actions/runs/33068920136 (Build and Test)
- Client-side surfacing:
java.lang.RuntimeException: Failed to send message: AggregateResponseEvent[...] wrapping
jsonRpcError: {"code":-32603,"message":"Error processing message: Stream unavailable for session 82454020-4c10-4276-9c30-57c15d49810e"}
Repro shape
- Client declares the
roots capability
- Client sends
initialize; server accepts and creates the session
- Server immediately pushes
roots/list over the session's GET /mcp stream
- POST traffic racing the first stream registration loses →
-32603, stream unavailable
Why we believe it is a race (not environment-specific)
Suggested directions
- Buffer server→client messages per session until a stream registers (short grace window), or
- Single retry on "stream unavailable" for capability-prompted pushes
A test-side await cannot fix this, since the failure occurs inside the server's push path.
Environment
Summary
HttpServletStreamableServerTransportProviderintermittently answers-32603 "Stream unavailable for session <id>"(wrapped as JSON-RPC internal error / HTTP 500) when it attempts to push a server-initiated request (e.g.roots/list) to a client whoseGET /mcpSSE stream has not been registered yet.Observed failure
HttpServletStreamableIntegrationTests.testRootsNotificationWithEmptyRootsList(String)[1]java.lang.RuntimeException: Failed to send message: AggregateResponseEvent[...]wrappingjsonRpcError: {"code":-32603,"message":"Error processing message: Stream unavailable for session 82454020-4c10-4276-9c30-57c15d49810e"}Repro shape
rootscapabilityinitialize; server accepts and creates the sessionroots/listover the session'sGET /mcpstream-32603, stream unavailableWhy we believe it is a race (not environment-specific)
fb029c8c"Clean up AbstractMcpClientServerIntegrationTests",HttpServletStreamableServerTransportProviderremoves session on non-fatal failure #952 (session removed on non-fatal failure), and Stateful streamable server calls listRoots() unconditionally on roots/list_changed, blocking a servlet thread until requestTimeout when no roots consumer is registered #1061 (same roots-push seam in the stateful streamable provider, blocking variant)Suggested directions
A test-side await cannot fix this, since the failure occurs inside the server's push path.
Environment
b31841ee(via PR feat(transport): add SEP-2243 Mcp-Method / Mcp-Name header mirroring with MCP-Protocol-Version validation #1112 CI), JDK 17, CI ubuntu-latest + local macOS