Repository navigation
Description
Describe the bug
Stateful Streamable HTTP session expiry is not correctly reflected in the PHP SDK’s connection state.
In the affected HttpTransport::send() implementation, HTTP status codes are not checked before processing or discarding the response body.
Consequently:
- A session-bound HTTP 404 with an empty or plain-text body leaves the tool request waiting until timeout.
Client::isConnected()remainstrue, and subsequent requests continue using the expired session.- A 404 returned for
notifications/cancelledis also discarded without invalidating the connection.
This concerns protocol revisions using Mcp-Session-Id, such as 2025-11-25.
To Reproduce
Ordinary tool request
- Initialize a connection to a stateful HTTP server and receive session ID
S. - Invalidate
Son the server. - Call a tool. The server returns HTTP 404 with an empty or plain-text body.
- Observe that the request waits until timeout and the client still reports itself connected.
- Make another call: it sends the same expired session ID.
Cancellation or deadline expiry
- Start a tool call using session
Sand leave its response pending. - Invalidate the session, then cancel the call or let its deadline expire.
- The SDK sends
notifications/cancelledwithS; the server returns HTTP 404. - The original call is interrupted, but the client remains marked connected despite its expired session.
Simply adding a ConnectionException for HTTP 404 is insufficient for the second case: Protocol::notifyCancellation() catches notification failures. Connection invalidation must persist independently of whether that exception reaches the caller.
Expected behavior
- Recognize a 404 on a request carrying
Mcp-Session-Idas session expiry. - Close the response body, clear the session ID, and mark the client uninitialized so
isConnected()returnsfalse. - Surface an ordinary request’s session expiry promptly as a connection failure.
- Preserve the original cancellation/deadline exception when expiry is detected during the cancellation POST.
- Allow a subsequent reconnect to initialize without the expired session ID.
- Keep healthy connections reusable after cancellation or deadline expiry.
The 2025-11-25 specification, Session Management points 3–4, requires fresh initialization after a session-bound 404. It does not require automatically replaying the interrupted tool call.
Additional context
- Related HTTP status-handling PR: [Client] Send
MCP-Protocol-Versionon every request after the handshake #425. - Similar reports: TypeScript SDK #1708, Python SDK #1676.
Activity