Interactive mode does not spawn stdio MCP servers from project-scope .mcp.json (v2.1.131)

Resolved 💬 3 comments Opened May 6, 2026 by epicfail Closed May 6, 2026

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 interactive claude is running.
  • ~/.cache/claude-cli-nodejs/<workspace>/mcp-logs-<server>/ → no new *.jsonl entries on interactive session start (only on claude mcp list or claude -p).
  • Custom bridge log → no START label=claude entry 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 (enabledMcpjsonServers allowlist required for .mcp.json v2.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.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗