[Bug] Claude Desktop 1.18286.0 silently drops an entire MCP server if its manifest display_name contains "&"

Open 💬 1 comment Opened Jul 3, 2026 by kiki830621

Summary

On Claude Desktop 1.18286.0 (macOS), if an installed .mcpb MCP server's manifest.json display_name contains a literal & (ampersand), Claude Desktop silently drops the entire server from every conversation. The transport handshake and tools/list both complete (Desktop receives the full tool list), but not a single tool is ever injected into any conversation, and nothing surfaces in any log — the drop happens above the MCP-protocol layer. The same server binary works end-to-end in Claude Code (which has no such injection layer).

This is distinct from #58239 (Calendar/Reminders TCC/entitlements). That bug is "server present, EventKit access denied"; this bug is "server absent, no tools at all" — a different failure at a different layer. It affects any .mcpb server, not just EventKit ones.

Environment

  • Claude Desktop: 1.18286.0 (regression appeared with this build; worked on prior builds)
  • macOS: 26 (Darwin 27), arm64
  • Repro server: local.mcpb.che-cheng.che-ical-mcp (Developer ID signed + notarized), but the trigger is manifest-content-only and server-agnostic

Root cause — confirmed by single-variable intervention

On the exact failing install, with the server binary and manifest.json otherwise byte-identical, changing only the display_name:

- "display_name": "macOS Calendar & Reminders",
+ "display_name": "macOS Calendar and Reminders",

flipped the server from dropped → injecting normally (real tool calls started returning data in a fresh conversation). No other variable changed — same binary, same tool count, same everything else. Reverting the & reproduces the drop; removing it fixes it, deterministically.

This also matches a clean regression timeline: the & had been in the display_name for months (the server worked in Desktop throughout); the server vanished only after the 1.18286.0 update, i.e. the update changed how the injection layer handles the field.

Reproduction

  1. Take any .mcpb extension. Set its manifest.json display_name to a string containing &, e.g. "Foo & Bar".
  2. Install it in Claude Desktop 1.18286.0, fully quit (Cmd+Q) and relaunch.
  3. Open a new conversation and look for the server's tools → none appear; the server is absent from the conversation's tool list.
  4. Edit the installed manifest.json display_name to remove the & (e.g. "Foo and Bar"), Cmd+Q + relaunch.
  5. Open a new conversation → the server's tools now appear and work.

The server process is spawned and healthy in both cases (visible in ps), and tools/list completes in both cases; only step 3 fails to inject.

Why it's hard to diagnose

  • No error in any Claude log — the MCP protocol exchange succeeds; the drop is in the injection/registration layer above it.
  • The server process runs normally, so process inspection looks fine.
  • The extension still shows in Settings by its display_name, so it looks "installed and enabled" while contributing zero tools.

display_name is a human-readable field where & (e.g. "Calendar & Reminders", "Docs & Database") is completely natural, so authors have no reason to suspect it.

Impact / scope

Any .mcpb author who used & in display_name loses their entire server under 1.18286.0 with no diagnostic signal. In a quick sweep of one author's 15 MCP servers, 2 carried a & in display_name — this is not a rare pattern.

Suggested fix

Either (preferred): the injection layer should tolerate a literal & (and other XML/HTML metacharacters) in human-readable manifest fields — presumably display_name is being interpolated somewhere without escaping. Or, at minimum: reject/escape it at .mcpb install time with a visible validation error, and document the constraint, so authors get a signal instead of a silent total drop.

Cross-references

  • Sibling TCC/entitlements bug (different layer, same server): #58239
  • Downstream fix + regression guard on the repro server: PsychQuant/che-ical-mcp#166

View original on GitHub ↗

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