Repository navigation
Claude Code client sends tools/call without initialize handshake — SSE transport rejects with -32602 #2579
Description
Summary
Claude Code MCP clients (the official claude-code CLI / SDK) intermittently send tools/call requests directly after opening an SSE session, without first sending the initialize request and notifications/initialized notification. The server then rejects the request with RuntimeError("Received request before initialization was complete") (mcp/server/session.py:193), which surfaces to the client as -32602: Invalid request parameters.
Likely related to #1844, but we have a concrete reproduction with full server-side debug logs.
Environment
mcp1.27.0 (also reproduces with 1.14.0, 1.27.1)- Python 3.13 on Debian 14
- Transport: SSE via
SseServerTransport+ Starlette/Uvicorn - Client:
claude-codeCLI (current version, agent-SDK based) - Reproduces with multiple parallel SSE sessions from the same host (typical of a multi-agent setup)
Server-side debug log (raw)
[INFO] openproject-mcp-sse - POST /messages session=f3ee2d98… method=tools/call id=14 body={"method": "tools/call", "params": {"name": "test_connection", "arguments": {}, "_meta": {"claudecode/toolUseId": "toolu_01SqXkUVGvojypc6RaA4UriG", "progressToken": 14}}, "jsonrpc": "2.0", "id": 14}
[DEBUG] mcp.server.sse - Validated client message: root=JSONRPCRequest(method='tools/call', params={'name': 'test_connection', 'arguments': {}, '_meta': {'claudecode/toolUseId': 'toolu_01SqXkUVGvojypc6RaA4UriG', 'progressToken': 14}}, jsonrpc='2.0', id=14)
[DEBUG] mcp.server.sse - Sending session message to writer: SessionMessage(...)
INFO: POST /messages/?session_id=f3ee2d980809439b97eb35556d220eb1 HTTP/1.1" 202 Accepted
[WARNING] root - Failed to validate request: Received request before initialization was complete
[DEBUG] root - Message that failed validation: method='tools/call' params={'name': 'test_connection', 'arguments': {}, '_meta': {'claudecode/toolUseId': 'toolu_01SqXkUVGvojypc6RaA4UriG', 'progressToken': 14}} jsonrpc='2.0' id=14
Note: The session was just newly created by the same SSE handshake (session_id=f3ee2d98... was generated 11 seconds before). The client did not send initialize between SSE-connect and tools/call — this is observable in the raw POST body capture above.
Reproduction
- Have a Python SSE MCP server using the standard
mcp.server.sse.SseServerTransport+Server(...).run()pattern (see example in the repo). - Connect with the Claude Code CLI as an MCP client (configure as a SSE-type MCP server in the user's
~/.claude/config). - The server has been running and idle for >1 hour.
- From within a Claude Code session, invoke a tool. About half the time, the request comes in without prior
initialize.
The first session right after a service restart always works correctly. The problem manifests after the client has gone idle for some time and then resumes — strongly suggests the client is caching session state across what the server considers a session re-establishment.
What I'd like to know
- Is this expected client behavior — should the server tolerate
tools/callwithout precedinginitialize? - Or should the SDK make the server idempotently re-initialize on first non-init request (a kind of stateless mode for SSE, like
StreamableHTTPSessionManager(stateless=True)does for streamable_http)? - Is there a workaround other than monkey-patching
_received_request?
Workaround we are using (not great, but it works)
We replaced the RuntimeError with an implicit state transition + warning, as a runtime monkey-patch:
async def _patched_received_request(self, responder):
match responder.request.root:
case types.InitializeRequest() | types.PingRequest():
return await _original(self, responder)
case _:
if self._initialization_state != InitializationState.Initialized:
logger.warning("Implicit initialization (client skipped initialize handshake)")
self._initialization_state = InitializationState.Initialized
return await _original(self, responder)
ServerSession._received_request = _patched_received_requestFull module: [linked in our deployment if helpful].
Possibly related
- SSE transport: "Received request before initialization was complete" error with Claude Code client #1844 — same symptom, also Claude-Code-client-related
- Bug Report: FastMCP
RuntimeError: Received request before initialization was completeLeading to Empty SSE Responses When Embedded in FastAPI #737 — FastMCP RuntimeError on pre-init in FastAPI embeds - fix(session): return INVALID_REQUEST error instead of crashing on pre-init requests #2411 — proposed fix to return
INVALID_REQUESTinstead of crashing - feat: add stateless_sse option for SSE transport #1845 —
stateless_sseoption PR (closed without merge?)
Thanks for the SDK!
Activity
maxisbey commentedon May 18, 2026
Closing as a duplicate of #423 — same root cause (client sends
tools/callbefore completing theinitializehandshake). Your Claude Code debug logs are the clearest capture of this so far — please add them to the discussion in #423. If this turns out to be a distinct issue, feel free to reopen or open a new one.AI Disclaimer