mcp-config: render the SAME MCP servers into Hermes' config

Hermes had no MCP servers at all -- no mcp_servers: key -- so "use the gitea
MCP" had nothing to call. The model said so ("there's no Gitea-specific skill"),
which was true, and then looped reaching for the browser as the only way in.

The obvious fix -- paste a gitea block into ~/.hermes/config.yaml -- is the
wrong one: it makes a SECOND definition of a server this repo already defines
once, free to drift (one pinned to gitea-mcp@0.0.10, the other to whatever got
typed). README already calls this out: "all MCP servers are defined here", and
listed other clients as "not done yet". So render, don't duplicate: sync.sh
already translates LiteLLM's /model/info into opencode's schema; this is the
same move into Hermes' schema, from opencode.gateway.json's mcp block. Add a
server once, both clients get it within the same TTL.

Not a shared server PROCESS, which is what "use the same one" would imply: MCP
stdio servers are subprocesses spawned per client over stdin/stdout and dying
with it. Each client running its own `npx -y <pkg>` is the design -- same
package, same pinned version, same per-user credential, same identity. Sharing
one process would need a persistent daemon plus a stdio->HTTP bridge, for
nothing. And it stays client-side: the gateway hosts no MCP servers on purpose
(values.yaml:892; user-scoped APIs, no shared tokens), and gitea-mcp hard-exits
without a token so LiteLLM's headerless listing never registers it anyway.

Translation notes: Hermes' `command` must be a STRING (a list stringifies to
"['npx', '-y']" and fails at exec), so opencode's argv list splits into
command + args. `{env:VAR}` becomes `${VAR}` -- both by-name, so no secret is
written to either file. Hermes gives an MCP child only a filtered baseline env,
so every secret must be listed in env:, which the rendered block does. Nothing
is added to platform_toolsets: MCP servers auto-enable by name, and listing some
would turn it into an allowlist.

Rendered names are recorded in ~/.config/mcp-sync/hermes-managed.json so a
server dropped upstream is dropped from Hermes, while servers the user added by
hand -- never in the manifest -- are left alone. Only writes when the result
changes, skips silently when Hermes isn't installed, warns when PyYAML is
missing (an absent MCP block is invisible rather than obviously broken).

Verified via Hermes' own discovery: 72 tools register -- 30 gitea (incl.
issue__list) and 42 proxmox -- with ${GITEA_KEY} / ${PROXMOX_MCP_*} resolving
and no secret in config.yaml.

Also fixes a stale README claim that MCP tools come from the gateway's /mcp
endpoint; they never do, and values.yaml:892 says why.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-16 11:04:57 -04:00
co-authored by Claude Opus 4.8
parent e42807c054
commit 11f88ad3a9
3 changed files with 199 additions and 7 deletions
+3 -2
View File
@@ -54,8 +54,9 @@ Already have a clone? Just run it directly:
is already present. `zsh/zshrc` puts `~/.local/bin` on `PATH`.
opencode is configured by `mcp-config/`: it points at the covert-gpt
LiteLLM gateway (`https://llm.covert-gpt.com/v1` for models,
`https://llm.covert-gpt.com/mcp` for MCP tools). Run
LiteLLM gateway (`https://llm.covert-gpt.com/v1`) for models. MCP tools do
NOT come from the gateway — it hosts no MCP servers, deliberately; they run
client-side under your own credentials (see `mcp-config/README.md`). Run
`mcp-config/install.sh` once to store your LiteLLM key and enable
config sync — without it, opencode installs but can't reach the
gateway.