MCP tools not registered in non-interactive modes (SDK streaming, -p flag)
Bug Description
MCP server tools (mcp__<server>__<tool> format) are not registered in Claude's tool list when running in non-interactive modes:
- SDK streaming mode (
--input-format stream-json --output-format stream-json) - Print mode (
-pflag)
The MCP server connects successfully (logs show hasTools: true), but the tools never appear in Claude's available tool list. Only the generic ListMcpResourcesTool and ReadMcpResourceTool are available.
Interactive sessions (normal claude command) work correctly — MCP tools are registered and usable.
Environment
- Claude Code CLI: 2.1.50 (both system CLI via brew and SDK-bundled CLI)
- claude-agent-sdk (Python): 0.1.39
- OS: macOS (Apple Silicon)
- MCP Server: custom stdio server using FastMCP (mcp[cli] 1.26.0)
Reproduction Steps
1. Set up an MCP server
.mcp.json at project root:
{
"mcpServers": {
"my-server": {
"type": "stdio",
"command": "uv",
"args": ["run", "--project", "/path/to/mcp-server", "python", "-m", "my_server"]
}
}
}
2. Verify MCP server is recognized
claude mcp list
# Output: my-server: ... - ✓ Connected
3. Test in interactive mode (works)
claude
# Ask: "List your MCP tools starting with mcp__"
# Result: mcp__my-server__tool1, mcp__my-server__tool2, etc. ✓
4. Test in non-interactive mode (fails)
claude -p "List your MCP tools starting with mcp__" --max-turns 2 --permission-mode bypassPermissions
# Result: "No mcp__ tools available" ✗
5. Test via Python SDK (fails)
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
options = ClaudeAgentOptions(
permission_mode="bypassPermissions",
cwd="/path/to/project", # directory containing .mcp.json
setting_sources=["user", "project", "local"],
)
async for message in query(prompt="List your mcp__ tools", options=options):
print(message)
asyncio.run(main())
# Result: No mcp__ tools in tool list ✗
MCP Logs Confirm Connection
The MCP server connects successfully in all modes:
{"debug":"Successfully connected to stdio server in 312ms",...}
{"debug":"Connection established with capabilities: {\"hasTools\":true,\"hasPrompts\":true,\"hasResources\":true,...}"}
What Was Tested
| Configuration | Interactive | -p flag | SDK streaming |
|---|---|---|---|
| .mcp.json (project scope) | ✓ | ✗ | ✗ |
| claude mcp add (local scope) | ✓ | ✗ | ✗ |
| ~/.claude.json mcpServers (user scope) | ✓ | ✗ | ✗ |
| SDK mcp_servers param (--mcp-config) | N/A | N/A | ✗ |
| --setting-sources user,project,local | ✓ | ✗ | ✗ |
All configurations show the same pattern: MCP server connects, but tools are only registered in interactive mode.
Additional Issue: rate_limit_event MessageParseError
The SDK (0.1.39) also crashes on rate_limit_event message type from the CLI:
MessageParseError: Unknown message type: rate_limit_event
parse_message() in message_parser.py only handles 5 types (user, assistant, system, result, stream_event). The rate_limit_event type passes through the control message filter and crashes the message parser, terminating the entire response.
Expected Behavior
MCP tools should be registered and available in all CLI modes (interactive, -p, and SDK streaming), not just interactive sessions.
Workaround
Currently calling MCP server functions directly via subprocess (uv run --project ... python -c "...") instead of using MCP protocol integration.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗