Repository navigation
mcp: {env:...} in remote server headers not expanded (401 unauthorized) #56125
Description
Summary
{env:...} placeholders are not expanded inside a remote MCP server's headers values. The server receives an empty/invalid bearer token, so token-authenticated remote MCP servers fail with HTTP 401. A literal token in the same headers map works, so the connection and oauth: false handling are fine — only env substitution in headers is broken.
Environment
- opencode version: 2.0.31
- OS: Microsoft Windows NT 10.0.19045.0 (win32 x64)
- Terminal: Windows (PowerShell launched from OpenCode); terminal env vars unset
- Shell: C:\WINDOWS\system32\cmd.exe (COMSPEC); reproduction commands run via PowerShell
- Install/channel: latest
- Active plugins: none found in config
Reproduction
-
Configure a remote MCP server that requires a bearer token, using env substitution in the header (
~/.config/opencode/opencode.jsonc):{ "$schema": "https://opencode.ai/config.json", "mcp": { "servers": { "kagi": { "type": "remote", "url": "https://mcp.kagi.com/mcp", "oauth": false, "headers": { "Authorization": "Bearer {env:KAGI_API_KEY}" } } } } } -
Set
KAGI_API_KEYand confirm it is present in the process environment (verified: non-empty, correct length). -
Run
opencode mcp list.
Expected Behavior
✓ kagi connected
Actual Behavior
✗ kagi failed: Error POSTing to endpoint: {"error": "invalid_token", "error_description": "Authentication failed. The provided bearer token is invalid, expired, or no longer recognized by the server. ..."} (HTTP 401)
Server-side log for the attempt:
level=WARN message="mcp http authentication rejected" status=401 server=kagi method=POST origin=https://mcp.kagi.com
level=WARN message="mcp connect failed" server=kagi status.status=failed
The same request sent directly (PowerShell Invoke-WebRequest with Authorization: Bearer <key>) returns HTTP 200.
Additional Context
-
Literal token works. Replacing the header value with the literal token connects successfully:
"Authorization": "Bearer <token>"→level=INFO message="mcp connected" server=kagi tools=2. -
Whole-value substitution also fails. A header value of exactly
"{env:KAGI_AUTH}"(withKAGI_AUTH="Bearer <key>"set in the environment) also returns 401, so it is not specific to theBearerprefix. -
The variable is present in the environment where
opencode mcp listruns; this is not a missing-variable issue. -
Redacted config that fails:
"headers": { "Authorization": "Bearer {env:KAGI_API_KEY}" }
Redacted config that works:
"headers": { "Authorization": "Bearer <REDACTED>" }
-
Reproducible consistently (multiple
opencode mcp listruns). -
Workaround in use: literal token in
headers. -
Possibly related to issue Remote MCP with custom headers returning 401 Unauthorized despite oauth: false #30428 ("Remote MCP with custom headers returning 401 Unauthorized").
Activity
opencode-agent commentedon Oct 16, 2026
Thanks for the detailed report. I tried this on 2.0.31 (Linux) with your config, pointed at a local mock MCP server that logs the
Authorizationheader it receives:KAGI_API_KEYwas set:✓ kagi connected, and the header arrived asBearer <token>. A whole-value"{env:KAGI_AUTH}"worked too.opencode mcp listfrom a shell that has it:✗ kagi failed: ... (HTTP 401), which is exactly your error. The server receivedAuthorization: Bearerwith an empty token.The reason is that
opencode mcp listdoesn't load the config itself. It asks the background service, and the service fills in{env:...}from its own environment. An unset variable silently becomes an empty string (#33853). So if the service was already running beforeKAGI_API_KEYwas set, or was started some other way (for example by the desktop app or at login), setting the variable in PowerShell won't reach it.Could you try one of these and tell us whether it fixes it?
opencode service restartfrom a PowerShell window whereKAGI_API_KEYis set, then runopencode mcp list.If it still fails after that, please tell us how the service is started (CLI, desktop app, something else), the output of
opencode service get env(with the value redacted), and whetheropencode api get /api/configshows an empty token afterBearerforkagi. I could only test on Linux, so details like these would help narrow down anything Windows-specific.Related issues, ordered by likelihood:
{env:...}header came out empty until the service was restarted after the variable was set (Windows){env:...}in MCPenvironmentempty when the service doesn't have the variable{env:VAR}silently becomes an empty string with no warningopencode service set envopencode-agent commentedon Oct 19, 2026
Closing this for now since we haven't heard back. On 2.0.31,
{env:...}in remote MCPheadersworked in my tests whenever the background service had the variable. I only got your exact 401 (an empty token afterBearer) when the service had been started withoutKAGI_API_KEY. Variables set in PowerShell don't reach a service that's already running.If you haven't yet, try
opencode service set env KAGI_API_KEY <your key>and thenopencode service restart. If it still fails after that, please reply with how the service is started and the output ofopencode service get env(value redacted), and we can reopen this. My tests were on Linux only, so anything Windows-specific would help. Meanwhile #33853 tracks warning about unset{env:...}variables instead of silently using an empty string. Thanks for the detailed report!