Custom Subagents Cannot Access Project-Scoped MCP Servers (Hallucinate Instead)
Summary
Custom subagents defined in .claude/agents/ cannot call MCP tools from locally-configured MCP servers (project-level .mcp.json). Instead of making actual MCP calls, subagents hallucinate plausible-looking results. Globally-configured MCP servers (~/.claude/mcp.json) work correctly in the same subagents.
Environment
- Claude Code Version: 2.0.68
- OS: macOS Darwin 24.6.0
- Shell: zsh
Steps to Reproduce
1. Set up a local MCP server
Create .mcp.json in project root:
{
"mcpServers": {
"padc-validator": {
"command": "uv",
"args": ["run", "--directory", "/path/to/project/mcp-servers/validator", "server.py"]
}
}
}
2. Create a custom subagent
Create .claude/agents/test-validator.md:
---
name: test-validator
model: haiku
description: Test agent for MCP validation
tools:
- mcp__padc-validator__validate_python_syntax
---
# Test Validator
When asked to validate Python code, call `mcp__padc-validator__validate_python_syntax` with the provided code and report the exact result.
3. Verify MCP server works from main thread
From the main Claude Code session, call the MCP tool directly:
Call: mcp__padc-validator__validate_python_syntax
Args: {"code": "def broken(\n return 42"}
Expected result: {"valid": false, "error": "'(' was never closed", "line": 1, "column": 11}
4. Test the same call via custom subagent
Spawn the custom subagent and ask it to validate the same code:
Task tool with subagent_type="test-validator"
Prompt: "Validate this Python code: def broken(\n return 42"
Expected result: Same error as main thread ('(' was never closed, line 1, column 11)
Actual result: Subagent returns a hallucinated error like invalid syntax (<unknown>, line 2) - different error message, different line number
5. Verify built-in subagent works correctly
Test the same MCP call using the built-in general-purpose subagent:
Task tool with subagent_type="general-purpose"
Prompt: "Call mcp__padc-validator__validate_python_syntax with code 'def broken(\n return 42' and report the exact result"
Result: Returns correct error ('(' was never closed, line 1, column 11)
6. Verify global MCP servers work in custom subagents
If you have a globally-configured MCP server (e.g., Playwright in ~/.claude/mcp.json), test it via a custom subagent:
Result: Works correctly - returns real data, not hallucinated
Evidence from Investigation
Test Matrix
| Subagent Type | MCP Server Location | Result |
|---|---|---|
Built-in (general-purpose) |
Local (.mcp.json) |
✅ Works |
Built-in (general-purpose) |
Global (~/.claude/mcp.json) |
✅ Works |
Custom (.claude/agents/) |
Local (.mcp.json) |
❌ Hallucinates |
Custom (.claude/agents/) |
Global (~/.claude/mcp.json) |
✅ Works |
Hallucination Evidence
Using intentionally broken Python code def broken(\n return 42:
- Real MCP result:
'(' was never closed, line 1, column 11 - Custom subagent (foreground):
invalid syntax (<unknown>, line 2)- WRONG - Custom subagent (background):
SyntaxError: unexpected indent- WRONG (different hallucination) - Built-in subagent:
'(' was never closed, line 1, column 11 - CORRECT
The hallucinated errors are syntactically plausible but factually incorrect, confirming the subagent is not actually calling the MCP tool.
What We Ruled Out
- Not a model issue: Tested with both
haikuandsonnetmodels - same behavior - Not a tools restriction issue: Tested with
tools:field present and omitted - same behavior - Not a foreground/background issue: Both execution modes hallucinate
- Not a tool calling syntax issue: Subagents can call built-in tools (Read, Write, etc.) correctly
Documentation Conflict
The sub-agents documentation states:
"MCP Tools: Subagents can access MCP tools from configured MCP servers. When the tools field is omitted, subagents inherit all MCP tools available to the main thread."
This implies custom subagents should have access to all MCP servers, including local ones. The current behavior contradicts this documentation.
Expected Behavior
Custom subagents should be able to call MCP tools from locally-configured MCP servers (.mcp.json) the same way they can call:
- Built-in tools (Read, Write, Glob, Grep, Bash)
- Globally-configured MCP tools (
~/.claude/mcp.json)
Actual Behavior
Custom subagents cannot call locally-configured MCP tools. Instead, they generate hallucinated responses that look like real MCP tool results but contain incorrect data.
Impact
This bug prevents using custom subagents for workflows that depend on local MCP servers, such as:
- Code validation pipelines
- Project-specific tool integrations
- Custom development workflows
The hallucination behavior is particularly problematic because:
- Results look valid, making the bug hard to detect
- Different runs produce different hallucinated results
- No error message indicates the MCP call failed
Workarounds
- Use built-in
general-purposesubagent for tasks requiring local MCP tools - Move MCP servers to global config (
~/.claude/mcp.json) if project-agnostic - Perform MCP calls at orchestrator level and pass results to subagents
Suggested Fix
Ensure custom subagents defined in .claude/agents/ have access to locally-configured MCP servers from the project's .mcp.json file, consistent with how built-in subagents and globally-configured MCP servers behave.
Found 3 possible duplicate issues:
- https://github.com/anthropics/claude-code/issues/13605
- https://github.com/anthropics/claude-code/issues/13890
- https://github.com/anthropics/claude-code/issues/13254
This issue will be automatically closed as a duplicate in 3 days.
- If your issue is a duplicate, please close it and 👍 the existing issue instead
- To prevent auto-closure, add a comment or 👎 this comment
🤖 Generated with Claude Code
Update: Confirmed Workaround
Further testing has confirmed that user-scoped MCP servers work correctly in custom subagents, while project-scoped MCP servers do not.
Working Workaround
Add MCP servers with --scope user instead of using project-level .mcp.json:
claude mcp add my-server --scope user -- command arg1 arg2
This stores the server in ~/.claude.json at the user level, and custom subagents can access it correctly.
Updated Test Matrix
| Subagent Type | MCP Server Scope | Result |
|---|---|---|
Built-in (general-purpose) |
Project (.mcp.json) |
✅ Works |
Built-in (general-purpose) |
User (--scope user) |
✅ Works |
Custom (.claude/agents/) |
Project (.mcp.json) |
❌ Hallucinates |
Custom (.claude/agents/) |
User (--scope user) |
✅ Works |
Conclusion
The bug is specifically in how project-scoped MCP server configurations are inherited by custom subagents. User-scoped servers are inherited correctly.
Trade-off of workaround: User-scoped servers require absolute paths and are available across all projects, so this works best for tools that aren't project-specific.
@YS-Crabtree Ive tried the above workaround, but the MCP tool calls for custom asynchronous agents still fail
| Agent Type | Execution Mode | MCP Access |
|---|---|---|
| Custom | Sync | ✅ Works |
| Custom | Async | ❌ Fails |
| Built-in (general-purpose) | Sync | ✅ Works |
| Built-in (general-purpose) | Async | ❌ Fails |
The async agent is trying to use Bash commands instead of calling the actual MCP function tools. Removing the project-scoped config didn't help.
The issue persists: async agents don't see MCP tools as callable functions, regardless of:
- Custom vs built-in agent type
- Project vs user MCP scope
- With or without project .mcp.json
This appears to be a fundamental bug in how Claude Code passes MCP connections to background agents. Only sync agents inherit the connections.
@dsull111 how do you run it synchronously? run_in_background: false does not seem to have an effect?