fix(mcp): give 'mcp add --command' a distinct argparse dest - #19787
fix(mcp): give 'mcp add --command' a distinct argparse dest#19787discodirector wants to merge 1 commit into
Conversation
The --command flag of `hermes mcp add` shared its argparse dest with the top-level subparser (`dest="command"` in `hermes_cli/_parser.py`). When the flag was omitted, argparse still wrote `args.command = None`, clobbering the top-level value of `"mcp"`. The dispatcher then saw `args.command is None` and fell through to interactive chat, so `hermes mcp add ...` silently launched chat instead of registering the server. `cmd_mcp_add` was never reached. Use `dest="mcp_command"` on the flag and read it from `cmd_mcp_add`. The user-facing CLI flag `--command` is unchanged; only the in-memory namespace attribute moves. Also updates the `_make_args` helper in `tests/hermes_cli/test_mcp_config.py` to populate the new dest, and adds `tests/hermes_cli/test_mcp_add_command_dest.py` with a parser- level regression test. Closes NousResearch#19785. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Note: #17294 is an earlier PR for the same argparse dest collision fix. This PR appears more complete (includes regression tests). |
1 similar comment
|
Note: #17294 is an earlier PR for the same argparse dest collision fix. This PR appears more complete (includes regression tests). |
|
Merged via #21204 — your commit was cherry-picked onto current main with your authorship preserved (commit 4f364c4). Thanks for the clean root-cause analysis and the parser-level regression test — made the salvage trivial. Sorry it bit the Sonoglyph onboarding; the fix is on main now and next |
|
Already merged via #21204 (commit 4f364c4 on main) — your commit landed with your authorship preserved via rebase-merge. E2E-verified just now that |
Thanks ser for the trust, now onboarding really should go smooth as butter.
|

What does this PR do?
hermes mcp add <name> --url <url>silently launches an interactive chat session instead of registering an MCP server, because of an argparsedestcollision. This PR fixes the collision and adds a regression test at the parser layer.The top-level subparsers in
hermes_cli/_parser.pyusedest="command"so the dispatcher inmain.pycan route onargs.command. Themcp addsubparser registers a--commandflag (the stdio command for an MCP server) without an explicitdest=, so argparse derivesdest="command"from the flag name. Whenever--commandis omitted (e.g. on the documented--urlinstall path), the subparser still writesargs.command = None, clobbering the top-level"mcp". The dispatcher then seesargs.command is Noneand falls through tocmd_chat.cmd_mcp_addis never reached — there is no error, no warning, no log.The fix gives the flag an explicit, non-colliding dest. The user-facing CLI flag
--commandis unchanged; only the in-memory namespace attribute moves.Related Issue
Fixes #19785.
Type of Change
Changes Made
hermes_cli/main.py— declaremcp_add_p.add_argument("--command", dest="mcp_command", ...)so the flag no longer overwritesargs.command. Comment explains the constraint so a future cleanup pass does not re-introduce the collision.hermes_cli/mcp_config.py—cmd_mcp_addreadsgetattr(args, "mcp_command", None)instead ofargs.command. Comment cross-references the parser.tests/hermes_cli/test_mcp_config.py—_make_argshelper now defaultsmcp_command=None(wascommand=None); the four call-sites that asserted stdio-server behavior passmcp_command="npx"/mcp_command="uvx"accordingly. Pure mechanical rename, no logic change.tests/hermes_cli/test_mcp_add_command_dest.py(new) — three parser-level regression tests modelled ontest_argparse_flag_propagation.pyandtest_subparser_routing_fallback.py. They build a minimal replica of the parent +mcp addsubparser, parse representative argv vectors, and assert (a)args.commandstays"mcp", (b)--command npxpopulatesargs.mcp_command(notargs.command), (c) the bare-mcp addform also preserves the top-level dest.How to Test
Reproduce on
mainatcfd86dc:Observe an interactive chat prompt opens;
hermes mcp listshows noexampleentry.Apply this PR. Repeat the command. The MCP server is now registered;
hermes mcp listshowsexample.Run the new regression test:
All three tests should pass. Reverting the
dest="mcp_command"change makestest_url_invocation_preserves_top_level_commandandtest_bare_mcp_add_does_not_clobber_commandfail withargs.command == None.The existing
tests/hermes_cli/test_mcp_config.pysuite (covering stdio-add, env vars, presets, etc.) continues to pass after the helper rename.Notes on scope
args.commandattribute. A naïve fallback (getattr(args, "mcp_command", None) or getattr(args, "command", None)) would silently return"mcp"whenevercmd_mcp_addis invoked through the real dispatcher (because argparse setsargs.command = "mcp"from the top-level subparser), makingcmd_mcp_addthink the user passed--command mcp. The clean rename is safer.--commandCLI flag name is preserved; this is purely an internal namespace change. No config-file format changes, no behaviour change for any path other than the previously broken one.Checklist
Code
pytest tests/ -qand all tests pass — I rantests/hermes_cli/test_mcp_add_command_dest.pyin isolation (3/3 pass) and verified Python syntax of the four touched files. I was not able to run the full pytest suite in my dev environment; happy to address any CI failures.Documentation & Housekeeping
--commandCLI flag is unchanged)cli-config.yaml.exampleif I added/changed config keys — N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — N/A