[Bug] MCP tool call wedges indefinitely without client-side timeout (CLI, no MCP_TOOL_TIMEOUT default)

Resolved 💬 2 comments Opened Jun 19, 2026 by aktopus Closed Jun 22, 2026

Type: Bug / robustness + feature (default timeout)
Claude Code version: 2.1.181 • OS: macOS 24.6.0 (darwin), zsh • Model: Opus 4.8 (1M context)

Summary

A single in-flight MCP tool call (run_snowflake_query, stdio MCP server) stalled server-side before the backend ever received the work, and Claude Code blocked on it for 6,348 seconds (~106 minutes) with no client-side timeout and no user-visible elapsed-time feedback. The session looked frozen ("Claude hung"); the only way out was a manual interrupt. This is distinct from the Claude Desktop timeout reports (#22542, #64614), which are the opposite problem — an over-aggressive fixed cap. Here the CLI has no effective cap.

What I expected

Either (a) a sane default per-tool-call timeout that aborts a wedged MCP call and returns a tool error, or (b) clear, continuously-updating user-facing feedback (elapsed time / "still running") plus a way to cancel just the tool call — so a stalled MCP server doesn't present as a frozen UI.

What happened

  • Two sequential run_snowflake_query calls (not a parallel batch). Call 1 returned cleanly in ~2.7s.
  • Call 2 was dispatched and never returned. The MCP server's own log shows it received the call and emitted still running (N s elapsed) heartbeats every 30s, climbing to 6,341s, then Tool 'run_snowflake_query' failed after 6348s: MCP error -32001: user-cancel — i.e., it ended only on my manual interrupt.
  • The backend (Snowflake) has zero record of call 2 ever executing — no SUCCESS, FAIL, CANCELLED, or RUNNING row. So the stall was in the MCP server's submit path, before the query reached the backend.
  • MCP_TIMEOUT and MCP_TOOL_TIMEOUT were unset (env + all settings.json). The call ran unbounded.

MCP server log excerpt (Snowflake MCP Server v2.14.7)

2026-06-18T19:32:21.833Z | Calling MCP tool: run_snowflake_query
2026-06-18T19:32:51.835Z | Tool 'run_snowflake_query' still running (30s elapsed)
2026-06-18T19:33:21.836Z | Tool 'run_snowflake_query' still running (60s elapsed)
   ... (heartbeats every 30s) ...
2026-06-18T21:18:03.467Z | Tool 'run_snowflake_query' still running (6341s elapsed)
2026-06-18T21:18:10.413Z | Tool 'run_snowflake_query' failed after 6348s: MCP error -32001: user-cancel

During that ~106 min the session transcript recorded no events between the tool dispatch and the user interrupt.

Impact

Any stdio MCP tool call that wedges server-side hangs the whole Claude Code session indefinitely. The MCP layer clearly has the progress signal (it logs still running (N s elapsed)), but it is not surfaced in the TUI and does not feed a timeout. Users experience it as a random freeze "with some frequency."

Requests

  1. Ship a sane default MCP_TOOL_TIMEOUT (per-tool-call execution ceiling) so a wedged call aborts and returns a tool error instead of hanging forever. #22542 already asks for MCP_TOOL_TIMEOUT parity — please confirm/document its CLI semantics and give it a non-infinite default.
  2. Surface long-running tool feedback in the TUI — the still running (N s elapsed) heartbeat already exists in the MCP log; show it (elapsed counter) so a slow/stalled call is distinguishable from a frozen client.
  3. Allow cancelling a single tool call without interrupting the whole turn/session.

Repro (approximate)

  1. Configure a stdio MCP server whose tool can stall in its submit path (network read / connection-handshake stall after a prior successful call).
  2. Issue a tool call that triggers the stall.
  3. Observe: no client-side timeout fires; the TUI shows no elapsed time; the session appears frozen until manual interrupt.

(In my case the trigger query was a COUNT(DISTINCT CASE WHEN … IN (subquery)) over a LATERAL FLATTEN of a 30M-row table — a heavy compile — but the defect is the unbounded, feedback-less wait, not the query.)

View original on GitHub ↗

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