MCP collision check suppresses claude.ai connectors that point to a different workspace than the same-named plugin — no scriptable workaround
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?
When a built-in plugin MCP (e.g. plugin:slack:slack, plugin:atlassian:atlassian) and the corresponding claude.ai connector (e.g. claude.ai Slack, claude.ai Atlassian) are intentionally pointed at different upstream workspaces, the /mcp UI suppresses the claude.ai connector as a false duplicate:
claude.ai Slack · ◌ hidden — same URL as your server 'plugin:slack:slack'To use this connector instead, disable the plugin server in /plugins
The two connectors are not duplicates: they authenticate to different workspaces, hold different OAuth tokens, and expose different data. The collision detector matches on a normalized URL signature that strips the very identity (workspace / OAuth) that distinguishes them.
Impact: anyone running a plugin MCP and the same-named claude.ai connector at different workspaces (e.g. a corporate workspace and a team workspace) loses the claude.ai connector on every cold start, with no scriptable workaround. The failure is silent — the connector is suppressed rather than erroring — so a user may not notice their second workspace's data is simply missing.
This re-files #58375, which the stale bot auto-closed on 2026-06-12 (not_planned, "inactive for too long") with no maintainer response. It still reproduces on 2.1.195 (capture below); the deminified root-cause analysis was done against 2.1.139.
Root cause. The URL-normalization function collapses gateway-routed URLs to just the ?mcp_url=... param; the signature builder keys collision on that string. Both the plugin-side and the claude.ai-side connector for the same product carry the same mcp_url, so the workspace/OAuth identity that distinguishes them is not in the key. (Minified names rotate per release; grep the stable log string Suppressing claude.ai connector "X": duplicates manually-configured "Y". Functions below are from 2.1.139.)
VG7 = ["/v2/session_ingress/shttp/mcp/", "/v2/session_ingress/mcp/ws/", "/v2/ccr-sessions/"];
function vG7(H) {
if (!VG7.some((_) => H.includes(_))) return H;
try { return new URL(H).searchParams.get("mcp_url") || H; } catch { return H; }
}
function $wH(H) { // collision-key builder
let _ = E16(H); if (_) return `stdio:${hH(_)}`;
let q = S16(H); if (q) return `url:${vG7(q)}`; // <-- identity not in this string
return null;
}
Why there is no scriptable workaround. The /mcp Disable button writes to ~/.claude.json → projects[<cwd>].disabledMcpServers[], so a script editing that array seems equivalent — but from observed behavior the button also disconnects/loads the plugin in-memory in the running session, and we could not find an exposed path to that in-memory half. A file edit alone produces a split-brain session that needs another restart, which puts the file back into the suppressing state. So the only fix is a manual disable→restart→re-enable dance on every cold start.
What Should Happen?
The collision check should treat a plugin MCP and a claude.ai connector that point at different workspaces / OAuth identities as distinct, and leave both connected after a cold start — no manual dance required.
Concretely, one of:
- (Preferred) Include the per-connector stable
idin the collision signature built by$wH, so connectors differing only by workspace/identity stop colliding. - Skip URL-based collision detection for the managed claude.ai-side connectors (discriminate on whatever field reliably separates the two sides), since the user explicitly opted into them.
- Match only when the OAuth account / workspace identifiers are also equal.
Secondary ask if the above are out of scope: expose claude mcp reload <plugin> (or any IPC) that performs the in-memory disconnect/load the UI buttons do, so the workaround is at least scriptable instead of a five-step manual dance per cold start.
Error Messages/Logs
Captured on Claude Code 2.1.195 (2026-06-29), bottom of the `/mcp` "Manage MCP servers" list (47 servers; the list scrolls — this is the lower portion):
claude.ai Slack · ◌ hidden — same URL as your server 'plugin:slack:slack'
To use this connector instead, disable the plugin server in /plugins
Built-in MCPs (always available)
plugin:atlassian:atlassian · ✔ connected · 40 tools
plugin:slack:slack · ✔ connected · 18 tools
The `claude.ai Slack` suppression is the line directly above the "Built-in MCPs" section (where both plugins show connected). The `claude.ai Atlassian` connector is above the visible portion of this list; it exhibits the identical suppression, but only the Slack line is shown here to keep this a faithful, un-stitched excerpt.
Suppression log line to grep: `Suppressing claude.ai connector "X": duplicates manually-configured "Y"`
Steps to Reproduce
- Install the built-in Slack (and/or Atlassian) plugin and OAuth it to Workspace A.
- Separately enable the corresponding claude.ai connector (via claude.ai connector settings) and OAuth it to a different Workspace B — a distinct workspace with a distinct OAuth identity.
- Cold-start Claude Code (fully quit and relaunch) and open
/mcp.
Result: the claude.ai connector shows as hidden — same URL as your server 'plugin:...'; its tools never register in the session. The plugin connectors work.
Manual workaround (must repeat every cold start): /mcp → Disable both plugins → quit and restart → re-enable both plugins. After that, all four connectors function simultaneously, until the next cold restart.
Related but different: #39511 (closed not_planned) covered a cosmetic warning on disconnected claude.ai connectors where the plugins still worked. This issue is about valid, simultaneously-active dual-workspace connectors made unusable.
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.195
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_