Hermes MCP Self-Heal
Overview
Use this when Hermes shows an MCP server as failed, disconnected, or unusable. Goal: repair the backing service first, then prove Hermes can connect again.
Default environment assumed here:
- macOS
- Hermes config at
~/.hermes/config.yaml - MCP services may be stdio, HTTP, or launchd-backed local daemons
When to Use
Trigger on asks like:
mcp failedmcp 挂了mcp 连不上修 mcpmcp 自愈openchronicle failedanything-analyzer failedbrowser-relay failedbadboy-browser failedopen-computer-use failedlaunchctlLaunchAgent后台常驻开机自启
Load companion skills when relevant:
autonomous-ai-agents/hermes-agentfor Hermes config/CLI truthsoftware-development/systmt-dbggngfor structured root-cause flowdevops/anything-analyzer-mcpfor AA/headless/MITM specificsdevops/badboy-br-aa-routingfor real-Chrome/CDP/browser routing
Core Rule
Do not patch Hermes config first. First prove whether the backing service, listener, or executable is actually down.
When the user's goal is deliberate teardown/minimization rather than repair, switch modes explicitly:
- inspect the current
mcp_servers:block and active launchd jobs first - disable unwanted servers in
~/.hermes/config.yaml - stop the backing daemons and boot out matching LaunchAgents
- verify the remaining enabled set with
hermes mcp list - only then chase residual processes that should no longer exist
Self-Heal Order
- List configured MCP servers.
- Test each failed server directly from Hermes.
- Inspect the exact backend:
- HTTP server -> listener/health endpoint
- stdio command -> binary path/help/test
- launchd-backed service -> plist, logs, launchctl state
- Repair the backend service.
- Retest from Hermes.
- If the service must survive reboot/login, add or patch a per-user LaunchAgent.
Minimal Command Set
1. Enumerate and test
hermes mcp list
hermes mcp test <name>
2. Inspect Hermes config slice
Read ~/.hermes/config.yaml around mcp_servers: and confirm:
urlorcommandargsenvheaderstimeout/connect_timeout
3. HTTP MCP checks
lsof -nP -iTCP:<port> -sTCP:LISTEN || true
curl -sS -D - -o /dev/null -H 'Accept: application/json, text/event-stream' http://127.0.0.1:<port>/mcp || true
4. stdio MCP checks
ls -l <binary>
<binary> --help
hermes mcp test <name>
5. launchd checks
launchctl print gui/$(id -u)/<label> | sed -n '1,140p'
tail -n 80 <stdout-log> 2>/dev/null || true
tail -n 80 <stderr-log> 2>/dev/null || true
6. launchd reload
launchctl bootout gui/$(id -u) "$HOME/Library/LaunchAgents/<label>.plist" >/dev/null 2>&1 || true
launchctl bootstrap gui/$(id -u) "$HOME/Library/LaunchAgents/<label>.plist"
launchctl kickstart -k gui/$(id -u)/<label>
Known Local Truths
OpenChronicle
- Hermes URL:
http://127.0.0.1:8742/mcp - Local binary:
~/.local/bin/openchronicle - Persistence plist:
~/Library/LaunchAgents/com.thrill3r.openchronicle.plist - If failed, first run:
openchronicle status
openchronicle start
hermes mcp test openchronicle
- Root cause already seen live: daemon stopped -> no listener on 8742.
anything-analyzer
- Hermes URL:
http://localhost:23816/mcp - Persistence plist:
~/Library/LaunchAgents/com.anything-analyzer.dev.plist - Must keep headless/no-UI unless user explicitly asks otherwise.
- Check 23816 listener before touching config.
browser-relay
- Backing LaunchAgent:
~/Library/LaunchAgents/com.liaotechs.browser-relay.plist - Typical listener:
127.0.0.1:18795 - Hermes side is stdio wrapper; verify both listener and
hermes mcp test browser-relay.
badboy-browser
- Hermes side uses shell wrapper + env injection.
- Transport may pass even when runtime emits harmless asyncio shutdown noise.
- Success criterion is
hermes mcp test badboy-browserdiscovering tools, not zero stderr noise.
open-computer-use
- Usually stdio only.
- Verify executable path first; then
hermes mcp test open-computer-use.
LaunchAgent Pattern
For durable local MCP services on macOS, prefer per-user LaunchAgents:
- file under
~/Library/LaunchAgents/ RunAtLoadKeepAlive- explicit
PATH - explicit logs under
~/Library/Logs/
Use listener guards if the underlying CLI exits non-zero when already running.
Observed example: openchronicle start returns exit code 1 when daemon already exists, so a guard like lsof ... || start prevents launchd restart churn.
Verification Checklist
-
hermes mcp listshows target enabled -
hermes mcp test <name>succeeds after repair - backing listener or stdio binary was directly verified
- if launchd-backed, plist path and
launchctl printwere checked - if persistent service needed, LaunchAgent exists and reload command works
- final result proven from Hermes side, not only backend side
Common Pitfalls
- Patching
~/.hermes/config.yamlbefore checking whether the backend daemon is simply down. - Missing the teardown case: if the user wants MCPs gone, leaving
enabled: trueonhermes,browser-relay,badboy-browser,anything-analyzer, oropenchronicleguarantees they can come back after reload/restart. - Treating noisy stderr as failure when
hermes mcp testalready proves tool discovery works. - Forgetting
Accept: application/json, text/event-streamon HTTP MCP probes. - Using ad-hoc shell backgrounding instead of launchd for services meant to persist.
- For AA tasks, accidentally opening UI/Electron despite user preference for hidden/headless mode.
- Declaring success because a port listens, without retesting from Hermes.
- Killing child MCP processes without checking the parent chain; a surviving parent
hermes mcp servecan recursively respawnbrowser-relay-mcp-line,hermes_context_server.py, and morehermes mcp servechildren.