Repository navigation
Description
Summary
Environment-variable substitution {env:NAME} in mcp.servers.*.environment resolves to an empty string, even though the variable is present in the OpenCode service process environment. Static values in the same environment map pass through correctly, so only substitution is broken. Documented at https://opencode.ai/v2/docs/mcp-servers ("Use {env:NAME} for environment substitution").
Environment
- opencode version: v2.0.25
- OS: Darwin 25.6.0 (darwin arm64) — macOS, zsh
- Terminal: iTerm.app, TERM=xterm-256color, COLORTERM=truecolor
- Shell: /bin/zsh
- Install/channel: latest (release)
- Active plugins: one local plugin discovered from
~/.config/opencode/plugins/icm.ts(unrelated to this issue); no package plugins configured
Reproduction
-
Export a test variable in the environment that launches OpenCode (verified present in the service process env via
ps eww <service-pid>):export HEVY_API_KEY=test-secret-value opencode -
Add a local MCP server to
opencode.jsonthat dumps its received environment:{ "mcp": { "servers": { "envtest": { "type": "local", "command": ["zsh", "-c", "env | grep -E '^(HEVY_API_KEY|DBG)' > /tmp/env-debug.txt; exit 1"], "environment": { "HEVY_API_KEY": "test-static-value", "DBG": "{env:HEVY_API_KEY}" } } } } } -
Run
opencode mcp list(or let the server auto-connect) and inspect/tmp/env-debug.txt.
Expected Behavior
DBG contains test-secret-value — the value of HEVY_API_KEY from the environment, per the documented {env:NAME} substitution.
Actual Behavior
DBG is an empty string. HEVY_API_KEY=test-static-value is received correctly, proving the environment map itself is applied — only {env:...} substitution resolves to empty.
Real-world impact (a local MCP server requiring a secret):
✗ my-server failed: Connection closed: MCP server process exited with code 1:
Hevy API key is required. Provide it via the HEVY_API_KEY environment variable.
— despite HEVY_API_KEY being set in the very same environment that runs OpenCode.
Additional Context
-
Reproducible consistently (100%, multiple runs).
-
Hypothesis: MCP server processes are spawned with a sanitized environment and substitution is resolved against that sanitized environment rather than the parent process environment. Alternatively, substitution may never be applied to the
environmentmap. -
opencode.jsonused: plain JSON project config (mcpsection only). -
Workaround that works: bypass substitution with a wrapper that reads the secret at spawn time, e.g.
"command": ["zsh", "-c", "export HEVY_API_KEY=\"$(cat ~/.config/opencode/hevy-api-key)\"; exec hevy-mcp"]
-
Recent changes around the repro: fresh opencode v2.0.25 install, first MCP server configuration in this project.
Activity
opencode-agent commentedon Oct 13, 2026
Thanks for the detailed report and the env-dump server. That made this easy to test.
I couldn't reproduce it on 2.0.25 (Linux). Here's what I tried with your config:
HEVY_API_KEYwas exported: the MCP server receivedHEVY_API_KEY=test-static-valueandDBG=test-secret-value. Substitution worked, and the static override of the same name didn't interfere.DBGcame out empty, exactly as you describe.{env:...}is resolved inside the background service against the service's own environment. Exporting a variable in a new shell, then runningopencodeoropencode mcp list, doesn't change a service that's already running. An unset variable is silently replaced with an empty string (Missing {env:VAR} in config silently resolves to empty string #33853).The service keeps running after you start opencode, so it may predate your
export, or it may have been started by the desktop app. Could you try these and say whether either fixes it?opencode service restart, thenopencode mcp list.opencode service set env HEVY_API_KEY <value>, thenopencode service restart.If
DBGis still empty after a restart, please tell us how the service gets started (CLI, desktop app or a login item) and which PID you checked withps eww. Also include the output ofopencode service get env.Related issues, ordered by likelihood:
{env:...}in MCPenvironmentcomes out empty{env:...}resolved empty until the service was restarted after the variable was set{env:VAR}silently becomes an empty string instead of showing a warningopencode-agent commentedon Oct 16, 2026
We haven't heard back, so I'm closing this as not planned for now.
On 2.0.25,
{env:HEVY_API_KEY}in an MCP server'senvironmentresolved correctly when the background service had the variable.DBGonly came out empty when the service was already running before the variable was exported. If you still see it afteropencode service restartfrom a shell that exports the variable, or afteropencode service set env HEVY_API_KEY <value>followed by a restart, please reply. Include how the service is started (CLI, desktop app or a login item) and the output ofopencode service get env, and we can reopen this.Related: #50882 (service missing saved env when the desktop app starts it) and #33853 (unset
{env:...}silently becomes empty). Thanks again for the clear report.