claude-code - 💡(How to fix) Fix `claude mcp remove` expands `${VAR}` env-var references inline in `.mcp.json`, leaking secrets [2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#58850Fetched 2026-05-14 03:37:55
View on GitHub
Comments
2
Participants
2
Timeline
8
Reactions
0
Timeline (top)
labeled ×5commented ×2cross-referenced ×1

claude mcp remove <name> correctly deletes the named server entry from .mcp.json, but as a side effect it expands every ${VAR} env-var placeholder elsewhere in the file to its current literal value. Secrets that were safely referenced via env var get baked into the file on disk. If the user commits .mcp.json, credentials leak to git history.

A secondary bug mangles nested/default-value placeholders.

Error Message

"RUFLO_LOG_LEVEL": "warn"

Root Cause

claude mcp remove <name> correctly deletes the named server entry from .mcp.json, but as a side effect it expands every ${VAR} env-var placeholder elsewhere in the file to its current literal value. Secrets that were safely referenced via env var get baked into the file on disk. If the user commits .mcp.json, credentials leak to git history.

A secondary bug mangles nested/default-value placeholders.

Fix Action

Workaround

After any claude mcp command that writes .mcp.json, git diff .mcp.json and restore any ${VAR} placeholders by hand before committing.

Code Example

{
  "mcpServers": {
    "github": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
      }
    },
    "ruflo": {
      "command": "npx",
      "args": ["ruflo@latest", "mcp", "start"],
      "env": {
        "RUFLO_DATA_DIR": "${RUFLO_DATA_DIR:-${HOME}/.ruflo}",
        "RUFLO_LOG_LEVEL": "warn"
      }
    },
    "figma": {
      "type": "http",
      "url": "https://mcp.figma.com/mcp"
    }
  }
}

---

claude mcp remove figma -s project

---

-        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
   +        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_REDACTED..."

---

-        "RUFLO_DATA_DIR": "${RUFLO_DATA_DIR:-${HOME}/.ruflo}",
   +        "RUFLO_DATA_DIR": "${HOME/.ruflo}",
RAW_BUFFERClick to expand / collapse

Summary

claude mcp remove <name> correctly deletes the named server entry from .mcp.json, but as a side effect it expands every ${VAR} env-var placeholder elsewhere in the file to its current literal value. Secrets that were safely referenced via env var get baked into the file on disk. If the user commits .mcp.json, credentials leak to git history.

A secondary bug mangles nested/default-value placeholders.

Version

Claude Code 2.1.84 (Windows 11, PowerShell 5.1)

Repro

Start with .mcp.json containing env-var-referenced secrets and one server to remove. Example (sanitized):

{
  "mcpServers": {
    "github": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
      }
    },
    "ruflo": {
      "command": "npx",
      "args": ["ruflo@latest", "mcp", "start"],
      "env": {
        "RUFLO_DATA_DIR": "${RUFLO_DATA_DIR:-${HOME}/.ruflo}",
        "RUFLO_LOG_LEVEL": "warn"
      }
    },
    "figma": {
      "type": "http",
      "url": "https://mcp.figma.com/mcp"
    }
  }
}

Have GITHUB_PERSONAL_ACCESS_TOKEN set in the shell environment. Run:

claude mcp remove figma -s project

Expected

Only the figma block is deleted from .mcp.json. All other entries, including ${VAR} references, are preserved verbatim.

Actual

  1. figma is deleted (correct).
  2. ${GITHUB_PERSONAL_ACCESS_TOKEN} is replaced with the literal token value:
    -        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
    +        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_REDACTED..."
  3. The nested-default placeholder ${RUFLO_DATA_DIR:-${HOME}/.ruflo} is mangled to ${HOME/.ruflo}, which is invalid syntax and breaks the ruflo server on next start:
    -        "RUFLO_DATA_DIR": "${RUFLO_DATA_DIR:-${HOME}/.ruflo}",
    +        "RUFLO_DATA_DIR": "${HOME/.ruflo}",

Reproduced across six different env-var references in a single claude mcp remove invocation (GITHUB_PERSONAL_ACCESS_TOKEN, NEON_API_KEY, FAL_KEY, FIRECRAWL_API_KEY, BROWSERBASE_API_KEY, BROWSERBASE_PROJECT_ID — every secret in the file was inlined).

Impact

  • Security. Any claude mcp remove against a .mcp.json containing ${VAR} secret references will leak those secrets into the file on disk. Users who commit .mcp.json after running the command leak credentials to git history. There is no warning.
  • Correctness. The ${VAR:-default} and ${VAR_A${VAR_B}...} forms get destructively re-serialized, producing invalid env values that break servers.

Suggested fix

claude mcp remove (and presumably claude mcp add/update) should treat the JSON file as text-preserving: parse, mutate only the targeted block, and round-trip every other string value verbatim. Today it looks like the file is being read through an env-var-expanding parser and re-emitted, which is the wrong model for a file where those references are meant to stay as references.

Workaround

After any claude mcp command that writes .mcp.json, git diff .mcp.json and restore any ${VAR} placeholders by hand before committing.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix `claude mcp remove` expands `${VAR}` env-var references inline in `.mcp.json`, leaking secrets [2 comments, 2 participants]