You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a client receives HTTP 404 in response to a request containing an Mcp-Session-Id, it MUST start a new session by sending a new InitializeRequest without a session ID attached.
To Reproduce
Connect an rmcp streamable HTTP client to a stateful MCP server with session TTL
Make tool calls (works fine)
Wait for the server-side session to expire
Make another tool call
Client fails with UnexpectedServerResponse("HTTP 404: ...") (or error decoding response body on rmcp 0.15.0)
All subsequent requests keep failing with the same stale session ID. No recovery.
Expected behavior
On HTTP 404, the client should automatically start a new session by sending a new InitializeRequest without a session ID, then retry the failed request.
Logs
Server-side logs from a real MCP server (CodeX as client, rmcp 0.15.0):
12:45:09 INFO Session expired {"sessionId":"e52ece66-..."}
12:46:37 WARN Session not found {"sessionId":"e52ece66-...","bodyMethod":"tools/call"}
12:46:37 WARN Session not found {"sessionId":"e52ece66-...","bodyMethod":"tools/call"}
12:46:37 WARN Session not found {"sessionId":"e52ece66-...","bodyMethod":"tools/call"}
12:46:49 WARN Session not found {"sessionId":"e52ece66-...","bodyMethod":"tools/call"}
12:47:01 WARN Session not found {"sessionId":"e52ece66-...","bodyMethod":"resources/list"}
12:47:28 WARN Session not found {"sessionId":"e52ece66-...","bodyMethod":"tools/call"}
No initialize request was ever sent after the 404 responses. The client is stuck permanently until restarted.
Code evidence: In StreamableHttpClientWorker::run() (crates/rmcp/src/transport/streamable_http_client.rs), the main event loop:
let send_result = match response {Err(e) => Err(e),// ← error forwarded as-is, no re-initOk(StreamableHttpPostResponse::Accepted) => { ...}Ok(StreamableHttpPostResponse::Json(message, ..)) => { ...}Ok(StreamableHttpPostResponse::Sse(stream, ..)) => { ...}};let _ = responder.send(send_result);
There is no code path that detects session expiry and triggers re-initialization. The session_id variable is immutable after the initial handshake.
The existing test test_streamable_http_stale_session.rs (added in #709) only asserts that stale sessions produce an UnexpectedServerResponse error. It does not test or expect re-initialization.
Describe the bug
When the server returns HTTP 404 for an expired session, the rmcp streamable HTTP client:
UnexpectedServerResponsesince fix(streamable-http): map stale session 401 to status-aware error #709)This violates MCP Spec 2025-03-26, Session Management, rule 4:
To Reproduce
UnexpectedServerResponse("HTTP 404: ...")(orerror decoding response bodyon rmcp 0.15.0)Expected behavior
On HTTP 404, the client should automatically start a new session by sending a new
InitializeRequestwithout a session ID, then retry the failed request.Logs
Server-side logs from a real MCP server (CodeX as client, rmcp 0.15.0):
No
initializerequest was ever sent after the 404 responses. The client is stuck permanently until restarted.CodeX issue: openai/codex#13969
Additional context
Code evidence: In
StreamableHttpClientWorker::run()(crates/rmcp/src/transport/streamable_http_client.rs), the main event loop:There is no code path that detects session expiry and triggers re-initialization. The
session_idvariable is immutable after the initial handshake.The existing test
test_streamable_http_stale_session.rs(added in #709) only asserts that stale sessions produce anUnexpectedServerResponseerror. It does not test or expect re-initialization.Related issues:
UnexpectedContentType(fixed, error message improved)UnexpectedServerResponse(fixed, error message improved)McpError(open)None of these address the missing re-initialization behavior.