[BUG] MCP stdio servers fail when they depend on env vars from .mcp.json (meta-ads-mcp)
Summary
Environment variables defined in the env block of .mcp.json are not being passed to stdio MCP server child processes. This causes any MCP server that reads config from env vars (rather than CLI args) to fail on startup.
Reproduction
.mcp.json config:
{
"mcpServers": {
"meta-ads": {
"type": "stdio",
"command": "/opt/homebrew/bin/npx",
"args": ["-y", "meta-ads-mcp"],
"env": {
"META_ACCESS_TOKEN": "<valid_token>"
}
}
}
}
What happens: The server starts, logs META_ACCESS_TOKEN: Missing, and exits with:
❌ Failed to start Meta Marketing API MCP Server: Error: Meta access token is required. Set META_ACCESS_TOKEN environment variable.
Claude Code reports: Failed to reconnect to meta-ads.
What should happen: The META_ACCESS_TOKEN from the env block should be passed to the child process, and the server should start normally.
Proof the token is valid: Running the exact same command manually in the terminal with META_ACCESS_TOKEN exported works perfectly. The server starts, authenticates, and responds to MCP requests.
Why other stdio servers aren't affected
Other npx-based MCP servers in the same .mcp.json (Stripe, Frase, DataForSEO) work fine because they accept secrets via CLI args (e.g., --api-key=xxx), which bypass the env var passing entirely. The meta-ads-mcp package only reads from env vars, making it the one that surfaces this bug.
Environment
- Claude Code: 2.1.81
- macOS: 26.2 (Darwin 25.2.0)
- Node: v25.2.1
- npx: 11.6.2
- Package:
meta-ads-mcp(npm, by pipeboard-co)
Related issues (all closed by inactivity bots, not by fixes)
- #1254 —
[BUG] Environment variables from env section not passed to MCP servers(closed Jan 2026, locked) - #10955 —
MCP Server Environment Variables Not Loading(closed Nov 2025 as dup of #1254, locked) - #23365 —
[BUG] claude mcp add doesn't work with environment variables for stdio transport(closed Mar 2026, locked) - #28090 —
[BUG] VSCode extension: MCP server env vars from global mcp.json not passed to server process(closed Feb 2026 as dup of #23216, locked)
All of these describe the same root cause. A commenter on #1254 identified the likely fix in the MCP spawning logic:
// Current (broken): replaces process.env entirely
spawn(command, args, { env: config.env || process.env })
// Fix: merge config env with process.env
spawn(command, args, { env: { ...process.env, ...(config.env || {}) } })
This issue has been reported since mid-2025 across macOS, Windows, and Linux, in both Claude Code CLI and Claude Desktop. The previous issues were all auto-closed by inactivity bots and then locked, so this is a fresh report as instructed by the lock messages.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗