Describe the bug
When apm install generates ~/.copilot/mcp-config.json for the copilot target, environment variable references (e.g. ${env:COPILOT_MCP_JIRA_PERSONAL_TOKEN}) are resolved to their actual values at install time and baked into the file as plaintext secrets.
The Copilot CLI adapter should instead emit ${VARIABLE} references (stripping the env: prefix), because Copilot CLI natively supports runtime variable substitution using $VAR, ${VAR}, and ${VAR:-default} syntax — as documented in the official GitHub docs.
This issue was introduced by PR #947 (fix for #944), which was based on the incorrect premise that "Copilot CLI mcp-config.json has no native interpolation."
To Reproduce
- Define an MCP server in
apm.yml with environment variable references:
target: copilot
dependencies:
mcp:
- name: my-atlassian
transport: http
url: https://my-instance.atlassian.net/mcp
headers:
"X-Atlassian-Jira-Personal-Token": "${env:COPILOT_MCP_JIRA_PERSONAL_TOKEN}"
- Ensure the environment variable
COPILOT_MCP_JIRA_PERSONAL_TOKEN is set in your shell.
- Run
apm install
- Inspect
~/.copilot/mcp-config.json
Expected behavior
The generated ~/.copilot/mcp-config.json should preserve environment variable references using Copilot CLI's native syntax:
{
"mcpServers": {
"my-atlassian": {
"type": "http",
"url": "https://my-instance.atlassian.net/mcp",
"headers": {
"X-Atlassian-Jira-Personal-Token": "${COPILOT_MCP_JIRA_PERSONAL_TOKEN}"
}
}
}
}
Translation rules should be:
apm.yml syntax |
mcp-config.json output |
${env:VAR} |
${VAR} |
${VAR} |
${VAR} |
$VAR |
$VAR |
This mirrors what the VS Code adapter does (preserving ${env:VAR} for VS Code's runtime) but adapted to Copilot CLI's documented syntax.
Actual behavior
The generated ~/.copilot/mcp-config.json contains the resolved secret values in plaintext:
{
"mcpServers": {
"my-atlassian": {
"type": "http",
"url": "https://my-instance.atlassian.net/mcp",
"headers": {
"X-Atlassian-Jira-Personal-Token": "<actual-secret-value-resolved-from-env>"
}
}
}
}
Security concern: This means secrets are stored in plaintext on disk in a user-global config file, which is both a security risk and breaks portability across machines/users.
Environment (please complete the following information):
- OS: Windows 11
- Python Version: 3.12
- APM Version: 0.12.2
- VSCode Version: 1.118.1
Logs
N/A — no error is raised; the behavior is silent and incorrect.
Additional context
Describe the bug
When
apm installgenerates~/.copilot/mcp-config.jsonfor thecopilottarget, environment variable references (e.g.${env:COPILOT_MCP_JIRA_PERSONAL_TOKEN}) are resolved to their actual values at install time and baked into the file as plaintext secrets.The Copilot CLI adapter should instead emit
${VARIABLE}references (stripping theenv:prefix), because Copilot CLI natively supports runtime variable substitution using$VAR,${VAR}, and${VAR:-default}syntax — as documented in the official GitHub docs.This issue was introduced by PR #947 (fix for #944), which was based on the incorrect premise that "Copilot CLI
mcp-config.jsonhas no native interpolation."To Reproduce
apm.ymlwith environment variable references:COPILOT_MCP_JIRA_PERSONAL_TOKENis set in your shell.apm install~/.copilot/mcp-config.jsonExpected behavior
The generated
~/.copilot/mcp-config.jsonshould preserve environment variable references using Copilot CLI's native syntax:{ "mcpServers": { "my-atlassian": { "type": "http", "url": "https://my-instance.atlassian.net/mcp", "headers": { "X-Atlassian-Jira-Personal-Token": "${COPILOT_MCP_JIRA_PERSONAL_TOKEN}" } } } }Translation rules should be:
apm.ymlsyntaxmcp-config.jsonoutput${env:VAR}${VAR}${VAR}${VAR}$VAR$VARThis mirrors what the VS Code adapter does (preserving
${env:VAR}for VS Code's runtime) but adapted to Copilot CLI's documented syntax.Actual behavior
The generated
~/.copilot/mcp-config.jsoncontains the resolved secret values in plaintext:{ "mcpServers": { "my-atlassian": { "type": "http", "url": "https://my-instance.atlassian.net/mcp", "headers": { "X-Atlassian-Jira-Personal-Token": "<actual-secret-value-resolved-from-env>" } } } }Security concern: This means secrets are stored in plaintext on disk in a user-global config file, which is both a security risk and breaks portability across machines/users.
Environment (please complete the following information):
Logs
N/A — no error is raised; the behavior is silent and incorrect.
Additional context
Original issue: [BUG] apm install writes bare ${VAR} in VS Code mcp.json headers #944 ("[BUG] apm install writes bare
${VAR}in VS Codemcp.jsonheaders")Fix PR: [fix] translate bare ${VAR} env-var refs in self-defined MCP server headers (#944) #947
The fix correctly handles the VS Code adapter (translating
${VAR}→${env:VAR}) but incorrectly handles the Copilot CLI adapter by resolving values at install time.GitHub Docs confirming Copilot CLI supports variable substitution: https://docs.github.com/en/copilot/how-tos/use-copilot-agents/cloud-agent/extend-cloud-agent-with-mcp#variable-substitution
The original issue reporter (@kkadete) also noted: "The target 'copilot' should also take this into consideration, but removing the 'env:' in case it exists" — which aligns with the expected behavior described above.