[BUG] Claude Desktop: tools/call discarded when the chat is switched before dispatch

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 4, 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?

This is a Claude Desktop bug. Filed here because Anthropic support directs Desktop reports to this repository and this is the only form available.

A tool call reaches the MCP server only if its chat is the active chat at the moment of dispatch. Between submitting the prompt and the dispatch, 5–45 seconds pass — with deferred tools the model runs tool_search first. Open a different chat in that window and the call is discarded: nothing is written to the server, no retry, no log entry anywhere in the client. Four minutes later the chat says:

No result received from the Claude Desktop app after waiting 4 minutes. The local MCP server providing this tool may be unresponsive, crashed, or not running. Further calls to this tool are likely to time out the same way; consider using an alternative approach or ask the user to restart their local MCP servers.

All three claims are false — the same server answered a control call in under 2 ms, 13 seconds after that message appeared, on the same process.

That text is not only shown to the user: it is delivered to the model as the tool result, and it ends with an instruction — "consider using an alternative approach or ask the user to restart their local MCP servers." The model follows it. In this run it replied that the server appeared "unresponsive or not running" and suggested restarting Claude Desktop's MCP servers. The wrong diagnosis is not merely displayed, it is propagated, and the suggested restart destroys the evidence.

Every call submitted while staying in the chat was delivered. Every call where I left the chat before dispatch was discarded.

Not a duplicate of #22451. That one was closed on 2026-05-25 — "the fix shipped in February", with an invitation to reopen on a current build — and then auto-locked, so the invitation cannot be taken up. The February fix addressed a collapsed tool box; the trigger here is leaving the chat, and it survives that fix six months later.

#66726 carries the same signature in June 2026 with logs from both sides, and was auto-closed as a duplicate of the fixed ticket by a bot. That thread states there is "no deterministic trigger". This report supplies one.

Also not the July 2026 dispatch outage (#79926, #79971, #80002). That one rejected the whole tools/list response when a tool declared $schema, so no call was ever dispatched, it failed instantly with "Tool execution failed", and it resolved server-side on 2026-07-23. Here the tool list was accepted and eight calls from it were dispatched normally on 2026-08-04; the tools declare no $schema.

What Should Happen?

A submitted tool call should be dispatched regardless of which chat is displayed when the dispatch happens.

Failing that, three lesser fixes would each remove most of the damage:

  1. Do not blame the local MCP server, and do not instruct the model to have the user restart it. The server is provably uninvolved — no bytes ever reach it.
  2. Log the discard. Discarded calls produce zero lines in mcp.log, main.log and the renderer log, so neither a user nor support can diagnose this from the client's own output.
  3. Fail fast, or retry. Four minutes of silence followed by a wrong diagnosis is the worst of both.

Error Messages/Logs

From an instrumented MCP server. Its capture and the client's own mcp.log agree to
the millisecond on every delivered call, and both are empty for every discarded one.


DELIVERED — probe-kilo, submitted, then switched to another APPLICATION

  capture   15:06:23.493  parsed in   id=8  echo  {"text":"probe-kilo"}
  capture   15:06:23.493  write out   id=8
  capture   15:06:23.494  flushed     id=8
  mcp.log   2026-08-04T15:06:23.492Z [mcp-debug] Message from client: method="tools/call" id=8
  mcp.log   2026-08-04T15:06:23.494Z [mcp-debug] Message from server: id=8 result(1 blocks)

  The dispatch happened 43 s AFTER the user left the application, with the window
  fully occluded. Window visibility and background throttling are not the factor.


DISCARDED — probe-juliett, submitted, then switched to another CHAT

  No line in the capture. None in mcp.log. None in main.log. No tool_approval_gate
  entry in claude.ai-web.log. The call exists only as a tool block in the UI and,
  four minutes later, as an error message.


DISCRIMINATOR — three calls, one variable each

  call           after submitting, switched to   returned after   result
  -------------  -----------------------------   --------------   ---------------
  probe-kilo     another application             never            delivered, 1 ms
  probe-lima     another chat                    3 s              delivered, 1 ms
  probe-juliett  another chat                    ~60 s            discarded

  Three seconds away is harmless: the dispatch had not happened yet.
  One minute away is fatal: it had.


RULED OUT — each with the measurement that refuted it

  server crashed, hung or restarted
      control calls answered in under 2 ms between the failures, and an in-process
      counter ran 0 -> 1 -> 2 -> 3 unbroken over 41 minutes

  back-pressure or a blocked write
      zero blocked writes; the detector does fire — against a deliberately
      non-reading consumer it reported 24 of 24 writes blocked

  approval dialog holding the call
      with the tool set to "always allow" it got worse, not better: nothing was
      delivered in that run

  deferred tool loading (tool_search)
      same result with a tool already in the loaded set

  tool identity, message size, handler duration
      ping, echo and slow_echo behave identically; 86-123 B requests,
      0-102 ms handlers

  Electron/Chromium background throttling
      see above: dispatched 43 s after the window was occluded

Steps to Reproduce

One chat is enough, and no dependencies are needed. Save this as echo-server.js — it is a complete MCP server whose stderr goes to ~/Library/Logs/Claude/mcp-server-echo-min.log, so the log itself shows whether a call arrived:

// Minimal MCP server over stdio. No dependencies. One tool: echo.
const send = m => process.stdout.write(JSON.stringify(m) + '\n');
let buf = '';
process.stdin.on('data', chunk => {
  buf += chunk;
  let i;
  while ((i = buf.indexOf('\n')) >= 0) {
    const line = buf.slice(0, i); buf = buf.slice(i + 1);
    if (!line.trim()) continue;
    console.error(new Date().toISOString(), 'IN', line);
    const m = JSON.parse(line);
    if (m.method === 'initialize') send({ jsonrpc: '2.0', id: m.id, result: {
      protocolVersion: m.params.protocolVersion,
      capabilities: { tools: {} },
      serverInfo: { name: 'echo-min', version: '1.0.0' } } });
    else if (m.method === 'tools/list') send({ jsonrpc: '2.0', id: m.id, result: {
      tools: [{ name: 'echo', description: 'Returns its text argument.', inputSchema: {
        type: 'object', properties: { text: { type: 'string' } }, required: ['text'] } }] } });
    else if (m.method === 'tools/call') send({ jsonrpc: '2.0', id: m.id, result: {
      content: [{ type: 'text', text: String(m.params.arguments.text) }] } });
    else if (m.id !== undefined) send({ jsonrpc: '2.0', id: m.id,
      error: { code: -32601, message: 'not implemented' } });
  }
});

Add it to claude_desktop_config.json:

{
  "mcpServers": {
    "echo-min": {
      "command": "/absolute/path/to/node",
      "args": ["/absolute/path/to/echo-server.js"]
    }
  }
}

Both paths must be absolute. command is the output of which node (where node on Windows) — a bare "node" is resolved against a PATH the app does not necessarily share with your shell.

Tested with Node v25.9.0. The script uses nothing version-specific, so any Node that Claude Desktop can launch should do.

Then:

  1. Restart Claude Desktop, then open Customize → Connectors → echo-min and set the Echo tool to Always allow. Otherwise the approval dialog holds you in the chat and suppresses the failure.
  2. Open a new chat and submit: Call the echo tool with the text probe-1. Answer with nothing but the tool's result.
  3. Immediately open a different chat. Do not wait to see whether anything happens — two seconds of watching can be enough for the call to go through.
  4. Stay away until the failure appears. The dispatch happens 5–45 s after submission and you have to be gone when it does — coming back early can let the call through and cost you the run.
  5. Return to the first chat and watch ~/Library/Logs/Claude/mcp-server-echo-min.log.

Expected: a tools/call line in the log and the result in the chat.
Actual: no tools/call line ever appears. After about four minutes the chat reports that the local MCP server may be unresponsive, crashed or not running. Returning to the chat does not recover it.

Two contrasts, both of which succeed — without them a single failed run proves nothing:

  • Leave for another application instead of another chat, for the same 60 seconds. The call is delivered while the window is occluded.
  • Leave for another chat for three seconds, then come back. The call is delivered, because the dispatch had not happened yet.

One condition matters. With only a handful of connected tools the dispatch is nearly immediate and there is barely any window to leave in. The run above had 6 servers and 177 tools in total, so tools were deferred and the model called tool_search first — that is what stretches the delay to tens of seconds. If it does not reproduce, add servers and repeat.

A fuller instrumented server, the complete protocol and the captured run are at https://github.com/rsascha/mcp-debug-claude-desktop.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

Claude Desktop 1.24012.11, Electron 42.7.0

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

Repository demonstrating the issue: https://github.com/rsascha/mcp-debug-claude-desktop

It contains an instrumented MCP server, the reproduction protocol, and the complete capture of the run quoted above in samples/reference-run-2026-08-04/. Running npm run analyse -- samples/reference-run-2026-08-04 prints the per-message table from it.

Screenshot: the failure as the user sees it, and what the model then does with it — the error text is delivered as the tool result, and the model relays its restart advice into the conversation.

Configuration: nothing beyond the four-line mcpServers entry in the reproduction steps is needed. The failure occurs with a single connected server, though a larger tool count widens the window in which it can be triggered.

One distinction I cannot resolve

#66726 describes a wedge: all servers stall simultaneously and only a full restart recovers. What I measured is a per-call race — control calls succeed in the same window, seconds after a failure, with no restart. These may be two defects sharing one symptom, or two severities of one. I cannot tell from outside the client and do not claim to.

Limits of this measurement

  • The dispatch path inside the client is not observable from outside it. "Never dispatched" is inferred from the absence of any request at the MCP layer and of any entry in the client's own logs — not from watching the dispatch.
  • The exact moment of dispatch cannot be observed before it happens, so the boundary between safe and unsafe was established by outcome, not by direct measurement.
  • One machine, one OS, one app version, 6 servers, deferred tools active. Whether any of those is a necessary condition has not been tested.
  • Sixteen calls is enough to show the pattern without exception, not enough to quantify a failure rate.

Related

  • #22451 — canonical, closed as fixed in February, now locked
  • #66726 — same signature, two-sided logs, auto-closed as a duplicate of the above by a bot
  • modelcontextprotocol#816"NO tools/call entry anywhere", tied to starting a new conversation, no response
  • #22127 — the return path gated on UI interaction: results not rendered until the user expands the tool panel. Closed not planned
  • #79926, #79971, #80002 — the July 2026 outage: tools/list rejected by client-side Zod validation when a tool declares $schema. Total, instant, resolved server-side on 2026-07-23. Listed to keep the two apart

<img width="1137" height="1104" alt="Image" src="https://github.com/user-attachments/assets/fc94e9c6-9808-4019-9512-206e9e1f0900" />

View original on GitHub ↗