Skip to content

Streamable HTTP client does not re-initialize session on HTTP 404 (MCP spec violation) #733

@ewfian

Description

@ewfian

Describe the bug

When the server returns HTTP 404 for an expired session, the rmcp streamable HTTP client:

  1. Surfaces the error to the caller (as UnexpectedServerResponse since fix(streamable-http): map stale session 401 to status-aware error #709)
  2. Does not attempt to re-initialize the session
  3. All subsequent requests continue using the stale session ID and keep failing permanently

This violates MCP Spec 2025-03-26, Session Management, rule 4:

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

  1. Connect an rmcp streamable HTTP client to a stateful MCP server with session TTL
  2. Make tool calls (works fine)
  3. Wait for the server-side session to expire
  4. Make another tool call
  5. Client fails with UnexpectedServerResponse("HTTP 404: ...") (or error decoding response body on rmcp 0.15.0)
  6. 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.

CodeX issue: openai/codex#13969

Additional context

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-init
    Ok(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.

Related issues:

None of these address the missing re-initialization behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is not working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions