[BUG] Channels (research preview): async MCP tool calls hang when the same streamable-HTTP server is bound as a channel source

Status Closed — not planned
Maintainer reply None cached
Activity 1 comment · opened Aug 20, 2026 · closed Aug 20, 2026

Summary

With the research-preview Channels feature, if a single MCP server exposed over the streamable-HTTP transport is bound as a channel source and also provides normal tools, async tool calls on that connection hang and never return to Claude Code — even though the same calls return in a few milliseconds to standard MCP clients, and the channel notifications themselves inject correctly.

Environment

  • Claude Code CLI (terminal), launched with --dangerously-load-development-channels server:<name>.
  • The channel source is an MCP server reached over the streamable-HTTP transport (not a stdio server Claude Code spawns).
  • That same server declares capabilities.experimental["claude/channel"] = {}, emits notifications/claude/channel, and also registers ordinary tools.

Symptom

  • A sync tool call on that connection returns normally.
  • An async tool call (one that returns immediately with an id and continues work in the background) never returns its result to Claude Code: the UI reports tool "…" is still running after 120s → moved to background → then fails with sent no response or progress for 300s; aborting.
  • The notifications/claude/channel events from the server do inject into the session correctly (the wake works). It is specifically the tool-call response that is not delivered.

Isolation (server is not at fault)

The identical server and identical async call return in 2–4 ms with Content-Type: application/json to:

  • curl (POST tools/call, with and without a progressToken in _meta), and
  • the official @modelcontextprotocol/sdk streamable-HTTP client (with and without a progress handler; before and after the connection has received a server notification).

Only Claude Code's MCP client hangs, and only when that server is bound as a channel source. This points to the Claude Code streamable-HTTP client's handling of tool-call responses on a connection that is also a channel subscriber (possible head-of-line blocking between the long-lived channel/SSE stream and pending tool-call responses).

Impact

A streamable-HTTP MCP server cannot be both a tool provider and a channel source on one connection — async tool calls to it become unusable. The workaround is to deliver channel events from a separate MCP server/connection, leaving the tool server not bound as a channel.

Repro sketch

  1. Stand up a streamable-HTTP MCP server that declares experimental["claude/channel"], registers a tool that returns immediately with a background job id, and emits notifications/claude/channel when the job finishes.
  2. claude --dangerously-load-development-channels server:that-server.
  3. Call the async tool. Observe the 120s→background→300s-abort hang, while a sync tool on the same server returns fine, and while curl/SDK get the async result in a few ms.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗