Nested ${VAR:-${HOME}...} expansion broken in .mcp.json args

Resolved 💬 2 comments Opened Feb 13, 2026 by bbarry Closed Mar 14, 2026

Description

Claude Code's environment variable expansion in .mcp.json does not correctly handle nested ${...} inside ${VAR:-default} syntax. The parser appears to match the first } it encounters rather than the balanced/outer }, causing the remaining text to be appended as a literal suffix.

Reproduction

Given this .mcp.json entry (from an MCP plugin):

{
  "my-server": {
    "command": "docker",
    "args": [
      "run", "-i", "--rm",
      "-v", "${AI_TOOLS_MCP_DIR:-${HOME}/.ai-tools-mcp}:/root/.ai-tools-mcp:ro",
      "some-image:latest"
    ]
  }
}

With AI_TOOLS_MCP_DIR=/mnt/c/Users/username/.ai-tools-mcp set in the environment:

| | Volume mount source path |
|---|---|
| Expected | /mnt/c/Users/username/.ai-tools-mcp |
| Actual | /mnt/c/Users/username/.ai-tools-mcp/.ai-tools-mcp} |

The parser expands ${AI_TOOLS_MCP_DIR:-${HOME} (up to the first }), resolves the variable correctly, but then treats the remaining /.ai-tools-mcp} as literal text and appends it.

Evidence

Docker auto-creates missing volume mount source directories. After Claude Code starts MCP servers with the broken paths, the following directory structure appears on the host (owned by root, all empty):

/mnt/c/Users/username/.ai-tools-mcp/.ai-tools-mcp}/
├── certs/
├── documents/
└── vector-db/

The .ai-tools-mcp} directory name (with literal }) and its empty subdirectories exactly match the volume mount patterns in .mcp.json, confirming the expansion produced a broken path.

Impact

  • All MCP servers using ${VAR:-${NESTED}/path} in their .mcp.json args get broken volume mounts
  • Containers start with empty mount directories and fail to find credentials/config
  • Servers that require credentials at startup (GitHub, Jira, Confluence, etc.) crash immediately
  • Servers that can start without credentials (e.g., document-search) appear to work but have no data
  • The failure is silent from the user's perspective — /mcp just shows "Failed to reconnect"

Workaround

Replacing ${AI_TOOLS_MCP_DIR:-${HOME}/.ai-tools-mcp} with ${AI_TOOLS_MCP_DIR} (no default value, no nesting) in .mcp.json fixes the issue. However, this requires the env var to always be set, and for plugins the fix is overwritten on updates.

Expected Behavior

${VAR:-default} expansion should handle nested ${...} in the default value by matching balanced braces, consistent with POSIX shell behavior. If nested expansion is not supported, the documentation for .mcp.json should note this limitation.

Environment

  • Claude Code: 2.1.41
  • OS: Linux (WSL2) 6.6.87.2-microsoft-standard-WSL2 x86_64
  • Docker: Rancher Desktop (via WSL2 socket)

Related

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗