Skip to main content
Glama

ChatBridge for Hermes

Hermes-native local MCP workbench for approved local files, patches, commands, durable sessions, images, artifacts, and opt-in worker delegation. It complements ARGOS, which governs the Hermes Codex OAuth credential pool.

Lineage: core executor patterns from chat-on-steroids (approved roots, capability switches, read-only kill switch, bounded results, loopback-only MCP endpoint with per-surface secret paths), reimplemented Hermes-native in Python. No Electron fork, no browser scraping, no extension port.

Why a separate plugin (not part of ARGOS)

  • Different trust boundary: ARGOS promises OAuth tokens only ever go to the official chatgpt.com usage endpoint and never scrapes a browser. ChatBridge must never touch ARGOS auth state.

  • Different lifecycle: a loopback MCP server + tunnel + approved-folder permissions, vs quota governance.

  • Deliberately NOT ported: the Chrome-extension DOM observation/attribution, Compact & Resume browser orchestration, worker-chat browser automation, Desktop computer-control, and tunnel-client bundling. Those would violate the no-scraping non-goal and need a full app, not a Hermes plugin.

Related MCP server: chatgpt-web-agent

Hermes-first operation

ChatBridge is installed, configured, and run by Hermes. Its MCP endpoint is an optional interoperability surface for a client you explicitly choose; it is not a ChatGPT or Codex desktop-app extension, does not automate a browser, and does not consume web-chat quota.

Install

Manual copy — hermes plugins install <github> deliberately refuses this plugin: its security scanner returns a dangerous verdict (subprocess execution is the plugin's purpose; 10 findings, all true positives on exec.py/patch.py). You are installing your own code on your own machine, so copy it yourself:

rm -rf "$HERMES_HOME/plugins/chatbridge"
cp -R /path/to/hermes-plugin-chatbridge "$HERMES_HOME/plugins/chatbridge"
hermes plugins enable chatbridge
hermes chatbridge status

Approve at least one folder in $HERMES_HOME/chatbridge.yaml:

approved_roots: /me/projects/app
read_only: true
allow_exec: false
allow_patch: false

Zero approved roots = the bridge answers but every read fails closed.

Use ChatBridge from Hermes

ChatBridge is an MCP server that Hermes can consume itself. This is the Hermes-native path: it does not require ChatGPT web, a browser extension, or a ChatGPT/Codex desktop-app modification.

  1. Configure the capability boundary in $HERMES_HOME/chatbridge.yaml. A project-scoped example:

    approved_roots: C:/Users/me/projects/my-app
    read_only: false
    allow_patch: true
    allow_exec: true
    allow_save: true
    exec_allowlist: git status; npm test; python -m pytest
    agents_enabled: true
    agents_max_workers: 2
    port: 18789

    An explicitly user-authorized full-local-workspace configuration is also supported, but grants the MCP client the same filesystem access as your Windows user:

    approved_roots: C:/
    read_only: false
    allow_patch: true
    allow_exec: true
    allow_save: true
    exec_allowlist: cmd /c; powershell -Command; python; py; git; node; npm; uv; hermes
    agents_enabled: true
    agents_max_workers: 2
    port: 18789
  2. Start the loopback server (keep this process running):

    hermes chatbridge serve --port 18789

    Set BRIDGE_HOME to the active Hermes home (on this Windows install it is %LOCALAPPDATA%\\hermes), then register the local endpoint without printing its secret path:

    BRIDGE_HOME="${HERMES_HOME:-$LOCALAPPDATA/hermes}"
    TOKEN="$(tr -d '\r\n' < "$BRIDGE_HOME/chatbridge.token")"
    hermes mcp add chatbridge --url "http://127.0.0.1:18789/${TOKEN}/mcp"

    At the prompts, choose No for separate authentication (the secret path already authenticates this loopback endpoint), then enable the desired tools. Check registration with hermes mcp list and service state with hermes chatbridge status.

  3. Start a new Hermes session. MCP tools are discovered at session startup and are named mcp_chatbridge_read, mcp_chatbridge_find, mcp_chatbridge_view_image, mcp_chatbridge_apply_patch, mcp_chatbridge_exec_command, mcp_chatbridge_write_stdin, mcp_chatbridge_download_artifact, and mcp_chatbridge_agents when their configuration gates are enabled. An already-running Hermes chat keeps its existing tool schema to preserve prompt caching.

  4. Use ordinary requests in the new chat, for example: “Find all Python tests under C:/Users/me/projects/my-app and run the relevant test command.” The agent receives the MCP tools alongside Hermes's normal tools.

The local server is intentionally not a Windows service. After a reboot, start hermes chatbridge serve --port 18789 again before beginning a Hermes session, or use your own supervised service mechanism. Never publish the local endpoint or its token path through a public tunnel unless you intentionally configure the tunnel guard in the next section.

Optional remote MCP client (tunnel)

The bridge binds 127.0.0.1 only. An approved remote MCP client can reach it through a tunnel you run:

hermes chatbridge serve --port 18789
cloudflared tunnel --url http://127.0.0.1:18789

Take the https://<name>.trycloudflare.com URL cloudflared prints, put it in chatbridge.yaml as tunnel_host: <name>.trycloudflare.com, restart serve, and register this connector URL only with the MCP client you intend to authorize:

https://<name>.trycloudflare.com/<secret-from-~/.hermes/chatbridge.token>/mcp

Verified end to end: health, initialize, tools/list, tools/call read all 200 through the public URL; wrong token → 404, other Host → 421, non-loopback Origin → 403. Three things the tunnel run taught us (all fixed and regression-tested):

  • The loopback guard checks the TCP peer, not the Host header (tunnels forward the public hostname as Host).

  • serve passes proxy_headers=False: uvicorn ≥ 0.41 trusts X-Forwarded-For from loopback peers by default, which would let the tunnel's XFF masquerade as the peer.

  • The MCP SDK's DNS-rebinding check stays on; tunnel_host allowlists the public hostname explicitly. Quick-tunnel hostnames are random per run — for daily use prefer a named tunnel (stable hostname) and update tunnel_host accordingly. Treat the full connector URL as a password.

Workers (opt-in multi-agent)

CoS's flagship is prime/worker chats; its workers are browser tabs driven by the extension — deliberately not ported. The Hermes-native equivalent: a worker is a background hermes -z one-shot run whose report the prime collects with the agents tool (spawn | message | status | finish).

agents_enabled: true
agents_max_workers: 2   # concurrency cap, hard max 8
worker_provider: ""     # empty = your configured defaults
worker_model: ""

Honest differences from CoS to know before enabling:

  • Workers spend Hermes-side model quota (Codex/API). Each run writes --usage-file to $HERMES_HOME/workers/<id>.usage.json so cost is auditable.

  • Workers are one-shot runs, not persistent chats. message on a finished worker revives it: a follow-up run seeded with (task, prior report, new instruction) under the same worker id. Running workers can't take injected input — message returns current output instead.

  • Workers never receive the connector URL and run with HERMES_CHATBRIDGE_WORKER=1; the bridge refuses spawn under that marker, so workers cannot spawn workers. Worker cwd is locked to the first approved root.

  • Default OFF (unlike CoS's on-by-default): enabling runs agent processes as your user. Full MCP path verified live (list → spawn → status → message/revive → finish → transcript, stub runner); only a real model run's stdout is pending a quota reset.

Write tools (opt-in)

Disabled unless all three hold in chatbridge.yaml: read_only: false, the matching allow_patch / allow_exec: true, and at least one approved root. Handlers re-read live config on every call, so re-enabling read-only takes effect without a restart:

read_only: false
allow_patch: true
allow_exec: true
exec_allowlist: npm test; git status
  • apply_patch takes a unified diff, preflights every file (context must match, targets inside approved roots, no binary/non-UTF-8, new files need existing parents), then applies atomically — any failure writes nothing. Deletes verify hunk context too.

  • exec_command runs one command from exec_allowlist (exact or prefix-plus-space match) with its cwd in the first approved root, 5-minute cap, 64 KiB output cap. POSIX runs argv without a shell; Windows runs the allowlisted string via cmd (the allowlist entry itself is the control, so keep entries exact).

  • Commands are not folder-sandboxed once started — same-user privileges, same as CoS. Keep the allowlist to build/test/lint commands. Long commands return a session_id; write_stdin polls it, answers stdin prompts, or kills it (kill: true); final collection retires the session. Note: piped stdout is block-buffered — prefer unbuffered child output (python -u, stdbuf -o0) for live progress.

File saving and images (read surface)

  • view_image is always listed (read-gated): PNG/JPEG/GIF/WebP up to 10 MiB, delivered to the model as a vision block rather than text.

  • download_artifact is opt-in (allow_save: true + read_only: false): saves only https://files.oaiusercontent.com/… (redirects re-checked), 20 MiB cap, destination parents must exist, existing files never overwritten, signed URL query material never logged.

Optional MCP-client connection

  1. hermes chatbridge serve --port 0 (loopback only; prints the port).

  2. Expose it via your own HTTPS tunnel (Cloudflare quick tunnel or equivalent) — the full public URL including the random tunnel path plus /<token>/mcp is the connector URL (the token segment is the credential; treat the URL as a password).

  3. In the approved MCP client, add the connector URL, review its actions, and enable it.

  4. Start with one read-only task; confirm the exact paths in the reply before widening anything.

Safety

  • Real MCP protocol (Streamable HTTP, stateless, JSON responses) — verified with a raw-protocol handshake test, not just the SDK client.

  • Binds 127.0.0.1 only; Host must be loopback; a present Origin must be loopback.

  • Secret path segment; wrong token = 404 (no oracle).

  • Request bodies capped at 1 MiB; file payloads 256 KiB each / 512 KiB aggregate.

  • Write tools absent from discovery unless explicitly enabled; handlers re-check live config anyway.

  • No raw tokens in logs/CLI output.

Tests

uv run --with pytest python -m pytest -q tests
hermes plugins doctor "$HERMES_HOME/plugins/chatbridge" --ci

License

MIT.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers