[BUG] claude.ai connectors that differ only by URL query string are deduplicated to one in Claude Code
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
I have several claude.ai connectors for one MCP server. Their URLs differ only by query string, and each one is a different role on the server:
https://mcp.example.com/mcp
https://mcp.example.com/mcp?role=accounting
https://mcp.example.com/mcp?role=client
Each connector is connected (OAuth) in claude.ai, and all of them work separately there. The server logs show requests to POST /mcp?role=client and POST /mcp?role=accounting, so claude.ai keeps the query string.
Claude Code loads only one of them. The others are dropped as duplicates. In the debug log, all of them show the same upstream URL with the query string removed. The connector list that Claude Code fetches from /v1/mcp_servers seems to return the URL without its query, so the dedup added in 2.1.121 ("Claude.ai connectors with the same upstream URL are now deduplicated") treats them as one server. Claude Code keeps the first one in the list.
There's no way to get them back. No setting turns off this dedup, and disableClaudeAiConnectors / ENABLE_CLAUDEAI_MCP_SERVERS / deniedMcpServers can only remove connectors.
What Should Happen?
Every connector should load as its own server, as it does on claude.ai. The MCP docs (https://code.claude.com/docs/en/mcp, "Scope hierarchy and precedence") say:
Two URL spellings count as the same endpoint when they differ only in the letter case of the scheme or host, the scheme's default port, such as:443onhttps, or a trailing slash. A different path, query string, userinfo, or non-default port makes two servers.
Connector-to-connector dedup should use the full URL, query included, or a connector key that is not lossy.
Error Messages/Logs
$ claude -p "ok" --debug claudeai-mcp
$ grep claudeai-mcp ~/.claude/debug/latest
[DEBUG] [claudeai-mcp] Fetching from https://api.anthropic.com/v1/mcp_servers?limit=1000&include_additional_installs=true
[DEBUG] [claudeai-mcp] Dropping duplicate upstream https://mcp.example.com/mcp: keeping mcpsrv_AAA, dropping mcpsrv_BBB
[DEBUG] [claudeai-mcp] Dropping duplicate upstream https://mcp.example.com/mcp: keeping mcpsrv_AAA, dropping mcpsrv_CCC
[DEBUG] [claudeai-mcp] Dropping duplicate upstream https://mcp.example.com/mcp: keeping mcpsrv_AAA, dropping mcpsrv_DDD
[DEBUG] [claudeai-mcp] Fetched 16 servers
(Host and connector ids redacted.)
Steps to Reproduce
- In claude.ai → Settings → Connectors, add two custom connectors for one MCP server whose URLs differ only by query string, e.g.
https://<host>/mcp?role=aandhttps://<host>/mcp?role=b. Connect both. - In claude.ai, check that both connectors show up and work separately.
- Run
claude -p "ok" --debug claudeai-mcp, thengrep claudeai-mcp ~/.claude/debug/latest. - The log has
Dropping duplicate upstream https://<host>/mcp: keeping …, dropping …. In an interactive session,/mcpand the tool list contain only one of the two connectors.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.296 (Claude Code). First seen on 2.1.227.
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other (tmux)
Additional Information
- Related: #54168 (docs on dedup of claude.ai connectors with the same upstream URL, closed as not planned) and #72333 (a connector suppressed by a same-URL plugin even though it is a different workspace). Neither covers connectors whose URLs differ by query string.
- Workaround on the server side: separate the roles by path (
/mcp/accounting) instead of query string. That needs a server change, and a query parameter is a normal way to select a role or tenant.