Plugin headersHelper cannot read user_config: where the Sume key goes

Claude Code rejects ${user_config.*} inside an MCP headersHelper. Use the headers field for a Sume API key, or fetch the key inside the helper script yourself.

3 min readSume
All posts

If you put ${user_config.sume_api_key} inside a plugin's MCP headersHelper, Claude Code refuses to run it and reports an error. The plugin manifest reference lists headersHelper next to shell-form hook commands and monitor commands as fields that reject ${user_config.*}, because the value is passed to a shell that would re-parse it.

For Sume this has a simple answer. A static API key belongs in the headers field, where ${user_config.KEY} is allowed. Use headersHelper only when the header must be computed at connect time, and let the script obtain the key itself.

Which field accepts what

This table is from the plugin reference and covers only the fields that matter for a Sume entry.

Where ${user_config.KEY} works in a plugin MCP entry (read 2026-10-08)
Fielduser_config allowedWhat the helper or field receives
MCP http headersYesThe substituted value
MCP urlYesThe substituted value
MCP headersHelperNo, the component fails with an errorCLAUDE_PLUGIN_ROOT, CLAUDE_CODE_MCP_SERVER_NAME, CLAUDE_CODE_MCP_SERVER_URL; no option values
Shell-form hook commandNoRead CLAUDE_PLUGIN_OPTION_<KEY> from the environment instead
Exec-form hook argsYesThe substituted value as one argument

Two working patterns

Pattern one is the plain header. Declare the option with sensitive: true and write "Authorization": "Bearer ${user_config.sume_api_key}" under headers. This is the shortest path and the one we recommend for a Sume key.

Pattern two is a helper script. The helper's environment carries the plugin root, the server name and the server URL, and nothing else from the plugin options. So the script has to find the key on its own, for example from your secret manager, and print the header JSON. Use it when the key is short-lived or issued per user. Note that a Sume OAuth access token lasts 3600 seconds and has no refresh token, so a helper that mints a fresh token each connect fits that lifetime better than a pasted one.

Steps to check yours

Run claude plugin validate on the plugin directory. It reports an error for an entry Claude Code would drop and warns when a header value looks like a literal credential, which needs Claude Code 2.1.281 or later. Then call mcp_health from the session to confirm the Sume server authenticated.

  • Search the manifest for headersHelper and ${user_config on the same server entry.
  • Move static keys to headers.
  • Keep the helper script out of the Bash tool path; it runs at connect time, not as a model tool.

When a helper is the better fit

A helper earns its place when the secret should never sit in plugin storage at all. Imagine a laptop where the key lives in a company vault: the script asks the vault at connect time and prints the header. That keeps rotation in one system. For everyone else, the static headers entry with a sensitive option is simpler and has fewer moving parts to debug.

What Sume does not do

Sume does not issue refresh tokens for MCP OAuth. For an API key, rotation is your job: update the plugin option or the helper's source, then revoke the old key in your account. The server only sees the Authorization header, never how you produced it.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume