Summary
The built-in customize-opencode skill shows an MCP headers example using shell-style ${ENV_VAR} interpolation, but opencode only interpolates {env:VAR} in config strings. The result is that a user (or an agent loading this skill) who follows the example gets the literal ${ENV_VAR} text sent over the wire as the credential, with no warning.
Where
packages/opencode/src/skill/prompt/customize-opencode.md, line 307 in the current dev branch:
"headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" }
The skill body has zero matches for {env: anywhere in its 377 lines, so a reader has nothing to disambiguate against. The public docs at https://opencode.ai/docs/mcp-servers use the correct syntax (see the Context7 example: "CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}"), so the skill is the inconsistent surface.
Reproduction
Global config ~/.config/opencode/opencode.jsonc:
With MCP_TINYBIRD_TOKEN exported in opencode's launch env, opencode log (~/.local/share/opencode/log/<latest>.log) shows:
service=mcp key=tinybird transport=StreamableHTTP connected
service=mcp key=tinybird error=MCP error -32603: Internal error: Error calling TinybirdAPI: invalid authentication token. Invalid token b'${MCP_TINYBIRD_TOKEN}': failed to get tools from client
Replacing ${MCP_TINYBIRD_TOKEN} with {env:MCP_TINYBIRD_TOKEN} makes opencode connect successfully and load the tools.
opencode version: 1.15.11
Suggested fix
Update the example on line 307 (and the matching Authorization header example earlier in the file around the mcp config block) to use {env:...}, and add a one-liner near the MCP section calling out that config-string interpolation is {env:VAR} only — ${VAR} is not interpolated.
Diff sketch:
- "headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" }
+ "headers": { "Authorization": "Bearer {env:GITHUB_TOKEN}" }
Happy to send a PR if useful.
Summary
The built-in
customize-opencodeskill shows an MCPheadersexample using shell-style${ENV_VAR}interpolation, but opencode only interpolates{env:VAR}in config strings. The result is that a user (or an agent loading this skill) who follows the example gets the literal${ENV_VAR}text sent over the wire as the credential, with no warning.Where
packages/opencode/src/skill/prompt/customize-opencode.md, line 307 in the currentdevbranch:The skill body has zero matches for
{env:anywhere in its 377 lines, so a reader has nothing to disambiguate against. The public docs at https://opencode.ai/docs/mcp-servers use the correct syntax (see the Context7 example:"CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}"), so the skill is the inconsistent surface.Reproduction
Global config
~/.config/opencode/opencode.jsonc:{ "mcp": { "tinybird": { "type": "remote", "url": "https://mcp.tinybird.co/", "headers": { "Authorization": "Bearer ${MCP_TINYBIRD_TOKEN}" }, "enabled": true } } }With
MCP_TINYBIRD_TOKENexported in opencode's launch env, opencode log (~/.local/share/opencode/log/<latest>.log) shows:Replacing
${MCP_TINYBIRD_TOKEN}with{env:MCP_TINYBIRD_TOKEN}makes opencode connect successfully and load the tools.opencode version: 1.15.11
Suggested fix
Update the example on line 307 (and the matching
Authorizationheader example earlier in the file around themcpconfig block) to use{env:...}, and add a one-liner near the MCP section calling out that config-string interpolation is{env:VAR}only —${VAR}is not interpolated.Diff sketch:
Happy to send a PR if useful.