headersHelper does not expand ${CLAUDE_PLUGIN_ROOT} or set it as env var
Summary
headersHelper in plugin .mcp.json does not expand ${CLAUDE_PLUGIN_ROOT} in the command string, nor is CLAUDE_PLUGIN_ROOT available as an environment variable when the helper runs. This makes it impossible to reference scripts bundled with a plugin.
Steps to reproduce
- Create a plugin with a shell script at
scripts/headers.shthat outputs JSON headers - Configure
.mcp.json:
``json``
{
"mcpServers": {
"test": {
"type": "http",
"url": "http://127.0.0.1:9499",
"headersHelper": "${CLAUDE_PLUGIN_ROOT}/scripts/headers.sh"
}
}
}
- Install the plugin (tested both via
--plugin-dirand marketplace install) - The MCP server fails to connect. Debug log shows:
````
Error getting headers from headersHelper: headersHelper for MCP server
'plugin:test:test' did not return a valid value
Expected behavior
${CLAUDE_PLUGIN_ROOT} should be expanded in headersHelper strings (same as it is in command, args, and hook command fields). Alternatively, CLAUDE_PLUGIN_ROOT should be set as an environment variable when the helper command runs.
Workaround investigation
- Hardcoded absolute path: works, confirming
headersHelperitself functions correctly $CLAUDE_PLUGIN_ROOT(shell syntax): does not work (the variable is not in the environment)bash -c '$CLAUDE_PLUGIN_ROOT/scripts/headers.sh': does not work (same reason)- Static
headersfield: works correctly, confirming HTTP transport + custom headers function
Environment
We also confirmed that headersHelper only receives two environment variables:
CLAUDE_CODE_MCP_SERVER_NAMECLAUDE_CODE_MCP_SERVER_URL
It does NOT receive CLAUDE_PLUGIN_ROOT or CLAUDE_PLUGIN_DATA, unlike hooks and MCP server subprocesses which do receive both.
Documentation references
The official plugin-dev skill reference at plugins/plugin-dev/skills/mcp-integration/references/authentication.md shows ${CLAUDE_PLUGIN_ROOT} in headersHelper examples, suggesting this is intended to work.
The plugins reference docs state: "Both [CLAUDE_PLUGIN_ROOT and CLAUDE_PLUGIN_DATA] are substituted inline anywhere they appear in skill content, agent content, hook commands, and MCP or LSP server configs."
Impact
Without CLAUDE_PLUGIN_ROOT expansion, plugins cannot use headersHelper to reference bundled scripts. This blocks the migration from stdio proxy patterns to native HTTP transport for plugins that need dynamic auth headers (e.g., IAP-protected MCP servers).
Versions tested
- Claude Code v2.1.87
- Claude Code v2.1.104
Tested on Linux (WSL2).
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗