Don't Run That headersHelper Blind — Claude Code 2.1.238 Moves the MCP Trust Boundary
Takeaway: Starting in Claude Code 2.1.238, project and plugin headersHelper commands do not run until folder trust is accepted, and when they do run they do not inherit credential-like environment variables. Treat a shared .mcp.json as a shell execution surface, not a harmless config file.
Why it matters
MCP looks like a clean “tool port” for agent stacks. When an HTTP/SSE server is not on OAuth, teams reach for headersHelper to mint short-lived tokens or internal SSO headers at connect time. The docs are blunt: Claude Code runs a shell command, merges a JSON object of string headers from stdout, gives up after 10 seconds, and does not cache the helper output.
Convenience is the trap. Committing .mcp.json plus a helper script speeds onboarding — and that helper may be a command you did not write. Before 2.1.238, claude -p and SDK sessions could run project/local-scope helpers without checking folder trust, and interactive sessions could lean on parent-folder trust. That made “CI quietly prints a token into headers” easy to reproduce without a security review.
How it compares
| Axis | Before (summary) | After 2.1.238 |
|---|---|---|
Project .mcp.json / local-scope helpers | Weak trust check under -p/SDK | Runs only after that folder’s trust dialog is accepted |
| Parent-folder trust | Easy accidental bypass | Does not count |
| Credential env | Easy to inherit full process env | Project/plugin/project agent-file helpers strip TOKEN/SECRET/KEY/… patterns and a fixed list |
| User / managed / claude.ai / SDK helper cwd | Often tied to the start directory | Anchored to the Claude config dir (~/.claude or CLAUDE_CONFIG_DIR) |
In the same window, GitHub Copilot for JetBrains shipped enterprise managed-settings.json controls for MCP allow/deny, plugin marketplaces, OpenTelemetry, and disabling Bypass Approvals / Autopilot. Claude’s change is less “central allowlist” and more per-folder execution gate + helper environment isolation. Both say the same cultural thing: MCP attachment is no longer a personal preference — but they enforce it at different layers.
Code / config example
A project-committed HTTP MCP entry. The helper should read from a file or secret store, then print only a string-valued JSON object:
{
"mcpServers": {
"internal-api": {
"type": "http",
"url": "https://mcp.internal.example.com",
"headersHelper": "/opt/bin/get-mcp-auth-headers.sh"
}
}
}
#!/usr/bin/env bash
# get-mcp-auth-headers.sh — do not expect ANTHROPIC_API_KEY in project-scope helpers
set -euo pipefail
TOKEN="$(cat "${MCP_TOKEN_FILE:?set MCP_TOKEN_FILE to a secret file}")"
# or: op read "op://Eng/mcp/token"
printf '{"Authorization":"Bearer %s"}\n' "$TOKEN"
Without trust, Claude Code skips the helper and tries static headers only. Under -p/SDK you may also see one headersHelper not run line per server on stderr. For headless CI, the docs point at setting projects["<path>"].hasTrustDialogAccepted to true in ~/.claude.json — the path key must match the directory you actually start Claude in.
Working-directory rules tightened too. User/managed/claude.ai helpers now run from the config directory; project .mcp.json helpers resolve relative paths from the directory where you started the session. Prefer absolute paths or PATH entries over brittle relative helpers.
Practical use
- Name the scope first. Committed
.mcp.json, user/local, and plugins diverge on env stripping, cwd, and trust. - Review helpers like install scripts. Share the contract: JSON stdout, 10s timeout, fresh run on each connect/reconnect, one retry after 401/403.
- Put credentials in a file/store. Patterns that “just worked” by reading
ANTHROPIC_API_KEYor*_TOKENfrom the process env break for project-scope helpers. - On failure, reconnect via
/mcp. Helpers re-run on connect/reconnect; tool calls that return 401/403 trigger one more helper pass under the same trust rule. - Stop relying on parent-folder trust. Monorepo habits that trusted only the repo root no longer unlock nested project helpers.
I hit a wall the first time a previously green -p job started printing headersHelper not run. It was not an expired token — folder trust no longer auto-passed on the non-interactive path. Mounting the token file as a secret and aligning the trust key unblocked the reconnect.
Senior-engineer perspective
Most agent-era security regressions are not flashy CVEs; they are shell that used to run quietly. headersHelper sounds like HTTP cosmetics. In practice it is a connect-time execution hook. 2.1.238 tightens that hook with (1) a folder trust gate, (2) credential env isolation, and (3) cwd pinned to config provenance. It is not a perfect sandbox — once trusted, the command still runs. Removing “clone and CI magically attaches MCP” as the default is still the kind of change platform teams should put on a review checklist.
Using it in Cursor
You do not need to claim Cursor’s MCP model is a 1:1 clone of Claude’s headersHelper rules. Transfer the review habit:
- When a PR adds
.mcp.json, helper scripts, or inline MCP in agent files, require comments on trust + secret paths - Ask whether the helper depends on process env
*_TOKENvalues - Document which cloud/local agent environments already have trust accepted when overnight agents touch the same repo
The faster agents land PR fixes overnight, the more a one-line header helper defines your blast radius on the build machine.
FAQ
Q. If I only use static headers, do I need trust?
A. While the helper is skipped, Claude Code connects with static headers alone. Putting long-lived secrets in committed static headers is still a bad idea; short-lived tokens usually belong in a helper + file/store.
Q. Are user-scope helpers stripped too?
A. Per the docs, stripping mainly targets project .mcp.json / plugins / project or --add-dir agent files. User, managed, claude.ai, SDK, and --mcp-config helpers keep credential env. Moving scopes changes behavior — standardize one scope per team.
Q. What does headersHelper not run mean?
A. Usually the start folder is untrusted, or only a parent folder is trusted. Accept the dialog interactively, or set hasTrustDialogAccepted for CI, then reconnect with /mcp.
Q. Does Claude Code cache helper output?
A. No. Token reuse policy belongs in your script.
Sources
- Claude Code v2.1.238 release notes
- Claude Code MCP docs — dynamic headers & trust
- Enterprise managed settings in GitHub Copilot for JetBrains (comparison)
Going forward, the first line of an MCP onboarding checklist is less “which model is fastest” and more who is allowed to run which shell in which folder. Ask that once per committed helper and you keep agent speed without widening the blast radius.