TL;DR: I set "x-api-key": "${EXA_API_KEY}" in mcp.json and cmd literally sends the string ${EXA_API_KEY} to the server, so every API-key MCP gets a 401. Same for stdio env values. I had to write a stdio proxy to make exa and peekaboo work. Want to delete the workaround.
From here on the slop:
Summary:
mcp.json values like "x-api-key": "${EXA_API_KEY}" are sent to the server as the literal string ${EXA_API_KEY} instead of being resolved from the environment. The same happens for env values passed to stdio MCP servers. This breaks all API-key authenticated HTTP MCP servers and makes stdio env values useless.
Expected behavior:
Placeholders are resolved at runtime from process.env before they are sent or passed to the child.
Actual behavior:
The raw ${VAR} text is sent, causing HTTP 401 errors for servers like exa and peekaboo.
Steps to reproduce:
cmd mcp add --transport http exa https://mcp.exa.ai/mcp --header "x-api-key: \${EXA_API_KEY}"
cmd -p 'use exa to search for something'
exa returns 401 because the header value is the literal string ${EXA_API_KEY}.
I confirmed this with a local fake MCP server: the incoming HTTP header was authorization: Bearer ${FAKE_TOKEN}.
Version: 1.4.6
OS: macOS
Terminal/shell: ghostty / zsh
Additional context:
cmd mcp get exa redacts the header, so the bug is not visible there.
droid and other clients expand the same placeholders correctly.
env values for stdio servers are also passed literally, overriding any inherited env var with the placeholder text.
Summary:
mcp.jsonvalues like"x-api-key": "${EXA_API_KEY}"are sent to the server as the literal string${EXA_API_KEY}instead of being resolved from the environment. The same happens forenvvalues passed to stdio MCP servers. This breaks all API-key authenticated HTTP MCP servers and makes stdioenvvalues useless.Expected behavior:
Placeholders are resolved at runtime from
process.envbefore they are sent or passed to the child.Actual behavior:
The raw
${VAR}text is sent, causing HTTP 401 errors for servers likeexaandpeekaboo.Steps to reproduce:
cmd mcp add --transport http exa https://mcp.exa.ai/mcp --header "x-api-key: \${EXA_API_KEY}"cmd -p 'use exa to search for something'exareturns 401 because the header value is the literal string${EXA_API_KEY}.I confirmed this with a local fake MCP server: the incoming HTTP header was
authorization: Bearer ${FAKE_TOKEN}.Version: 1.4.6
OS: macOS
Terminal/shell: ghostty / zsh
Additional context:
cmd mcp get exaredacts the header, so the bug is not visible there.droidand other clients expand the same placeholders correctly.envvalues for stdio servers are also passed literally, overriding any inherited env var with the placeholder text.