Title: Claude Code client sends tools/call without initialize handshake — SSE transport rejects with -32602 · Issue #2579 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: Claude Code client sends tools/call without initialize handshake — SSE transport rejects with -32602 · Issue #2579 · modelcontextprotocol/python-sdk
X Title: Claude Code client sends tools/call without initialize handshake — SSE transport rejects with -32602 · Issue #2579 · modelcontextprotocol/python-sdk
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. ...
Open Graph 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 ...
X 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 ...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/issues/2579
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Claude Code client sends tools/call without initialize handshake — SSE transport rejects with -32602","articleBody":"## Summary\n\nClaude 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`.\n\nLikely related to #1844, but we have a concrete reproduction with full server-side debug logs.\n\n## Environment\n\n- `mcp` 1.27.0 (also reproduces with 1.14.0, 1.27.1)\n- Python 3.13 on Debian 14\n- Transport: SSE via `SseServerTransport` + Starlette/Uvicorn\n- Client: `claude-code` CLI (current version, agent-SDK based)\n- Reproduces with **multiple parallel SSE sessions** from the same host (typical of a multi-agent setup)\n\n## Server-side debug log (raw)\n\n```\n[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}\n[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)\n[DEBUG] mcp.server.sse - Sending session message to writer: SessionMessage(...)\nINFO: POST /messages/?session_id=f3ee2d980809439b97eb35556d220eb1 HTTP/1.1\" 202 Accepted\n[WARNING] root - Failed to validate request: Received request before initialization was complete\n[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\n```\n\nNote: 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.\n\n## Reproduction\n\n1. Have a Python SSE MCP server using the standard `mcp.server.sse.SseServerTransport` + `Server(...).run()` pattern (see [example in the repo](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/servers/simple-resource/mcp_simple_resource/server.py)).\n2. Connect with the Claude Code CLI as an MCP client (configure as a SSE-type MCP server in the user's `~/.claude/config`).\n3. The server has been running and idle for \u003e1 hour.\n4. From within a Claude Code session, invoke a tool. About half the time, the request comes in **without prior `initialize`**.\n\nThe 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.\n\n## What I'd like to know\n\n1. Is this expected client behavior — should the server tolerate `tools/call` without preceding `initialize`?\n2. 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)?\n3. Is there a workaround other than monkey-patching `_received_request`?\n\n## Workaround we are using (not great, but it works)\n\nWe replaced the `RuntimeError` with an implicit state transition + warning, as a runtime monkey-patch:\n\n```python\nasync def _patched_received_request(self, responder):\n match responder.request.root:\n case types.InitializeRequest() | types.PingRequest():\n return await _original(self, responder)\n case _:\n if self._initialization_state != InitializationState.Initialized:\n logger.warning(\"Implicit initialization (client skipped initialize handshake)\")\n self._initialization_state = InitializationState.Initialized\n return await _original(self, responder)\n\nServerSession._received_request = _patched_received_request\n```\n\nFull module: [linked in our deployment if helpful].\n\n## Possibly related\n\n- #1844 — same symptom, also Claude-Code-client-related\n- #737 — FastMCP RuntimeError on pre-init in FastAPI embeds\n- #2411 — proposed fix to return `INVALID_REQUEST` instead of crashing\n- #1845 — `stateless_sse` option PR (closed without merge?)\n\nThanks for the SDK!\n","author":{"url":"https://github.com/Aksels73","@type":"Person","name":"Aksels73"},"datePublished":"2026-05-12T10:14:20.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":1},"url":"https://github.com/2579/python-sdk/issues/2579"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:828dbc2e-ff37-1f0c-45a9-8d2f73c2ab03 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | E95E:3E383E:32BEEA:42374E:6A5FEEA4 |
| html-safe-nonce | 1ae068c8d972de2ad0d57805873e3258b567b2c32d40b840de9ccdb91f368bba |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFOTVFOjNFMzgzRTozMkJFRUE6NDIzNzRFOjZBNUZFRUE0IiwidmlzaXRvcl9pZCI6IjExNDIwODk1NjQ1MTEyNjg1MTYiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | c2f8482f07586f9e6ac2d8f3e1029a1af475252af002cae721bec90745cc2c8d |
| hovercard-subject-tag | issue:4428207921 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/modelcontextprotocol/python-sdk/2579/issue_layout |
| twitter:image | https://opengraph.githubassets.com/42c875ccab65590d58846d2013294279a55a94d9b42823fb4d438813799fcd51/modelcontextprotocol/python-sdk/issues/2579 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/42c875ccab65590d58846d2013294279a55a94d9b42823fb4d438813799fcd51/modelcontextprotocol/python-sdk/issues/2579 |
| og:image:alt | 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 ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | Aksels73 |
| hostname | github.com |
| expected-hostname | github.com |
| None | ba296ecd3a3521238fe43b3b3b08cc09207ddc21173e16ee656db03803de8e2b |
| turbo-cache-control | no-preview |
| go-import | github.com/modelcontextprotocol/python-sdk git https://github.com/modelcontextprotocol/python-sdk.git |
| octolytics-dimension-user_id | 182288589 |
| octolytics-dimension-user_login | modelcontextprotocol |
| octolytics-dimension-repository_id | 862584018 |
| octolytics-dimension-repository_nwo | modelcontextprotocol/python-sdk |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 862584018 |
| octolytics-dimension-repository_network_root_nwo | modelcontextprotocol/python-sdk |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 6e50fb37e29e4aa0df6386cb485e58b0e3ca97ab |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width