MCP stdio initialize handshake no longer completes as of 2.1.282 (regression from 2.1.281) — tool calls still work, proactive server push breaks silently
Summary
Starting with Claude Code 2.1.282, the initialize handshake for a stdio-transport MCP server no longer reaches the server's ServerHandler::initialize() implementation (rmcp 3.1.2, Rust SDK). Symptom on the server side: the standard initialize/notifications/initialized exchange that used to complete cleanly on every prior version stops being logged at all — the server's own request-scoped tracing shows only Service initialized as server peer_info=None instead of peer_info=Some(InitializeRequestParams { ... client_info: Implementation { name: "claude-code", version: "2.1.28x", ... } }).
Oddly, tool calls continue to work normally after this — tools/call requests are dispatched and answered correctly even though the server never observed a completed initialize. Only things that depend on the initialize handshake having actually populated server-side peer state — in our case, proactive server→client push via the MCP channels feature (notifications/claude/channel) — silently stop working. The client itself surfaces this as:
Channel messages from "<server>" are unavailable: this connection's protocol version has no channel delivery path
which reads as a protocol-version mismatch, but is reproducible with an unchanged server (same binary, same rmcp version, same protocol version it always advertised) — only the CLI version changed.
Environment
- Claude Code: regression appears between 2.1.281 (last confirmed working) and 2.1.282 (confirmed broken), reproduced independently on two separate long-running sessions/machines
- MCP Rust SDK (
rmcp): 3.1.2 (unchanged across the whole window — verified viaCargo.lockgit history, no dependency bump in this timeframe) - Transport: stdio (bare
mcp_servers.<name>entry,command+args, no--channels/--dangerously-load-development-channelsrequired to reproduce — see below) - OS: Linux (koshak01 tested; both interactive and non-interactive/automation-launched sessions affected)
- Server: custom Rust MCP server using
#[tool_handler(router = self.tool_router)]+ a manualimpl ServerHandlerwith an overriddenasync fn initialize(...), advertisingcapabilities.experimental["claude/channel"]
Repro (observed, not synthetic — but trivially reproducible)
- Have a long-running stdio MCP server configured in
.mcp.json/settings (any server that logs or otherwise observes itsServerHandler::initialize()being called). - Run Claude Code 2.1.281 or earlier against it — initialize completes normally, tool calls work.
- Update to 2.1.282 (auto-update or fresh install) and start a new session against the same server.
- Observe:
tools/callrequests still succeed, but the server-sideinitialize()override is never observed as completing — no corresponding client-info log, no channel registration confirmation. If the server exposes an experimental channel capability, the client now reports:Channel messages from "<server>" are unavailable: this connection's protocol version has no channel delivery path.
This reproduced independently on two different sessions on the same machine after both were restarted and picked up 2.1.282 — one launched normally/interactively, one launched via an automation wrapper (non-interactive) with --dangerously-load-development-channels. Both show the identical symptom, which rules out that flag as the cause (we initially suspected it was — it is not; this is a separate, more general regression).
Debug evidence
Working session, client 2.1.281 (2026-09-24, before the regression):
INFO synapse::mcp_bridge: MCP handshake done, peer stored
INFO serve_inner: rmcp::service: Service initialized as server peer_info=Some(InitializeRequestParams { meta: None, protocol_version: ProtocolVersion("2025-11-25"), capabilities: ClientCapabilities { experimental: None, extensions: None, roots: Some(RootsCapabilities { list_changed: Some(true) }), sampling: None, elicitation: Some(ElicitationCapability { form: None, url: None }) }, client_info: Implementation { name: "claude-code", title: Some("Claude Code"), version: "2.1.281", description: Some("Anthropic's agentic coding tool"), icons: None, website_url: Some("https://claude.com/claude-code") } })
Broken session, same server binary, client 2.1.282 (2026-09-25, after auto-update/restart):
INFO serve_inner: rmcp::service: Service initialized as server peer_info=None
— no preceding "MCP handshake done" line (our own log statement inside initialize()), no InitializedNotification received afterward either. Yet the very same session went on to successfully make multiple tools/call requests for the rest of the day.
Impact
Any long-running stdio MCP server that relies on the initialize handshake completing (to store peer/client capabilities, to gate proactive server→client notifications, etc.) silently loses that functionality on update to 2.1.282, while appearing to work fine for ordinary tool calls — making this very easy to miss until you specifically go looking for why proactive server pushes stopped arriving.
Question
Is this a known regression in 2.1.282's stdio initialize handling, and is there a recommended workaround (env var, flag) short of pinning to 2.1.281?
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗