|
30 | 30 | from mcp_types.version import MODERN_PROTOCOL_VERSIONS |
31 | 31 | from pydantic import ValidationError |
32 | 32 |
|
33 | | -from mcp.client._transport import TransportStreams |
| 33 | +from mcp.client._transport import SESSION_EXPIRED, SESSION_EXPIRED_MARKER, TransportStreams |
34 | 34 | from mcp.shared._compat import resync_tracer |
35 | 35 | from mcp.shared._context_streams import ContextReceiveStream, ContextSendStream, create_context_streams |
36 | 36 | from mcp.shared._httpx_utils import create_mcp_http_client |
@@ -359,13 +359,24 @@ async def _handle_post_request(self, ctx: RequestContext) -> None: |
359 | 359 | pass |
360 | 360 | logger.debug("Non-2xx body was not a JSON-RPC error; using fallback") |
361 | 361 | 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: |
363 | 364 | # No session yet → 404 is the HTTP-level spelling of |
364 | 365 | # 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. |
366 | 367 | error_data = ErrorData(code=METHOD_NOT_FOUND, message="Not Found") |
367 | 368 | 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 | + ) |
369 | 380 | else: |
370 | 381 | error_data = ErrorData(code=INTERNAL_ERROR, message="Server returned an error response") |
371 | 382 | session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data)) |
|
0 commit comments