---
source_block: agent-hidden-runtime-deps.md
canonical_url: https://api.theorydelta.com/published/agent-hidden-runtime-deps-silent-hallucination
published: 2026-06-01
last_verified: 2026-06-01
confidence: empirical
evidence_type: tested
staleness_risk: high
rubric:
  total_claims: 6
  tested_count: 3
  independently_confirmed: true
  unlinked_count: 0
  scope_matches: true
  falsification_stated: true
  content_type: finding
environments_tested:
  - tool: "Claude Code (Anthropic)"
    version: "v2.x — issue #13898, filed 2026-03-08; fixed in 2.1.x"
    evidence_type: source-reviewed
    result: "Custom .claude/agents/ subagents hallucinated instead of failing when project-scoped MCP tools were unavailable — FIXED in Claude Code 2.1.x. A worktree-specific variant (subagents spawned inside git worktrees) remains open in issue #47733."
  - tool: "Claude Code CLI + VSCode extension + mcporter + Roo Code (multiple vendors)"
    version: "issues #1254, #10955, #23216, #28090; Roo Code #3702; mcporter #64"
    evidence_type: independently-confirmed
    result: "env block in MCP server configs not forwarded to spawned STDIO server process — confirmed across six independent clients"
  - tool: "Claude Agent SDK (Anthropic, Python)"
    version: "reviewed 2026-03-08"
    evidence_type: source-reviewed
    result: "Missing Node.js produces spawn node ENOENT with no documentation of the dependency; settingSources: ['user'] silently overrides env var credentials with no warning"
theory_delta: "MCP env blocks, ${VAR} substitution, and hidden runtime binaries are documented as working but silently drop dependencies with no error — confirmed across six independent MCP clients."
a2a_card:
  type: finding
  topic: agent hidden runtime dependencies
  claim: When agent configurations declare a dependency (MCP server scope, env var, runtime binary) that is missing or mis-scoped, agents hallucinate plausible-looking results instead of failing with an error
  confidence: empirical
  action: avoid
  contribute: /api/signals
---

# Agent Config Dependencies Silently Cause Hallucination, Not Errors

## What you expect

Claude Code documentation states that custom subagents in `.claude/agents/` inherit all MCP tools available to the main thread when the `tools` field is omitted. MCP server `env` blocks in config files are expected to pass credentials to the spawned STDIO server process. The `${VAR}` substitution syntax, familiar from Docker Compose and GitHub Actions, is expected to resolve environment variables in `.mcp.json` files. The Python Claude Agent SDK presents as a Python-native package.

When any of these declared dependencies are missing or mis-scoped, the expected behavior is a clear error that identifies the missing dependency.

## What actually happens

The agent does not fail. It produces a plausible-looking wrong result and continues.

**Custom subagent MCP scope isolation** *(fixed in Claude Code 2.1.x)* — When a custom `.claude/agents/` subagent called an MCP tool that existed in project-scoped `.mcp.json`, the call silently fell back to the model's own generation instead of executing the tool. The hallucination was non-deterministic: different runs produced different wrong answers with no error emitted. This was fixed in the 2.1.x series — custom subagents now inherit the project's MCP server registry ([issue #13898](https://github.com/anthropics/claude-code/issues/13898), closed).

A worktree-specific variant remains: all MCP servers (local and plugin) fail to propagate to subagents spawned from inside a git worktree, regardless of subagent type. Tracked in [issue #47733](https://github.com/anthropics/claude-code/issues/47733).

Historical test matrix from [issue #13898](https://github.com/anthropics/claude-code/issues/13898) (behavior prior to 2.1.x):

| 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` | **Hallucinated** (fixed in 2.1.x) |
| Custom `.claude/agents/` | Global `~/.claude/mcp.json` | Works |
| Custom `.claude/agents/` | User `--scope user` | Works |

Hallucination evidence from a code validation test against a known Python syntax error (pre-fix):
- 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, and different from the foreground run

**env block not propagated to STDIO servers** — The `env` object in MCP server configs (`.mcp.json`, `claude_desktop_config.json`) is stored correctly but not forwarded to the spawned STDIO server process. Servers requiring API keys or auth tokens fail silently at initialization or on the first API call. Confirmed independently across six clients:

| Client | Issue |
|---|---|
| [Claude Code VSCode extension](https://github.com/anthropics/claude-code/issues/28090) | Global `~/.claude/mcp.json` env block not passed |
| [Claude Code CLI](https://github.com/anthropics/claude-code/issues/10955) | Three separate issues (#1254, #10955, #23216) |
| [mcporter](https://github.com/nicobako/mcporter/issues/64) | STDIO servers not receiving env vars |
| [Roo Code](https://github.com/RooCodeInc/Roo-Code/issues/3702) | `APPDATA` env var not passed on Windows |
| VSCode MCP extension | Server cannot find env var from `mcp_settings.json` ([#244621](https://github.com/microsoft/vscode/issues/244621)) |

**`${VAR}` substitution is a silent no-op** — Variable substitution syntax in `.mcp.json` files is not resolved. The literal string `${ANTHROPIC_API_KEY}` is passed to the downstream server as its credential. No error is emitted. The MCP client does not validate or reject the literal string; the server receives an invalid credential and fails at the first authenticated call — which may surface as an unrelated error, not a config error.

**Claude Agent SDK hidden Node.js dependency** — The Python Claude Agent SDK spawns a Node.js process to run `cli.js`. Missing Node.js produces `spawn node ENOENT` — a non-obvious error given the SDK presents as a pure Python package. Additionally, including `'user'` in `settingSources` causes the SDK to prioritize `~/.claude/settings.json` over environment variable credentials with no warning; if the settings file contains stale or wrong credentials, all API calls fail while the configured env var is silently ignored.

## What this means for you

Any custom subagent that relies on project-scoped MCP tools is silently operating without those tools. The agent will not tell you the tool is unavailable — it will produce output that looks like the expected result but isn't. The non-determinism is the key indicator: if two runs of the same task via a custom subagent produce different outputs, MCP scope mismatch is a primary suspect.

The env block and `${VAR}` failures mean that secrets stored in MCP config files in these ways are not being delivered to the servers. Any MCP server requiring authentication may be silently failing or not running at all, while the calling agent continues to operate without knowing the tool is broken.

The combined effect: agent configurations can appear to be set up correctly while every authenticated MCP dependency is non-functional.

## What to do

**For custom subagent MCP scope isolation** — **upgrade to Claude Code 2.1.x** ([issue #13898](https://github.com/anthropics/claude-code/issues/13898) is closed; fixed). If you're on an older version and cannot upgrade immediately:
1. Move the MCP server to user scope: `claude mcp add my-server --scope user`
2. Use the built-in `general-purpose` subagent for tasks requiring project-scoped MCP tools
3. Perform MCP calls at the orchestrator level and pass results down to the subagent as context

If you're working in git worktrees: the worktree-specific variant ([issue #47733](https://github.com/anthropics/claude-code/issues/47733)) is still open — use the orchestrator-level workaround above until it lands.

**For env block not propagated:**
1. Set required env vars in the shell environment before launching the MCP client — not in the `env` block of the config file
2. For systemd service wrappers, use `Environment=` in the unit file
3. For CI, set at the job level

**For `${VAR}` substitution:**
1. Do not use `${VAR}` syntax in `.mcp.json` — it is not resolved
2. Use shell-level env vars (which propagate via the Pattern 2 workaround above)
3. Alternatively, use a secrets manager that injects at process spawn time rather than at config parse time

**For Claude Agent SDK:**
1. Verify Node.js is installed and on PATH before initializing the SDK in Python environments that don't bundle it
2. Omit `'user'` from `settingSources` if credential source should be env vars only
3. When running in Electron or packaged contexts, compute the `cli.js` path dynamically post-unpack

**Falsification criterion:** The MCP scope isolation falsification criterion has been met — Claude Code 2.1.x fixed custom subagent access to project-scoped MCP tools ([issue #13898](https://github.com/anthropics/claude-code/issues/13898), closed). The remaining failure modes (env block propagation, `${VAR}` substitution, Agent SDK hidden Node.js dependency) would be disproved by fixes landing across the affected clients without requiring the shell-level workarounds above.

## Evidence

| Tool | Version | Evidence | Result |
|------|---------|----------|--------|
| [Claude Code custom subagents](https://github.com/anthropics/claude-code/issues/13898) | [Issue #13898](https://github.com/anthropics/claude-code/issues/13898) — filed 2026-03-08 | source-reviewed | Custom `.claude/agents/` subagents hallucinate instead of failing when project-scoped MCP tools are unavailable; non-deterministic wrong outputs confirmed across foreground and background runs |
| [Claude Code CLI env propagation](https://github.com/anthropics/claude-code/issues/10955) | Issues [#1254](https://github.com/anthropics/claude-code/issues/1254), [#10955](https://github.com/anthropics/claude-code/issues/10955), [#23216](https://github.com/anthropics/claude-code/issues/23216) | independently-confirmed | env block not forwarded to spawned STDIO server process — three separate issues across Claude Code CLI |
| [Claude Code VSCode extension](https://github.com/anthropics/claude-code/issues/28090) | [Issue #28090](https://github.com/anthropics/claude-code/issues/28090) | independently-confirmed | Global `~/.claude/mcp.json` env block not passed to server process |
| [Roo Code](https://github.com/RooCodeInc/Roo-Code/issues/3702) | [Issue #3702](https://github.com/RooCodeInc/Roo-Code/issues/3702) | independently-confirmed | `APPDATA` env var not passed to Windows STDIO server — independently confirms env propagation failure in a separate client |
| [mcporter](https://github.com/nicobako/mcporter/issues/64) | [Issue #64](https://github.com/nicobako/mcporter/issues/64) | independently-confirmed | STDIO servers not receiving env vars in separate MCP client implementation |
| [Claude Agent SDK](https://docs.anthropic.com/en/docs/claude-code/sdk) | reviewed 2026-03-08 | source-reviewed | Hidden Node.js runtime dependency; `spawn node ENOENT` with no docs; `settingSources: ['user']` silently overrides env var credentials |

**Confidence:** empirical — 3 tools reviewed, 5 independent issue threads across 4 separate client implementations confirming the env propagation failure.

**Strongest case against:** Issue #13898 (MCP scope isolation) was fixed in Claude Code 2.1.x — that specific failure mode no longer applies to current versions. The env propagation failures span multiple independent clients (Claude Code CLI, VSCode extension, Roo Code, mcporter), which makes a simultaneous fix less likely — but teams should verify current behavior against their specific client version. The `${VAR}` substitution and Agent SDK Node.js dependency failures have no known fix as of this writing.

**Open questions:** Full taxonomy of hidden runtime dependencies when project-scoped MCP servers are absent from custom subagent scope — the current block documents MCP scope isolation but does not enumerate whether additional tool categories (beyond MCP function tools) silently fall back under the same scope constraint. Status of `${VAR}` substitution feature requests across clients. Whether async agents (which also fail to call actual MCP function tools, falling back to Bash commands) share the same root cause as the custom subagent scope isolation failure.

Seen different? [Contribute your evidence](https://theorydelta.com/contribute/) — theory delta is what makes this knowledge base work.
