headersHelper for HTTP MCP servers is silently ignored — script never executed

Resolved 💬 4 comments Opened Mar 31, 2026 by tlongccm Closed Apr 4, 2026

Description

headersHelper in MCP server config is accepted at plugin install time but the specified command is never executed at runtime. This affects HTTP-type MCP servers in plugins. The feature is documented at code.claude.com/docs/en/mcp under "Use dynamic headers for custom authentication."

Reproduction

Minimal test plugin:

.claude-plugin/plugin.json

{
  "name": "headershelper-test",
  "version": "1.0.0",
  "description": "Test plugin to verify headersHelper execution",
  "mcpServers": {
    "headershelper-test": {
      "type": "http",
      "url": "https://httpbin.org/get",
      "headersHelper": "node \"${CLAUDE_PLUGIN_ROOT}/mcp_servers/test-headers.mjs\""
    }
  }
}

mcp_servers/test-headers.mjs

import { writeFileSync } from "fs";
import { join } from "path";
import { homedir } from "os";

const marker = join(homedir(), ".claude", "headershelper-test-marker.txt");
writeFileSync(marker, `headersHelper executed at ${new Date().toISOString()}\n`);

process.stdout.write(JSON.stringify({ "x-test": "headersHelper-works" }));

Steps:

  1. Install the plugin via a marketplace or --path
  2. Restart Claude Code / run /mcp
  3. Check for marker file: cat ~/.claude/headershelper-test-marker.txt

Expected: Marker file exists, proving the script was called.
Actual: File does not exist. The script is never executed.

Additional observations

  • Array format rejected at install: Using "headersHelper": ["node", "..."] fails plugin validation with mcpServers: Invalid input. Only the string format is accepted.
  • No error output: There is no error, warning, or log indicating that headersHelper was skipped or failed. The MCP server simply connects without the dynamic headers, leading to auth failures that are hard to diagnose.
  • Static headers field works fine as a workaround.

Platforms tested

| Platform | Claude Code version | Plugin installs? | headersHelper executed? |
|----------|-------------------|------------------|------------------------|
| macOS (Apple Silicon) | 2.1.87 | Yes | No |
| WSL (Ubuntu) | 2.1.87 | Yes | No |
| Windows (PowerShell) | 2.1.87 | Yes | No |

Workaround

Use static headers in plugin.json with a placeholder value, then have a login command inject the real token into the cached plugin.json at ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/.claude-plugin/plugin.json.

View original on GitHub ↗

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