Models and MCP servers are discovered from the LiteLLM gateway at sync time
(/v1/models, and the aggregate /mcp/ endpoint). Skills have no gateway side to
query: LiteLLM's /v1/skills is a passthrough to Anthropic's Skills API, which
lists skills on an Anthropic account rather than serving skill files, and
/public/skill_hub is a marketplace catalog. So the repo is the source of truth
and the tree is fetched whole, from the repo tarball.
Deploy to ~/.config/mcp-sync/skills rather than ~/.config/opencode/skills so
the atomic replace can never delete a skill the user wrote by hand; opencode
picks the tree up via skills.paths, which expands {env:HOME} — verified — so
the shared config stays identical for every user.
Same throttle and non-fatal discipline as the config sync: a fetch that yields
no skills/ leaves the last-good tree in place instead of emptying it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
91 lines
4.6 KiB
Markdown
91 lines
4.6 KiB
Markdown
# mcp-config — shared MCP gateway config for laptops
|
|
|
|
Single source of truth for the **shared** MCP servers every covert-gpt user
|
|
gets through the LiteLLM gateway (`llm.covert-gpt.com`). Users install once;
|
|
their config then refreshes automatically on each new shell.
|
|
|
|
This repo lives in Gitea at `public/dotfiles`. (It is mirrored from the
|
|
`ai-k8s-iac` repo under `mcp-config/`; edit it there or here and keep them in
|
|
sync — the laptops pull from Gitea's `main`.)
|
|
|
|
## How it works
|
|
|
|
- `opencode.gateway.json` — the shared base config: the `covert-gpt` model
|
|
provider (LiteLLM's OpenAI-compatible endpoint at
|
|
`https://llm.covert-gpt.com/v1`, models map left empty — it is filled by
|
|
discovery at sync time) and a single MCP entry for the gateway's
|
|
**aggregate** endpoint `https://llm.covert-gpt.com/mcp/` (trailing slash
|
|
required; the bare path 307-redirects, which MCP clients don't follow).
|
|
That one endpoint exposes every MCP server the user's key can access, so
|
|
new gateway servers need no client config change at all. **Identical for
|
|
every user**: the per-user key is injected via `{env:LITELLM_KEY}`, never
|
|
written into the file.
|
|
- `sync.sh` — sourced from each user's shell rc. On a new shell (throttled
|
|
~1h) it pulls the base config from Gitea, queries the gateway's
|
|
`/v1/models` with the user's key to **auto-discover models** (opencode
|
|
can't list models from a custom provider itself, so the map is
|
|
materialized client-side; if discovery fails the previous map is carried
|
|
over), deploys the repo's **skills** (see below), deploys the config to
|
|
`~/.config/opencode/opencode.gateway.json`, and exports `LITELLM_KEY`
|
|
(from `~/.config/mcp-sync/key`) plus `OPENCODE_CONFIG` (pointing at the
|
|
deployed file — opencode does NOT auto-load extra files in its config dir,
|
|
so without this export the file is ignored). Silent + non-fatal: a Gitea
|
|
hiccup never breaks the shell, last-good config stays in place.
|
|
- `../skills/` — the shared skill folders, deployed to
|
|
`~/.config/mcp-sync/skills` and wired in through `skills.paths` in the
|
|
config above. Skills are plain files, so — unlike models and MCP servers —
|
|
there is nothing on the gateway to discover and **the repo is the source of
|
|
truth**; the tree is fetched whole from the repo tarball. They deploy to
|
|
mcp-sync's own directory rather than `~/.config/opencode/skills` so the
|
|
atomic replace can never delete a skill the user wrote by hand. See
|
|
`skills/README.md`.
|
|
- `install.sh` — one-time bootstrap (curl-pipe). Fetches `sync.sh`, stores the
|
|
user's key (0600), and adds the rc hook.
|
|
|
|
opencode merges the `OPENCODE_CONFIG` file on top of the user's global
|
|
`~/.config/opencode/opencode.json` (and under any project `opencode.json`),
|
|
so the synced config coexists with each user's own settings and any
|
|
**local-only** MCP servers (e.g. a client-side `kubernetes` pointed at their
|
|
own kubeconfig). Sync never touches those.
|
|
|
|
## User setup (one time)
|
|
|
|
Each user needs a LiteLLM **virtual key** scoped to the gateway servers (see
|
|
`charts/inference/MCP-GATEWAY.md` in ai-k8s-iac for how keys are minted). Then:
|
|
|
|
```sh
|
|
curl -fsSL https://git.nic-oconnor.com/public/dotfiles/raw/branch/main/mcp-config/install.sh | sh
|
|
# (prompts for the sk-... key; or pass it: ... | LITELLM_KEY=sk-... sh)
|
|
```
|
|
|
|
Open a new terminal, run `opencode`, and the gateway tools are there.
|
|
|
|
## Adding a gateway server or model (admin)
|
|
|
|
Register it on the gateway (`charts/inference/values.yaml` →
|
|
`proxy_config.mcp_servers` for MCP servers, `model_list` for models),
|
|
deploy, smoke-test. That's it — clients auto-discover both: MCP servers
|
|
through the aggregate `/mcp/` endpoint, models via the `/v1/models` query
|
|
in `sync.sh`. Users pick them up within the sync TTL (or immediately on a
|
|
new shell). `opencode.gateway.json` here only needs editing for structural
|
|
changes (a new provider, endpoint URLs).
|
|
|
|
## Adding a skill (admin)
|
|
|
|
Skills have no gateway side. Add a folder under `skills/` and push to `main` —
|
|
see `skills/README.md`. Verify with `opencode debug skill`.
|
|
|
|
For **per-user / per-target** tools (cluster access, etc.) do NOT add them
|
|
here — those run client-side with the user's own credentials. See
|
|
`charts/inference/MCP-GATEWAY.md`.
|
|
|
|
## Notes / caveats
|
|
|
|
- **Local-server precedence**: opencode merges with later-config-wins on key
|
|
conflicts. If a user names a local server the same as a gateway one, theirs
|
|
wins. Use distinct names.
|
|
- **Key rotation**: re-run `install.sh` (or edit `~/.config/mcp-sync/key`).
|
|
- **Other clients**: this ships an opencode config. Claude Code / open-webui
|
|
would need their own equivalent file + a parallel sync entry; not done yet.
|
|
- **Throttle**: override with `MCP_SYNC_TTL=0` to force a pull every shell.
|