Skip to content

Env placeholder syntax for --header/--env is undiscoverable from CLI or npm package; ${env:VAR} silently passes through verbatim #323

Description

@elecnix

Summary

The environment placeholder format supported by mcporter for HTTP headers and stdio env values (${VAR}, ${VAR:-fallback}, and whole-value $env:VAR) is not discoverable by a user or coding agent that only has the npm package installed: it is not mentioned in any --help text, the README only says configs accept "environment placeholders" without giving the syntax, and the docs that do document it (docs/config.md) are not shipped in the published package (the tarball contains only dist/, LICENSE, README.md, and package.json). The only way to learn the format without opening the repo on GitHub is to read dist/env.js / dist/runtime/utils.js in the installed package.

Worse, the ${env:VAR} syntax that is the de-facto convention in Cursor / Claude Code / Codex / Windsurf MCP configs is silently NOT expanded: a header value like Authorization: Bearer ${env:SOME_API_KEY} is sent over the wire literally, producing a 401 that looks like a wrong API key. I hit exactly this: mcporter config add <name> <url> --header "Authorization=Bearer ${env:INNGEST_API_KEY}" wrote the config fine and connected with 401; switching the config to ${INNGEST_API_KEY} worked immediately. The placeholder regex requires an identifier followed by } or :-fallback, so ${env:VAR} fails the match and falls through untouched, and materializeHeaders sends the literal string. Because the CLI help promises nothing about interpolation, a user has no way to know this is the cause.

Places where the format could be mentioned (so a user or agent knows without reading source)

  1. mcporter config add --help — the --header KEY=value and --env KEY=value flag descriptions should state the supported placeholders and show an example, since that is the exact moment a user is authoring header/env values.
  2. mcporter config --help and mcporter config get --help — parent/subcommand help for the config surface.
  3. README.md — the sentence "Config files accept JSONC, environment placeholders, ..." should include the syntax inline (at minimum ${VAR} / ${VAR:-fallback} / $env:VAR), because docs/config.md is not available to npm installers.
  4. The published npm package — ship the docs directory (package.json "files" field) so the existing docs/config.md content is actually reachable from an install.
  5. docs/config.md — already documents the syntax well (headers/env schema rows and the placeholder section); keep it as the source of truth but make it reachable per point 4.
  6. JSON schema property descriptions for env and headers in the config schema, so editor/IDE validation surfaces the format.
  7. Runtime error handling — when a header/env value contains the unsupported ${env:...} pattern, fail fast with a clear error naming the variable instead of silently sending the literal string (which manifests as opaque 401/403 auth failures); either translate ${env:VAR} to the mcporter syntax or reject it explicitly.
  8. docs/import.md — imported Cursor/Claude/Codex/OpenCode configs very commonly use ${env:VAR} in mcpServers headers, so the import reference is the most likely place a user will inherit this syntax from and should warn that mcporter does not expand it.

Environment

  • mcporter 0.13.7 (latest as of filing)
  • Reproduced with an HTTP (SSE) remote MCP server and a Bearer auth header
  • Also verified the code path in dist/env.js resolveEnvPlaceholders and dist/runtime-header-utils.js materializeHeaders

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerThis issue is about auth, provider routing, model choice, or SecretRef resolution.impact:ux-frictionUser-facing flow adds avoidable confusion or support burden without fully blocking progress.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions