You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
StreamableHTTPSessionManager returns 400 instead of 404 for unknown session ID #1727
StreamableHTTPSessionManager._handle_stateful_request() returns HTTP 400 Bad Request when a session ID is provided but not found in the server instances. According to the MCP spec, this should be HTTP 404 Not Found.
Servers that require a session ID SHOULD respond to requests without an Mcp-Session-Id header (other than initialization) with HTTP 400 Bad Request.
The server MAY terminate the session at any time, after which it MUST respond to requests containing that session ID with HTTP 404 Not Found.
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.
Current Behavior
In src/mcp/server/streamable_http_manager.py, the _handle_stateful_request method:
ifrequest_mcp_session_idisnotNoneandrequest_mcp_session_idinself._server_instances:
# Handle existing session
...
elifrequest_mcp_session_idisNone:
# Create new session
...
else:
# Session ID provided but not foundresponse=Response(
"Bad Request: No valid session ID provided",
status_code=HTTPStatus.BAD_REQUEST, # ← Should be NOT_FOUND (404)
)
Expected Behavior
The else branch should return 404 Not Found:
else:
response=Response(
"Not Found: Session not found",
status_code=HTTPStatus.NOT_FOUND,
)
Why This Matters
The distinction matters for client behavior:
400 indicates a malformed request - clients may retry or report an error
404 indicates the session doesn't exist - clients know to re-initialize
The transport layer (streamable_http.py) correctly implements this in _validate_session(), but the manager layer has its own session lookup that doesn't follow the same pattern.
Note
The TypeScript SDK's StreamableHTTPServerTransport correctly returns 404 for session mismatch in its validateSession method.
Confirming this issue on MCP SDK 1.24.0 and Python 3.12
Attempting to connect from Claude.ai client (protocol version 2025-06-18, which has the same specification as pointed out by @johnw188 )
Observed behavior: Server returns HTTP 400 "Bad Request: No valid session ID provided" when Claude sends an unknown/expired session ID in mcp-session-id header. Claude.ai therefore doesn't re-initialize.
Activity
max-rousseau commentedon Dec 19, 2025
Confirming this issue on MCP SDK 1.24.0 and Python 3.12
Attempting to connect from Claude.ai client (protocol version 2025-06-18, which has the same specification as pointed out by @johnw188 )
Observed behavior: Server returns HTTP 400 "Bad Request: No valid session ID provided" when Claude sends an unknown/expired session ID in
mcp-session-idheader. Claude.ai therefore doesn't re-initialize.refactor: use typed models and add test for session 404 response
test: add pragma no cover to mock_receive function