[BUG] Claude Code Native SSE MCP Transport

Resolved 💬 3 comments Opened May 13, 2026 by andygoodger-svg Closed May 17, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Summary

When an MCP server is configured in ~/.claude.json using the native SSE transport ("type": "sse"), tool schemas load correctly (tools/list works), but every tools/call returns -32602 Invalid request parameters. Root cause: Claude Code's native SSE transport never sends the notifications/initialized message that the MCP spec requires after InitializeResult, so the server stays in Initializing state and rejects subsequent requests.

The bug affects every MCP server using the official Python MCP SDK on its server side, which is most of them.

Environment

  • Claude Code version: 2.1.140
  • macOS: 26.4.1 (Tahoe), Apple Silicon
  • Tested against MCP server: mem0ai/mem0 OpenMemory (mem0/openmemory-mcp, mem0ai==0.1.108, Python MCP SDK)
  • Server repo: https://github.com/mem0ai/mem0

Quick repro (~3 minutes)

Step 1. Add a native-SSE MCP server entry to ~/.claude.json. Substitute any reachable MCP server speaking SSE:

{
  "mcpServers": {
    "repro-server": {
      "type": "sse",
      "url": "http://YOUR_MCP_HOST:8765/mcp/sse/path"
    }
  }
}

Step 2. Restart Claude Code, then run /mcprepro-server shows as connected with its tool count populated. So far so good (schemas loaded).

Step 3. Ask Claude to call any tool exposed by the server. Observe:

MCP error -32602: Invalid request parameters

Step 4. Replace the same entry with the mcp-remote stdio bridge form:

{
  "mcpServers": {
    "repro-server": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://YOUR_MCP_HOST:8765/mcp/sse/path",
        "--allow-http"
      ]
    }
  }
}

Restart Claude Code, repeat Step 3 — tool call succeeds. Confirms the bug is in Claude Code's native SSE path, not in the server or the network.

Root cause (confirmed server-side)

In the MCP Python SDK at mcp/server/session.py:162, the server rejects any non-init request when self._initialization_state != InitializationState.Initialized:

case _:
    if self._initialization_state != InitializationState.Initialized:
        raise RuntimeError("Received request before initialization was complete")

The session state machine transitions:

  • NotInitialized → Initializing on InitializeRequest
  • Initializing → Initialized only when InitializedNotification (notifications/initialized) is received

Server-side logs from the repro show:

WARNING Failed to validate notification: Received notification before initialization was complete.
        Message was: method='notifications/roots/list_changed' params=None jsonrpc='2.0'
WARNING Failed to validate request: Received request before initialization was complete

The only notification ever observed from Claude Code's native SSE client is notifications/roots/list_changednever notifications/initialized. Per the MCP lifecycle spec, clients MUST send notifications/initialized after receiving InitializeResult and before any further requests.

Why this implicates Claude Code specifically

The same MCP server works correctly via:

  • npx -y mcp-remote <url> stdio bridge — used by Claude Desktop and Cowork. Handshake completes, notifications/initialized is sent, tool calls succeed.
  • The Python MCP SDK's ClientSession.initialize() — Handshake completes, tool calls succeed.

Both client implementations are spec-compliant. Only Claude Code's native SSE transport fails to send notifications/initialized.

Impact

  • Every MCP server configured in Claude Code via native SSE transport is unusable for tool calls. Schemas load (so /mcp looks healthy) but the server never accepts a single tools/call. Easy to miss in shallow testing.
  • The workaround (wrapping in npx mcp-remote) requires a Node subprocess per MCP server per Code session lifetime. Functional, but defeats the point of Claude Code having native SSE support.
  • This is likely under-reported because native SSE is presumably less commonly used than stdio transport in MCP setups. It bites the moment someone deploys their own MCP server on a remote host.

Suggested fix

Send notifications/initialized from Claude Code's native SSE transport client after receiving the server's InitializeResult response and before issuing any further requests. Per MCP spec, this is required behavior, not optional.

How to verify a fix

When a future Claude Code version claims to fix this, the verification is the Quick repro above with two changes — Step 1 uses the same native-SSE JSON config, Step 3 should now succeed.

A one-liner repro check from the laptop (assuming an SSE-capable MCP server is reachable at $URL):

# Drop a minimal native-SSE config into a scratch settings file
cat > /tmp/sse-test.json <<EOF
{"mcpServers": {"repro": {"type": "sse", "url": "$URL"}}}
EOF
# Launch Claude Code pointing at the scratch config, exec a single tool call, observe the exit
claude --settings /tmp/sse-test.json --print 'Call the simplest tool on the repro MCP server and report the result verbatim.'

If the output includes MCP error -32602, bug is still present. If the output includes the tool's actual response, bug is fixed.

Additional context

  • Only became observable after switching to a self-hosted MCP server reached over the network. Native SSE is presumably underused relative to stdio for MCP, which may explain why this hasn't been reported earlier.
  • tools/list works fine — schemas are fetched and displayed correctly under /mcp. The failure is specific to tools/call. This is consistent with the Python SDK's behavior: tools/list is permitted during Initializing, but tools/call requires Initialized.
  • Reproducible 100% of the time. Not a race condition. Not network-dependent (tested over both LAN and Tailscale overlay).
  • Discovered while debugging a self-hosted mem0ai/mem0 OpenMemory instance, but the bug is not specific to that server. Any MCP server using the official Python SDK on the server side will hit it.

What Should Happen?

After receiving the server's InitializeResult in response to its InitializeRequest, Claude Code's native SSE transport should send the notifications/initialized JSON-RPC notification before issuing any further requests — as required by the MCP lifecycle spec.
With that notification sent, the server transitions from Initializing to Initialized state and accepts subsequent tools/call requests normally. The user-visible behavior should match what happens today when the same MCP server is configured via the npx mcp-remote stdio bridge: tools list, tools call, and all return their expected payloads without -32602 errors.
In short — a server configured with "type": "sse" should be functionally equivalent to the same server reached via mcp-remote. There should be no difference in spec compliance between Claude Code's native SSE client and a Node-based bridge.

Error Messages/Logs

Steps to Reproduce

Spin up any MCP server speaking SSE that uses the official Python MCP SDK server-side. (I tested against mem0ai/mem0 OpenMemory, but the bug is independent of which server — the failure is in Claude Code's SSE client, not the server. Any spec-compliant SSE MCP server will repro.)
Add the server to ~/.claude.json using the native SSE transport:

json{
"mcpServers": {
"repro-server": {
"type": "sse",
"url": "http://YOUR_SSE_MCP_HOST:8765/mcp/sse/path"
}
}
}

Restart Claude Code. Run /mcp. repro-server shows as connected with its tool count populated correctly. So far so good — schemas load.
Ask Claude to call any tool exposed by repro-server. Observe the result:

MCP error -32602: Invalid request parameters

Confirm the bug is in Claude Code's native SSE transport (not in the server). Replace the same entry with the mcp-remote stdio bridge form:

json{
"mcpServers": {
"repro-server": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://YOUR_SSE_MCP_HOST:8765/mcp/sse/path",
"--allow-http"
]
}
}
}

Restart Claude Code. Repeat step 4 — same server, same tool, but reached through mcp-remote. Tool call now succeeds with the expected payload.
Inspect server-side logs from step 4 (any standard MCP Python SDK server logs to stderr by default). You'll see:

WARNING Failed to validate notification: Received notification before initialization was complete.
Message was: method='notifications/roots/list_changed' params=None jsonrpc='2.0'
WARNING Failed to validate request: Received request before initialization was complete
The only notification received from Claude Code's native SSE client is notifications/roots/list_changed. The required notifications/initialized is never sent — but is sent correctly when the same server is reached via mcp-remote, which is why step 6 works.
Note: Reproducible 100% of the time, not a race condition. Reproduces over LAN and over a Tailscale overlay network. tools/list works fine in the broken state — only tools/call is blocked, which matches the Python MCP SDK's behavior of permitting tools/list during Initializing but rejecting tools/call until Initialized.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.140

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

_No response_

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗