[BUG] macOS desktop app does not expand ${VAR} in .mcp.json env (unfixed part of #9427)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
${VAR} expansion in a project-root .mcp.json works in the CLI but NOT in the macOS desktop app. An MCP server spawned by the desktop app receives the literal string ${GOOGLE_MAPS_API_KEY} instead of the resolved value, so the downstream API rejects it as an invalid key.
This is the still-unfixed part of #9427 (closed "completed" 2025-12-19 with no linked fix, while users kept reporting it on 2.0.71/2.0.73) and #40372 (auto-closed as a duplicate). Both are now closed and locked.
Root cause: macOS GUI apps inherit the launchd environment, not the shell's. A variable that lives only in the shell or in .claude/settings.local.json's env block is therefore not present when the desktop app expands ${}. That env block reaches the Bash tool but is not used for .mcp.json ${} expansion in the desktop app.
What Should Happen?
Per the docs (https://code.claude.com/docs/en/mcp#environment-variable-expansion-in-mcp-json), ${VAR} expansion in .mcp.json should behave identically in the desktop app and the CLI. A variable defined in .claude/settings.local.json's env block should be available for ${} expansion regardless of how Claude Code is launched.
Error Messages/Logs
MCP tool call fails:
Failed to geocode address: API key invalid or required API not enabled.
But the SAME key works when sent directly:
$ curl "https://maps.googleapis.com/maps/api/geocode/json?address=Fukuoka&key=$GOOGLE_MAPS_API_KEY"
{ "status": "OK", ... }
Inspecting the running MCP child processes (`ps eww <pid>`) shows two instances:
# spawned by terminal `claude` CLI -> correct
GOOGLE_MAPS_API_KEY=AIzaSy... (length 39) works
# spawned by Claude desktop app -> literal, not expanded
GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY} (length 22) "API key invalid"
Process parentage confirms the broken instance is a child of the desktop app
(/Applications/Claude.app/.../claude-code/2.1.181/...), and that process's own
environment does not contain GOOGLE_MAPS_API_KEY.
Steps to Reproduce
- Put a secret in
.claude/settings.local.jsonenv(and/or a project.env), but do NOT export it from a shell rc — i.e. it is not in the macOS GUI/launchd environment. - Reference it in a project-root
.mcp.json:
"env": { "GOOGLE_MAPS_API_KEY": "${GOOGLE_MAPS_API_KEY}" }
- Launch Claude Code via the macOS desktop app (not a terminal) and call any tool from that MCP server.
- The call fails with an invalid-key/auth error;
ps ewwon the server shows the literal${GOOGLE_MAPS_API_KEY}. - Launch the same project via the terminal
claudeCLI in a shell that has the variable exported → it works.
Workaround: a LaunchAgent (RunAtLoad) that runs launchctl setenv GOOGLE_MAPS_API_KEY "$GOOGLE_MAPS_API_KEY", then fully quit (⌘Q) and reopen the app. This resolves it, confirming the cause is the launch environment, not the key or config syntax.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
N/A (CLI works; desktop app never worked for this)
Claude Code Version
2.1.181 (macOS desktop app)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗