Claude Desktop: local MCP server stops receiving tools/list after reconnect, but status shows stale 'Connected (N tools)'

Status Open
Maintainer reply None cached
Activity 0 comments · opened Jul 23, 2026

Summary

A locally-configured MCP server (stdio, defined in claude_desktop_config.json under mcpServers) completes the MCP handshake successfully on every reconnect (initialize → response → notifications/initialized), but the Desktop app's internal connector manager (LocalMcpServerManager, per main.log) stops sending the follow-up tools/list request. The server therefore never registers any tools and is invisible to the conversation, while the app's own log keeps reporting Connected to <server> (1 tools) on every subsequent reconnect — a status that turns out to be a stale/cached tool count, not the result of a live query.

A second, unrelated local MCP server in the exact same config continues to receive tools/list normally on every reconnect throughout, ruling out a global/transport-wide issue.

Environment

  • Claude Desktop: reproduced on 1.22209.0 (build 77c938, 2026-07-16) and still reproduces after updating to 1.24012.1 (build 0adcae, 2026-07-21)
  • OS: macOS (Darwin 25.5.0)
  • Two local mcpServers entries configured, both stdio, both wrapper shell scripts:
  • zotero_cookjohn → works correctly throughout
  • rag-legal → affected
"mcpServers": {
  "zotero_cookjohn": { "command": "$HOME/scripts/zotero_mcp_stdio_wrapper.sh", "args": [] },
  "rag-legal": { "command": "$HOME/src/mcp_rag_wrapper.sh", "args": [] }
}
  • The affected server (rag-legal) works perfectly when the exact same command is used via Claude Code / claude.ai instead of Desktop — confirming the server process, its wrapper script, and its single exposed tool are all healthy. This isolates the bug to Desktop's client-side connector management.

Evidence

Last known-good connection

~/Library/Logs/Claude/mcp-server-rag-legal.log:

2026-07-21T15:55:41.438Z [rag-legal] [info] Server started and connected successfully
2026-07-21T15:55:42.907Z [rag-legal] [info] Message from client: method="tools/list" id=1 params

This is the last time tools/list was ever sent to this server, across dozens of reconnects since (verified through 2026-07-23, spanning a full app update).

First broken connection (~2h later, same evening, after a normal app quit/relaunch — not a crash)

2026-07-21T17:58:36.745Z [rag-legal] [info] Server started and connected successfully
2026-07-21T17:58:40.670Z [rag-legal] [info] Message from client: method="initialize" id=0 params
2026-07-21T17:58:40.671Z [rag-legal] [info] Message from server: id=0 result
2026-07-21T17:58:40.820Z [rag-legal] [info] Message from client: method="notifications/initialized"
2026-07-22T02:04:45.232Z [rag-legal] [info] Shutting down server...

No tools/list anywhere in this ~8-hour connection. Every subsequent reconnect (dozens, across two days and one app version upgrade) shows the identical pattern: full handshake, zero tools/list.

The misleading part: main.log reports a healthy status anyway

2026-07-23 12:19:28 [info] [LocalMcpServerManager] Connecting to rag-legal
2026-07-23 12:19:30 [info] [LocalMcpServerManager] Connected to rag-legal (1 tools)

This is logged ~9 seconds after a handshake that (per the raw MCP log above) never included a tools/list call. The "(1 tools)" figure matches the server's real, single tool (rag_query) — it's the last successful count from 2026-07-21, being redisplayed as if live. This makes the failure invisible from the app's own status output; it only surfaces when a user actually tries to invoke the tool in conversation.

Comparison with the unaffected server (same app, same timestamps)

zotero_cookjohn receives tools/list on literally every one of the same reconnect events where rag-legal doesn't:

2026-07-23 12:19:28 [info] Checking if UtilityProcess should be used for extension zotero_cookjohn
2026-07-23 12:19:28 [warn] UtilityProcess Check: Extension zotero_cookjohn not found in installed extensions

(This "UtilityProcess Check ... not found" warning appears identically for both servers — confirmed not to be the differentiator.)

Remediation attempts (all failed, same symptom every time)

  1. Full quit (Cmd+Q) + relaunch. No change.
  2. Remove the rag-legal entry from claude_desktop_config.json, confirm removal reflected in-app, re-add the identical entry, two full restarts. No change.
  3. Rename the config key rag-legalrag-legal-v2. Discovered along the way: claude_desktop_config.json is not the source of truth — on the next relaunch, Desktop silently rewrote the file back to rag-legal, overwriting the external edit before the app finished starting. (File mtime changes exactly at relaunch time; content reverts.) This suggests Desktop persists its own internal connector state elsewhere (plausibly its Electron IndexedDB/localStorage under ~/Library/Application Support/Claude/IndexedDB/https_claude.ai_0.indexeddb.leveldb) and treats the flat JSON config as a generated mirror rather than authoritative input.
  4. Remove rag-legal via Desktop's own in-app settings UI (not file editing) — confirmed this time that the removal genuinely propagated to the config file. Manually re-added the entry by editing the JSON file directly, then restarted. No change — identical stale-cache symptom returned.
  5. Full app update, 1.22209.0 → 1.24012.1. No change — bug reproduces identically on the new version.

Suggested areas to look at

  • Whatever code path decides to (re-)issue tools/list on an MCP server reconnect in LocalMcpServerManager — possibly a race between the notifications/initialized handler and whatever registers the "new connection, needs discovery" event, causing it to sometimes silently no-op instead of retrying.
  • The connector status/tool-count display should not fall back to a previous session's cached count when no live tools/list response has been received on the current connection — at minimum this should be visually distinguishable from a real live count, since it currently hides a total loss of functionality behind an apparently-healthy status line.
  • Given point 3 above, it may also be worth auditing why claude_desktop_config.json can get silently overwritten by the app's own internal state on startup, independent of this specific bug — external edits to that file are not guaranteed to stick.

Impact

The affected connector is completely unusable in Desktop conversations (no tools ever appear), with no user-visible error — the connector looks connected and healthy. The only workaround found was using the same MCP server configuration from Claude Code instead of Desktop.

View original on GitHub ↗