hermes - 💡(How to fix) Fix cli.py invoked directly bypasses discover_mcp_tools(); banner shows "(stdio) — failed" for unconnected servers [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When cli.py is invoked directly (e.g. python /path/to/cli.py -q "..." or python -m cli), MCP servers configured in ~/.hermes/config.yaml under mcp_servers: never get connected. The startup banner displays each server as (stdio) — failed, which is misleading — the spawn never happened, the registry is just empty.

Going through the hermes wrapper (hermes_cli/main.py) works correctly because that path explicitly calls discover_mcp_tools() at line 10228. cli.py itself only references discover_mcp_tools() inside the config-watcher reload path (line 7428), with no startup invocation.

Other entry points handle this correctly:

  • gateway/run.py:12028await _loop.run_in_executor(None, discover_mcp_tools)
  • tui_gateway/entry.py:115discover_mcp_tools()
  • acp_adapter/entry.py:122discover_mcp_tools()
  • tui_gateway/server.py:3331discover_mcp_tools()
  • hermes_cli/main.py:10229discover_mcp_tools()

cli.py (when invoked directly) is the only top-level entry that doesn't.

Root Cause

Going through the hermes wrapper (hermes_cli/main.py) works correctly because that path explicitly calls discover_mcp_tools() at line 10228. cli.py itself only references discover_mcp_tools() inside the config-watcher reload path (line 7428), with no startup invocation.

Fix Action

Fixed

Code Example

# config.yaml has a working MCP server, e.g.:
#   mcp_servers:
#     obsidian:
#       command: /path/to/node
#       args: [/path/to/mcpvault/server.js, /path/to/vault]

# Direct invocation — MCP fails:
python /home/$USER/.hermes/hermes-agent/cli.py -q "use mcp_obsidian_get_vault_stats"
# Banner shows: obsidian (stdio) — failed
# Agent reports tool not available

# Wrapper invocation — works:
hermes chat -q "use mcp_obsidian_get_vault_stats"
# Banner shows server connected, tool returns data
RAW_BUFFERClick to expand / collapse

Summary

When cli.py is invoked directly (e.g. python /path/to/cli.py -q "..." or python -m cli), MCP servers configured in ~/.hermes/config.yaml under mcp_servers: never get connected. The startup banner displays each server as (stdio) — failed, which is misleading — the spawn never happened, the registry is just empty.

Going through the hermes wrapper (hermes_cli/main.py) works correctly because that path explicitly calls discover_mcp_tools() at line 10228. cli.py itself only references discover_mcp_tools() inside the config-watcher reload path (line 7428), with no startup invocation.

Other entry points handle this correctly:

  • gateway/run.py:12028await _loop.run_in_executor(None, discover_mcp_tools)
  • tui_gateway/entry.py:115discover_mcp_tools()
  • acp_adapter/entry.py:122discover_mcp_tools()
  • tui_gateway/server.py:3331discover_mcp_tools()
  • hermes_cli/main.py:10229discover_mcp_tools()

cli.py (when invoked directly) is the only top-level entry that doesn't.

Reproduction

# config.yaml has a working MCP server, e.g.:
#   mcp_servers:
#     obsidian:
#       command: /path/to/node
#       args: [/path/to/mcpvault/server.js, /path/to/vault]

# Direct invocation — MCP fails:
python /home/$USER/.hermes/hermes-agent/cli.py -q "use mcp_obsidian_get_vault_stats"
# Banner shows: obsidian (stdio) — failed
# Agent reports tool not available

# Wrapper invocation — works:
hermes chat -q "use mcp_obsidian_get_vault_stats"
# Banner shows server connected, tool returns data

The MCP server itself is healthy — driving it directly through the MCP SDK's stdio_client succeeds and list_tools() returns the expected tools.

Suggested fixes (either alone is sufficient)

  1. Parity fix: Have cli.py main() call discover_mcp_tools() (or _ensure_mcp_loop() followed by discovery) at startup, the same way hermes_cli/main.py does. This is the most user-friendly fix — direct cli.py invocations would behave identically to wrapper invocations.

  2. Honest banner status: If keeping the current behavior, change the banner string from (stdio) — failed to (stdio) — not initialized (or similar) when _servers[name] has never been started, so users aren't sent down a debugging rabbit hole investigating a spawn that never happened. failed should be reserved for cases where startup was attempted and threw.

Environment

  • hermes-agent commit: a830f25f716190168dd7db6819c0b48848049002
  • Python 3.11.15
  • Linux (Debian) running on a TrueNAS VM
  • Invocation context: SSH non-interactive shell calling python venv/bin/python cli.py directly

Why I hit this

I was testing a newly-registered MCP server (MCPVault for Obsidian) and saw it as "failed" in the CLI banner while the same server worked correctly via the messaging gateway (Discord). Spent ~30 minutes confirming the server itself was healthy via direct SDK calls before realizing the CLI just hadn't discovered it. Switching to hermes chat -q "..." resolved it instantly.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix cli.py invoked directly bypasses discover_mcp_tools(); banner shows "(stdio) — failed" for unconnected servers [1 pull requests]