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

Status Open
Reported on v2.1.282
Maintainer reply None cached
Activity 2 comments · opened Sep 25, 2026

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 via Cargo.lock git history, no dependency bump in this timeframe)
  • Transport: stdio (bare mcp_servers.<name> entry, command + args, no --channels/--dangerously-load-development-channels required 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 manual impl ServerHandler with an overridden async fn initialize(...), advertising capabilities.experimental["claude/channel"]

Repro (observed, not synthetic — but trivially reproducible)

  1. Have a long-running stdio MCP server configured in .mcp.json/settings (any server that logs or otherwise observes its ServerHandler::initialize() being called).
  2. Run Claude Code 2.1.281 or earlier against it — initialize completes normally, tool calls work.
  3. Update to 2.1.282 (auto-update or fresh install) and start a new session against the same server.
  4. Observe: tools/call requests still succeed, but the server-side initialize() 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?

View original on GitHub ↗

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