[BUG] claude -p (non-interactive mode) does not connect to claude.ai MCP servers
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?
When using claude -p (non-interactive/print mode), claude.ai remote MCP servers (Atlassian/Jira, Slack, Notion, Google Calendar, Gmail, Sentry, Cloudflare, Context7) are never connected, even though:
- OAuth tokens are valid and accessible
- The
/v1/mcp_serversAPI call succeeds and returns the server list (verified via--debug) - All local/project MCP servers (from
.mcp.json) load normally in-pmode - The same machine, same user, same project — interactive mode loads all 114+ MCP tools correctly
What Should Happen?
claude -p should connect to claude.ai MCP servers the same way interactive mode does, since:
- The OAuth token is already available (no interactive login needed)
- The server list fetch already runs in
-pmode (only the connection step is skipped) - Local/project MCP servers already connect fine in
-pmode
Error Messages/Logs
# Interactive mode: 114 tools (including claude.ai MCP)
$ claude
# /mcp shows all remote servers connected ✓
# Non-interactive mode: 0 claude.ai MCP tools
$ claude -p "List tools starting with mcp__claude_ai" \
--output-format stream-json --verbose --max-turns 1 \
--dangerously-skip-permissions < /dev/null
# init event in stream output:
# Total tools: 92, claude.ai MCP tools: 0
# Only local MCP tools (codebase-memory-mcp, chrome-devtools, etc.) present
With DEBUG=* claude -p ..., I can see the /v1/mcp_servers?limit=1000 request IS sent and the server list IS fetched, but the individual server connections are never established.
Steps to Reproduce
- Ensure you have claude.ai MCP servers configured (Atlassian, Slack, etc.) — verify they work in interactive mode
- Run:
``bash``
claude -p "List all tools starting with mcp__claude_ai, one per line" \
--output-format stream-json --verbose --max-turns 1 \
--dangerously-skip-permissions < /dev/null 2>/dev/null \
| head -1 | python3 -c "
import sys, json
evt = json.loads(sys.stdin.readline())
tools = evt.get('tools', [])
mcp = [t for t in tools if t.startswith('mcp__claude_ai')]
print(f'Total: {len(tools)}, claude.ai MCP: {len(mcp)}')
"
- Observe:
claude.ai MCP: 0
Root Cause (binary analysis of v2.1.81)
The MCP initialization has two phases in the startup code:
// Phase 1: Fetch cloud MCP server list — runs in BOTH modes ✓
cloudServers = isPrintMode && !isSimpleMode && !hasEnterpriseMcp()
? fetchCloudMcpServers()
: Promise.resolve({});
// Phase 2: Connect to individual servers — SKIPPED in -p mode ✗
cloudMcp = isPrintMode
? Promise.resolve({ clients: [], tools: [], commands: [] }) // ← always empty
: cloudServers.then(connectServers);
// Final merge
allMcp = Promise.all([localMcp, cloudMcp]).then(merge);
The isPrintMode ? Promise.resolve({}) : ... condition unconditionally skips cloud MCP connection in -p mode.
Suggested Fix
Either remove the -p gate:
cloudMcp = cloudServers.then(servers =>
Object.keys(servers).length > 0 ? connectServers(servers) : { clients: [], tools: [], commands: [] }
);
Or add an opt-in flag (e.g., --connect-remote-mcp) for users who need cloud MCP in non-interactive mode.
Claude Code Version
2.1.81
Is this a regression?
I don't know
Claude Model
Opus
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Non-interactive/CI environment
Additional Information
Impact: This affects all non-interactive use cases — CI/CD pipelines, bot/bridge integrations (Telegram/Slack bots spawning claude -p), cron jobs, and SDK-style integrations.
Workaround: Configure each cloud MCP server as a local stdio server in .mcp.json using mcp-remote:
{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.context7.com/mcp"]
}
}
}
This works for servers without OAuth (Context7), but servers requiring OAuth (Atlassian, Slack, Notion) need individual OAuth flows through mcp-remote, defeating the purpose of unified claude.ai MCP.
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗