Docs say `claude_desktop_config.json` MCP servers "will not appear in the Code tab," but the desktop app injects them into Code sessions
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 a recent build (Claude Desktop 1.9659.2 / engine 2.1.156)
Summary
The Desktop documentation states that MCP servers in claude_desktop_config.json are isolated from the Code tab, but in practice the desktop app injects them into Code-tab sessions at runtime. The documented contract and the actual behavior disagree.
Environment
- Claude Desktop (Windows): 1.9659.2 (x64 / MSIX)
- Bundled Claude Code engine: 2.1.156
- OS: Windows 10 Pro 19045
- Also reproduces on macOS per #53281 (desktop 1.4758.0 / binary 2.1.119), so this is not Windows-specific.
What the docs say
Desktop reference -> Shared configuration:
MCP servers configured for the Claude Desktop chat app inclaude_desktop_config.jsonare separate from Claude Code and will not appear in the Code tab. To use MCP servers in Claude Code, configure them in~/.claude.jsonor your project's.mcp.jsonfile.
What actually happens
MCP servers defined only in claude_desktop_config.json are present and callable in Code-tab sessions.
Repro
- Add a stdio MCP server to
claude_desktop_config.jsononly (do not add it to~/.claude.jsonor any.mcp.json). - Start a Code-tab session and list/call MCP tools.
- The server's tools are available (e.g.
mcp__<server>__*) even though no Claude Code file config references it.
In my case winget-mcp and a stdio github server exist only in claude_desktop_config.json, yet both are live in the Code tab.
Mechanism (from app bundle + live process inspection)
- The Code engine is launched by the desktop app as an SDK subprocess:
claude.exe --output-format stream-json --input-format stream-json --setting-sources=user,project,local ... — with no --mcp-config flag, so the servers are not arriving via a flag or settings file.
resources/app.asarparsesclaude_desktop_config.json(including validation and user-facing "...not valid MCP server configurations and were skipped" dialogs) and pushes servers to the running engine over the SDK control protocol:
query.setMcpServers({ ...claudeJsonMcpServers, ...activeMcpServers }) / replaceRemoteMcpServers.
- Independently corroborated by the
main.logexcerpt in #53281:
[CCD] [replaceRemoteMcpServers] Calling SDK with N total servers { serverNames: [ ...chat connectors..., 'ccd_session', 'ccd_directory', ... ] }.
Why it matters
- Contradicts the documented contract and causes confusion about where MCPs should be configured for the Code tab.
- Least-privilege / security: a coding agent that runs shell commands silently inherits every Chat MCP server, including ones holding plaintext credentials (e.g. a stdio GitHub server with a PAT stored in
claude_desktop_config.json). There is no documented way to opt out. - Duplicate toolsets: when the same service is configured both as a chat MCP and as a Code plugin/connector, the Code tab loads it twice.
Request
Please reconcile the docs with the behavior. If the injection is intended (it appears deliberate), document it, and consider an opt-in/toggle so users can keep Chat MCP servers out of Code-tab sessions.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗