Windows Codex Desktop stdio MCP child process does not inherit user env vars for mcp-remote header substitution
Summary
On Windows Codex Desktop, a stdio MCP server launched via npx mcp-remote did not receive a user-level environment variable used in a custom Authorization header. As a result, mcp-remote forwarded the literal placeholder ${AMINER_MCP_AUTH_HEADER} to the remote MCP server instead of a JWT, causing authentication failures.
This looks like a Codex stdio MCP environment propagation/documentation issue rather than a remote MCP server issue: the same token works when connecting with the Python MCP SDK directly, and also works when the stdio server is launched through a PowerShell wrapper that explicitly loads the User environment variable.
Environment
- OS: Windows
- App: Codex Desktop
- Codex CLI shown in local docs/config:
0.133.0 - MCP server type: stdio wrapper around remote SSE via
mcp-remote - Remote MCP:
https://mcp.aminer.cn/sse - Node/npm available through
npx
Original config shape
[mcp_servers.AMiner_Scholar_MCP]
command = "npx"
args = [
"-y",
"mcp-remote@latest",
"https://mcp.aminer.cn/sse",
"--header",
"Authorization:${AMINER_MCP_AUTH_HEADER}",
"--transport",
"sse-only",
"--silent"
]
enabled = true
startup_timeout_sec = 120
AMINER_MCP_AUTH_HEADER was set as a Windows User environment variable and was visible from normal PowerShell/Python processes.
Expected behavior
Either:
- Codex should pass the relevant user/process environment to stdio MCP child processes so that
mcp-remotecan expand${AMINER_MCP_AUTH_HEADER}fromprocess.env, or - Codex documentation/config examples should make clear that
${VAR}inargsis not expanded by Codex and that stdio MCP child processes may not receive Windows User environment variables unless explicitly provided through MCP config or a shell wrapper.
Actual behavior
The launched mcp-remote process received the literal string as its header value. A process command-line shape check showed the Authorization value had:
- length: 25
- contained
$ - contained
{and} - had 1 JWT segment instead of 3
The remote AMiner MCP tool call returned:
{
"code": 40308,
"success": false,
"msg": "Token Parse Error"
}
Verification that the token/server were not the issue
Using the same token:
- Python MCP SDK direct SSE connection to
https://mcp.aminer.cn/ssesucceeded. list_toolsreturned 16 tools.search_paperreturnedcode: 200and paper data.- Launching the stdio server through a PowerShell wrapper also succeeded.
Workaround that fixed it
[mcp_servers.AMiner_Scholar_MCP]
command = "powershell.exe"
args = [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$env:AMINER_MCP_AUTH_HEADER = [Environment]::GetEnvironmentVariable('AMINER_MCP_AUTH_HEADER', 'User'); if (-not $env:AMINER_MCP_AUTH_HEADER) { throw 'AMINER_MCP_AUTH_HEADER missing' }; & npx -y mcp-remote@latest https://mcp.aminer.cn/sse --header 'Authorization:${AMINER_MCP_AUTH_HEADER}' --transport sse-only --silent"
]
enabled = true
startup_timeout_sec = 120
After this change, Codex exposed the AMiner MCP tool and search_paper returned code: 200.
Request
Please consider one of:
- ensuring stdio MCP servers inherit expected process/user environment variables on Windows Desktop,
- supporting explicit environment-variable expansion in MCP
args, - adding a config-supported way to map an existing user env var into the stdio child process without embedding secrets in
config.toml, or - documenting the expected behavior and recommended Windows workaround.
No secrets are included in this report.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗