mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-09 08:21:50 +00:00
Subcommands whose handler was a closure defined inside main() — memory, acp, tools, insights, skills, pairing, plugins, mcp, claw — have their handler promoted to a top-level function and their parser block extracted into hermes_cli/subcommands/<name>.py (build_<name>_parser, injected handler). These 9 had zero closure-over-main-locals, so promotion is a pure relocation. acp/mcp parser blocks use the shared add_accept_hooks_flag helper. main() 1798 -> 954 LOC (71% below the 3297 Phase-2 starting point); add_parser calls in main.py 89 -> 28. Deferred: sessions, computer-use, secrets handlers reference <name>_parser (for a no-subcommand print_help fallback) — left in place to avoid the _self_parser indirection; minority, low value. Behavior-neutral: all 9 subcommands' --help (incl nested subactions) byte- identical to pre-extraction (diff-verified). tests/hermes_cli/ 6519 passed / 0 failed; new test_subcommands_followup.py covers the 9 builders.
104 lines
3.8 KiB
Python
104 lines
3.8 KiB
Python
"""``hermes mcp`` subcommand parser.
|
|
|
|
Extracted from ``hermes_cli/main.py:main()`` (god-file Phase 2 follow-up).
|
|
Handler injected to avoid importing ``main``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Callable
|
|
|
|
from hermes_cli.subcommands._shared import add_accept_hooks_flag
|
|
|
|
|
|
def build_mcp_parser(subparsers, *, cmd_mcp: Callable) -> None:
|
|
"""Attach the ``mcp`` subcommand to ``subparsers``."""
|
|
mcp_parser = subparsers.add_parser(
|
|
"mcp",
|
|
help="Manage MCP servers and run Hermes as an MCP server",
|
|
description=(
|
|
"Manage MCP server connections and run Hermes as an MCP server.\n\n"
|
|
"MCP servers provide additional tools via the Model Context Protocol.\n"
|
|
"Use 'hermes mcp add' to connect to a new server, or\n"
|
|
"'hermes mcp serve' to expose Hermes conversations over MCP."
|
|
),
|
|
)
|
|
mcp_sub = mcp_parser.add_subparsers(dest="mcp_action")
|
|
|
|
mcp_serve_p = mcp_sub.add_parser(
|
|
"serve",
|
|
help="Run Hermes as an MCP server (expose conversations to other agents)",
|
|
)
|
|
mcp_serve_p.add_argument(
|
|
"-v",
|
|
"--verbose",
|
|
action="store_true",
|
|
help="Enable verbose logging on stderr",
|
|
)
|
|
add_accept_hooks_flag(mcp_serve_p)
|
|
|
|
mcp_add_p = mcp_sub.add_parser(
|
|
"add", help="Add an MCP server (discovery-first install)"
|
|
)
|
|
mcp_add_p.add_argument("name", help="Server name (used as config key)")
|
|
mcp_add_p.add_argument("--url", help="HTTP/SSE endpoint URL")
|
|
# dest="mcp_command" so this flag does not clobber the top-level
|
|
# subparser's args.command attribute, which the dispatcher reads to
|
|
# route to cmd_mcp. Without an explicit dest, argparse derives
|
|
# dest="command" from the flag name and sets it to None when the
|
|
# flag is omitted, causing `hermes mcp add ...` to fall through to
|
|
# interactive chat.
|
|
mcp_add_p.add_argument(
|
|
"--command", dest="mcp_command", help="Stdio command (e.g. npx)"
|
|
)
|
|
mcp_add_p.add_argument(
|
|
"--args", nargs="*", default=[], help="Arguments for stdio command"
|
|
)
|
|
mcp_add_p.add_argument("--auth", choices=["oauth", "header"], help="Auth method")
|
|
mcp_add_p.add_argument("--preset", help="Known MCP preset name")
|
|
mcp_add_p.add_argument(
|
|
"--env",
|
|
nargs="*",
|
|
default=[],
|
|
help="Environment variables for stdio servers (KEY=VALUE)",
|
|
)
|
|
|
|
mcp_rm_p = mcp_sub.add_parser("remove", aliases=["rm"], help="Remove an MCP server")
|
|
mcp_rm_p.add_argument("name", help="Server name to remove")
|
|
|
|
mcp_sub.add_parser("list", aliases=["ls"], help="List configured MCP servers")
|
|
|
|
mcp_test_p = mcp_sub.add_parser("test", help="Test MCP server connection")
|
|
mcp_test_p.add_argument("name", help="Server name to test")
|
|
|
|
mcp_cfg_p = mcp_sub.add_parser(
|
|
"configure", aliases=["config"], help="Toggle tool selection"
|
|
)
|
|
mcp_cfg_p.add_argument("name", help="Server name to configure")
|
|
|
|
mcp_login_p = mcp_sub.add_parser(
|
|
"login",
|
|
help="Force re-authentication for an OAuth-based MCP server",
|
|
)
|
|
mcp_login_p.add_argument("name", help="Server name to re-authenticate")
|
|
|
|
# ── Catalog (Nous-approved MCPs shipped with the repo) ─────────────────
|
|
mcp_sub.add_parser(
|
|
"picker",
|
|
help="Interactive catalog picker (also the default for `hermes mcp`)",
|
|
)
|
|
mcp_sub.add_parser(
|
|
"catalog",
|
|
help="List Nous-approved MCPs available for one-click install",
|
|
)
|
|
mcp_install_p = mcp_sub.add_parser(
|
|
"install",
|
|
help="Install a catalog MCP by name (e.g. `hermes mcp install n8n`)",
|
|
)
|
|
mcp_install_p.add_argument(
|
|
"identifier",
|
|
help="Catalog entry name (or `official/<name>`)",
|
|
)
|
|
|
|
add_accept_hooks_flag(mcp_parser)
|
|
mcp_parser.set_defaults(func=cmd_mcp)
|