-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
The MCP spec (2025-03-26), Session Management point 4 says:
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 newInitializeRequestwithout a session ID attached.
Neither send() (POST) nor _startOrAuthSse() (GET) handle 404. Both paths just throw StreamableHTTPError. There's no session ID clearing and no re-initialization.
send() has retry logic for 401 (auth) and 403 (insufficient_scope), but 404 falls through to:
throw new StreamableHTTPError(response.status, `Error POSTing to endpoint: ${text}`);Since _sessionId isn't cleared before the throw, subsequent send() calls keep sending the stale session ID and keep getting 404. It's not a transient failure - the client is stuck until it's destroyed and recreated.
This means servers that correctly return 404 for expired/unknown session IDs (as #389 asks them to) permanently break SDK-based clients instead of triggering a graceful reconnect.
Expected behavior: On 404, clear _sessionId and either re-initialize the session automatically or surface an event that lets the Client layer handle re-initialization (since InitializeRequest involves capability negotiation that the transport doesn't own).
Ref: #389 tracks the server-side of this (examples returning 400 instead of 404). This is the client-side counterpart. Affects v1.26.0 and v1.27.1.