Repository navigation
[DOCS] With CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1, more MCP header variables read as empty than the docs say (e.g. API_KEY) #100930
Description
Documentation Type
Incorrect/outdated documentation
Documentation Location
https://code.claude.com/docs/en/mcp#credential-variables-that-read-as-empty
Section/Topic
MCP: Credential variables that read as empty. Also env vars: CLAUDE_CODE_SUBPROCESS_ENV_SCRUB
Current Documentation
A name outside this set, such as
API_KEY, expands as written. To give the server one of the covered credentials, copy it into a variable with a name of your own and reference that name instead.
The CLAUDE_CODE_SUBPROCESS_ENV_SCRUB entry describes scrubbing only for subprocesses (Bash, hooks, stdio MCP servers). It doesn't mention remote MCP url/headers expansion.
What's Wrong or Missing?
When CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 is set, variables that read as empty in a remote server's headers also include ones the scrub recognizes as credentials, by name or by value. In my tests:
API_KEY=plain-value, the name the docs give as an example that expands, reads as empty.MY_HEADER="Bearer <43-char random token>"reads as empty, even though the name is your own. So the documented workaround of copying the credential into a variable with your own name doesn't help with the scrub on.
Without the scrub, both expand.
Repro on Claude Code 2.1.295 (macOS). Nothing needs to listen on the port, because only the debug log matters:
TOKEN=$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 API_KEY=plain-value MY_HEADER="Bearer $TOKEN" \
claude -p hi --strict-mcp-config --setting-sources project,local --debug-file /tmp/cc-debug.log \
--mcp-config '{"mcpServers":{"t":{"type":"http","url":"http://127.0.0.1:47899/mcp","headers":{"Authorization":"${MY_HEADER}","X-Key":"${API_KEY}"}}}}'
grep 'never expanded toward a remote server' /tmp/cc-debug.logWith the scrub on, the log names both variables (read as empty). A local test server then receives empty headers. Without the scrub, there is no log line and both values arrive.
This broke a real integration silently. T3 Code passes its MCP token via ${VAR} in the header (pingdotgg/t3code#17633, since pingdotgg/t3code#17408), and users with the scrub enabled got a 401 with no hint why.
Suggested Improvement
In "Credential variables that read as empty", add something like:
When
CLAUDE_CODE_SUBPROCESS_ENV_SCRUBis set, variables the scrub treats as credentials, recognized by name or by value, also read as empty in a remote server'sheaders. This includes names outside the set above, such asAPI_KEY, and variables with your own name whose value looks like a credential.
Please also document the supported way to send a credential to a remote MCP server with the scrub on. Integrations that launch Claude Code through the Agent SDK need one. Also add a cross-reference in the CLAUDE_CODE_SUBPROCESS_ENV_SCRUB entry on the env vars page.
If this widening isn't intended, please treat this as a bug report instead.
Impact
Medium - Makes feature difficult to understand
Additional Context
- Tested directly on Claude Code 2.1.295, macOS. T3 Code (Agent SDK) fails the same way on Linux with 2.1.296 and the scrub on; I didn't check the debug log there.
- Checked against the docs and changelog as of 2026-10-10. Related: [DOCS]
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1environment variable is missing from the docs #38559 (scrub originally undocumented).
Activity