headersHelper in plugin .mcp.json does not receive CLAUDE_PLUGIN_ROOT or CLAUDE_PLUGIN_DATA env vars

Resolved 💬 2 comments Opened Jun 17, 2026 by kostas-petrakis Closed Jun 17, 2026

Summary

headersHelper in a plugin-provided .mcp.json does not expand ${CLAUDE_PLUGIN_ROOT} in the command string, nor is CLAUDE_PLUGIN_ROOT (or CLAUDE_PLUGIN_DATA) available as an environment variable when the helper command executes.

The only environment variables available to headersHelper are:

  • CLAUDE_CODE_MCP_SERVER_NAME
  • CLAUDE_CODE_MCP_SERVER_URL

This makes it impossible for plugins to reference bundled authentication scripts in headersHelper, forcing authors to either inline the entire command or use absolute paths (which break on distribution).

Steps to reproduce

  1. Create a plugin with a script at scripts/get-token.sh
  2. Configure .mcp.json in the plugin root:
{
  "mcpServers": {
    "my-server": {
      "type": "http",
      "url": "https://example.com/api/2.0/mcp/endpoint",
      "headersHelper": "${CLAUDE_PLUGIN_ROOT}/scripts/get-token.sh"
    }
  }
}
  1. Install the plugin and start Claude Code
  2. The MCP server fails to connect — ${CLAUDE_PLUGIN_ROOT} is not expanded and the script is not found

Verified behavior

| Approach | Result |
|----------|--------|
| "headersHelper": "${CLAUDE_PLUGIN_ROOT}/scripts/get-token.sh" | ❌ Not expanded, script not found |
| "headersHelper": "$CLAUDE_PLUGIN_ROOT/scripts/get-token.sh" | ❌ Env var not set, script not found |
| "headersHelper": "/absolute/path/to/scripts/get-token.sh" | ✅ Works |
| "headersHelper": "inline command that outputs JSON" | ✅ Works |
| "command": "${CLAUDE_PLUGIN_ROOT}/servers/my-server" (stdio) | ✅ Works (expansion works for command field) |

Expected behavior

Either:

  1. ${CLAUDE_PLUGIN_ROOT} should be expanded in headersHelper strings (same as command, args, env, url, headers), OR
  2. CLAUDE_PLUGIN_ROOT and CLAUDE_PLUGIN_DATA should be set as environment variables when the headersHelper command executes (same as they are for hook processes and MCP server subprocesses)

Documentation inconsistency

The plugins reference states:

"All are substituted inline anywhere they appear in skill content, agent content, hook commands, monitor commands, and MCP or LSP server configs."

This implies headersHelper (which is part of an MCP server config) should support the substitution, but it does not.

The MCP docs env var expansion section lists supported expansion locations as: command, args, env, url, headers — notably headersHelper is missing from this list.

Impact

This blocks plugins from using native HTTP transport with dynamic authentication headers for remote MCP servers. Plugin authors are forced to either:

  • Inline the entire auth command (works but less maintainable)
  • Use stdio transport with a proxy like mcp-remote (adds unnecessary dependencies)

This is particularly impactful for MCP servers where tokens must be fetched dynamically.

Related

  • #47789 (same issue, closed as stale without fix)

Environment

  • Claude Code: v2.1.178
  • Platform: macOS (darwin)
  • Plugin installed via marketplace

View original on GitHub ↗

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