Preflight Checklist
What's Wrong?
When running claude mcp add to add a new MCP server to a project's .mcp.json, the command also expands existing environment variable placeholders (like ${GITHUB_PERSONAL_ACCESS_TOKEN}) and writes the resolved values back to the file.
This is a security risk as it can lead to accidental credential commits if the user doesn't notice the change.
What Should Happen?
Environment variable placeholders like ${VAR_NAME} should be preserved as literal strings when the CLI rewrites .mcp.json. Only the new MCP server entry should be added; existing entries should remain unchanged.
Error Messages/Logs
No error message - the operation appears to succeed, but inspecting .mcp.json reveals the expanded secrets.
Steps to Reproduce
- Create a
.mcp.json with environment variable placeholders:
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}"
}
},
"context7": {
"type": "http",
"url": "https://mcp.context7.com/mcp",
"headers": {
"CONTEXT7_API_KEY": "${CONTEXT7_API_KEY}"
}
}
}
}
-
Ensure the environment variables are set in your shell
-
Run claude mcp add to add a new server:
claude mcp add discourse -s project -- npx -y @discourse/mcp@latest
- Inspect
.mcp.json - the placeholders have been replaced with actual values:
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer gho_actualTokenValueHere..."
}
},
...
}
}
Claude Model
Opus 4.5
Is this a regression?
I don't know
Last Working Version
No response
Claude Code Version
2.1.9
Platform
Claude Max
Operating System
macOS
Terminal/Shell
Fish shell (but likely affects all shells)
Additional Information
Security Impact: This can lead to accidental credential leaks if users commit .mcp.json without noticing the expanded secrets.
Root Cause Hypothesis: When the CLI reads .mcp.json, it appears to resolve environment variables during parsing. When it writes the file back (after adding the new MCP server), it writes the resolved values instead of preserving the original ${...} syntax.
Workaround: After running claude mcp add, use git checkout -- .mcp.json to restore the original file, then manually add the new MCP server entry.
Related Issues:
Preflight Checklist
What's Wrong?
When running
claude mcp addto add a new MCP server to a project's.mcp.json, the command also expands existing environment variable placeholders (like${GITHUB_PERSONAL_ACCESS_TOKEN}) and writes the resolved values back to the file.This is a security risk as it can lead to accidental credential commits if the user doesn't notice the change.
What Should Happen?
Environment variable placeholders like
${VAR_NAME}should be preserved as literal strings when the CLI rewrites.mcp.json. Only the new MCP server entry should be added; existing entries should remain unchanged.Error Messages/Logs
No error message - the operation appears to succeed, but inspecting
.mcp.jsonreveals the expanded secrets.Steps to Reproduce
.mcp.jsonwith environment variable placeholders:{ "mcpServers": { "github": { "type": "http", "url": "https://api.githubcopilot.com/mcp/", "headers": { "Authorization": "Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}" } }, "context7": { "type": "http", "url": "https://mcp.context7.com/mcp", "headers": { "CONTEXT7_API_KEY": "${CONTEXT7_API_KEY}" } } } }Ensure the environment variables are set in your shell
Run
claude mcp addto add a new server:.mcp.json- the placeholders have been replaced with actual values:{ "mcpServers": { "github": { "type": "http", "url": "https://api.githubcopilot.com/mcp/", "headers": { "Authorization": "Bearer gho_actualTokenValueHere..." } }, ... } }Claude Model
Opus 4.5
Is this a regression?
I don't know
Last Working Version
No response
Claude Code Version
2.1.9
Platform
Claude Max
Operating System
macOS
Terminal/Shell
Fish shell (but likely affects all shells)
Additional Information
Security Impact: This can lead to accidental credential leaks if users commit
.mcp.jsonwithout noticing the expanded secrets.Root Cause Hypothesis: When the CLI reads
.mcp.json, it appears to resolve environment variables during parsing. When it writes the file back (after adding the new MCP server), it writes the resolved values instead of preserving the original${...}syntax.Workaround: After running
claude mcp add, usegit checkout -- .mcp.jsonto restore the original file, then manually add the new MCP server entry.Related Issues:
${...}folders