Skip to content

Commit 9436ace

Browse files
committed
fix(client): reinitialize expired streamable HTTP sessions
1 parent 053e798 commit 9436ace

1 file changed

Lines changed: 15 additions & 4 deletions

File tree

src/mcp/client/streamable_http.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from mcp_types.version import MODERN_PROTOCOL_VERSIONS
3131
from pydantic import ValidationError
3232

33-
from mcp.client._transport import TransportStreams
33+
from mcp.client._transport import SESSION_EXPIRED, SESSION_EXPIRED_MARKER, TransportStreams
3434
from mcp.shared._compat import resync_tracer
3535
from mcp.shared._context_streams import ContextReceiveStream, ContextSendStream, create_context_streams
3636
from mcp.shared._httpx_utils import create_mcp_http_client
@@ -359,13 +359,24 @@ async def _handle_post_request(self, ctx: RequestContext) -> None:
359359
pass
360360
logger.debug("Non-2xx body was not a JSON-RPC error; using fallback")
361361
if response.status_code == 404:
362-
if self.session_id is None:
362+
request_session_id = headers.get(MCP_SESSION_ID)
363+
if request_session_id is None:
363364
# No session yet → 404 is the HTTP-level spelling of
364365
# METHOD_NOT_FOUND (gateway / legacy server doesn't know
365-
# this method); "Session terminated" would be a lie here.
366+
# this method); session recovery would be a lie here.
366367
error_data = ErrorData(code=METHOD_NOT_FOUND, message="Not Found")
367368
else:
368-
error_data = ErrorData(code=INVALID_REQUEST, message="Session terminated")
369+
# A post-session 404 means the server discarded this
370+
# request's session. Clear only if this request still
371+
# owns the current generation: a delayed old 404 must
372+
# not erase a session another request just recovered.
373+
if self.session_id == request_session_id:
374+
self.session_id = None
375+
error_data = ErrorData(
376+
code=SESSION_EXPIRED,
377+
message="Session expired",
378+
data={SESSION_EXPIRED_MARKER: True},
379+
)
369380
else:
370381
error_data = ErrorData(code=INTERNAL_ERROR, message="Server returned an error response")
371382
session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data))

0 commit comments

Comments
 (0)