[BUG] `claude mcp add` passthrough arg parser breaks on bare -p flag in subcommand args
Description
claude mcp add <name> -s <scope> -- <command> [args...] fails to parse when the passthrough command args (after --) contain a bare short flag -p (as in docker run ... -p 127.0.0.1:8085:8085). The CLI's own top-level option parser appears to rescan the args after -- and misfires on an unrelated top-level flag, rather than treating everything after -- as opaque passthrough.
This breaks the documented Docker-based local setup for MCP servers that need a published port (e.g. GitHub's official MCP server local/OAuth setup, per https://github.com/github/github-mcp-server/blob/main/docs/installation-guides/install-claude.md).
Environment
- Claude Code CLI version: 2.1.216
- OS: macOS (Darwin 25.5.0)
Steps to reproduce
# Fails: "error: unknown option '-s'"
claude mcp add testA -s user -- docker run -i --rm -p 127.0.0.1:8085:8085 alpine
# Fails the same way even with a simple non-colon value:
claude mcp add testC -s user -- docker run -i --rm -p 8085 alpine
Expected behavior
Everything after -- should be treated as opaque args for the subprocess command and never re-parsed as top-level CLI options — this is the standard meaning of -- in POSIX-style CLIs (and is what commander.js does by default).
Actual behavior
error: unknown option '-s'
The reported "unknown option" is whichever top-level option was passed before -- (-s, -e, or --scope, depending on order) — i.e. the presence of -p later in the passthrough args corrupts parsing of earlier, valid top-level options.
Workaround
Replacing the short flag with its long form in the passthrough command avoids the bug entirely, since it's specifically the bare -p token that trips the parser:
# Works:
claude mcp add testB -s user -- docker run -i --rm --publish 127.0.0.1:8085:8085 alpine
Minimal isolation
| Command tail (after --rm) | Result |
|---|---|
| -p 127.0.0.1:8085:8085 alpine | ❌ unknown option '-s' |
| -p 8085 alpine | ❌ unknown option '-s' |
| --publish 127.0.0.1:8085:8085 alpine | ✅ works |
| (no -p/-e at all) | ✅ works |
| single -e FOO=bar (no -p) | ✅ works |
Adding -p anywhere in the passthrough args reproduces the failure regardless of whether -e is also present.
3 Comments
Thanks for the detailed report and the minimal isolation table — this reproduces exactly as described.
Verified on the latest release (2.1.233, Linux, clean config):
Every row of your isolation table matches:
-p 8085fails the same way, while--publish 127.0.0.1:8085:8085, no--p, and-e FOO=bar-only variants all succeed.We also bisected across published releases: this worked correctly up through 2.1.81 and first breaks in 2.1.83 (no 2.1.82 was published), so it's a confirmed regression from that release onward — predating the 2.1.216 you reported against and still present in 2.1.233. Your diagnosis matches what we observed: a bare
-ptoken after--collides with a top-level short flag during a rescan of the passthrough args, which then corrupts parsing of the earlier, valid options. Everything after--should of course be treated as opaque.Marking as a reproduced regression. Until a fix ships, the workaround you found — using the long form (
--publish) in the passthrough command — is the best option.🤖 Generated with Claude Code
This was fixed in Claude Code v2.1.239: the CLI's early scan for the print flag (
-p/--print) now stops at the--separator, so flags in the passthrough command (like docker's-p 127.0.0.1:8085:8085) are no longer misread as CLI options.Verified on the current build:
Please update to v2.1.239 or later (
claude update). We also added regression tests covering this exact command so it stays fixed. Changelog: https://github.com/anthropics/claude-code/blob/main/CHANGELOG.mdThis issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.