Interactive mode does not spawn stdio MCP servers from project-scope .mcp.json (v2.1.131)
Bug summary
Claude Code v2.1.131 in interactive mode does not spawn stdio MCP servers defined in project-scope .mcp.json, even when enabledMcpjsonServers allowlist contains the server name and alwaysLoad: true is set. The same configuration works correctly in claude -p headless mode and claude mcp list health check.
Reproduction
Setup
.mcp.json (project root):
{
"mcpServers": {
"skillinator": {
"type": "stdio",
"command": "/path/to/bridge.py",
"args": ["...", "--endpoint", "http://localhost:9876/mcp"],
"env": {"MCP_SPY_LABEL": "claude"},
"alwaysLoad": true
}
}
}
~/.claude.json for the workspace:
{
"projects": {
"/path/to/workspace": {
"enabledMcpjsonServers": ["skillinator"],
"hasTrustDialogAccepted": true
}
}
}
Trust dialog accepted, no auth pending in mcp-needs-auth-cache.json.
Behavior matrix
| Mode | Server spawned? | tools/list called? | Tool visible to LLM? |
|---|---|---|---|
| claude mcp list | ✅ Yes | ✅ Yes | (N/A — health check only) |
| claude -p "ping" headless | ✅ Yes | ✅ Yes (eager via alwaysLoad) | ✅ Yes |
| claude interactive | ❌ No subprocess spawned | ❌ Never called | ❌ mcp__skillinator__* not in ToolSearch registry |
Diagnostic evidence
pgrep -af mcp-protocol-bridge→ 0 processes when only interactiveclaudeis running.~/.cache/claude-cli-nodejs/<workspace>/mcp-logs-<server>/→ no new*.jsonlentries on interactive session start (only onclaude mcp listorclaude -p).- Custom bridge log → no
START label=claudeentry on interactive session, plenty for headless.
claude mcp list output (shows Connected for the ostensibly-missing server):
skillinator: /path/to/bridge.py ... - ✓ Connected
claude mcp get skillinator:
skillinator:
Scope: Project config (shared via .mcp.json)
Status: ✓ Connected
Type: stdio
But the interactive session LLM does not see mcp__skillinator__* tools and falls back to alternative paths (e.g. Bash(curl ...) in our case).
Workaround (validated)
Move the same server definition from .mcp.json (project-scope) to ~/.claude.json mcpServers.<name> (user-scope). With identical server config (just different scope), interactive mode spawns the bridge correctly and the LLM sees the MCP tools immediately.
jq '.mcpServers.skillinator = {
"type": "stdio",
"command": "/path/to/bridge.py",
"args": ["...", "--endpoint", "http://localhost:9876/mcp"],
"env": {"MCP_SPY_LABEL": "claude-userscope"},
"alwaysLoad": true
}' ~/.claude.json > /tmp/fix.json && mv /tmp/fix.json ~/.claude.json
After restart, interactive claude spawns the server and tools become available.
Environment
- Claude Code: 2.1.131 (
/home/mauro/.local/share/claude/versions/2.1.131) - Platform: Linux 6.12.58 / zsh
- MCP server: stdio bridge (Python) → Exograph 0.29 native MCP
Expected behavior
Interactive mode should spawn MCP servers defined in project-scope .mcp.json identically to headless -p and claude mcp list, when:
- Server is listed in
enabledMcpjsonServers - Trust dialog is accepted
- No auth pending
Relation to existing issues
Possibly related to (but distinct from):
- #51736 (
enabledMcpjsonServersallowlist required for.mcp.jsonv2.1.116+) — this is a prerequisite, our issue is downstream: even with allowlist set, project-scope is ignored in interactive.
Why this matters
Project-scope .mcp.json is the recommended pattern for MCP servers shared across team/repo (cross-machine portable via path templates). User-scope workaround forces hardcoded absolute paths in user config, breaking portability.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗