Skip to content

Deploying the registry

Almost everything the registry writes lives in committed files, so most of the rollout is “merge the catalog and let existing entry points run sync”. No per-developer install campaign: choose the channels that match your org and layer them.

ChannelCoversDev-machine footprint
Repo + CI drift gateProject configs for every dev who pullsnone
Claude Code SessionStart hookSelf-healing configs each sessionnone (npx on demand)
OpenCode autosyncOpenCode users at startupnone (plugin already loads)
MDM / login scriptUser-level configs (Claude Desktop, ~/.claude.json)one scripted command

registry sync --check exits 1 when committed configs drift from the catalog — pair it with the scan gate:

.github/workflows/mcp-registry.yml
name: MCP registry drift
on:
pull_request:
paths:
- '.ringzero/**'
- '**/.mcp.json'
- '**/.vscode/mcp.json'
- '**/.cursor/mcp.json'
- '**/opencode.json'
- '**/opencode.jsonc'
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npx @ringzero/mcp-scan@latest registry validate
- run: npx @ringzero/mcp-scan@latest registry sync --check

When the catalog changes, run registry sync locally (or let a bot do it) and commit the updated configs + lock file in the same PR.

Commit the hook once and every session self-heals its MCP config:

.claude/settings.json
{
"hooks": {
"SessionStart": [
{
"hooks": [
{ "type": "command", "command": "npx -y @ringzero/mcp-scan registry sync --quiet" }
]
}
]
}
}

ringzero-mcp init --print-hooks claude-code prints this together with the usage-auditing hooks. --quiet prints nothing when clean and a single line when it applied changes, so session startup stays clean. Repos without a catalog are a silent no-op.

If your org already ships @ringzero/opencode-mcp-guard, the registry deploys itself: the plugin applies a project-scope sync at startup whenever a catalog is present.

  • Changes to opencode.json take effect on the next OpenCode restart — the plugin says so on stderr when it applied changes.
  • Failures never block the session (fail-open), conflicts are reported.
  • Opt out per environment with RINGZERO_MCP_REGISTRY_AUTOSYNC=0.

User-level configs (Claude Desktop, ~/.claude.json, ~/.cursor/mcp.json, user OpenCode) are the one surface a repo can’t carry. Ship one command through whatever your org already runs on login:

Terminal window
# Scheduled task or Intune remediation script — run at logon
$env:RINGZERO_MCP_REGISTRY = '\\fileserver\ringzero\mcp-registry.json'
npx -y @ringzero/mcp-scan registry sync --machine --quiet
  1. Seed the catalogringzero-mcp registry add the servers your org already blesses (or registry pull once the platform catalog ships — the pulled catalog also carries your org’s control level, so runtime enforcement rides the same file). Merge it with "harnesses" limited to one harness if you want a canary.

  2. Turn on the CI drift gate so the catalog and configs can’t diverge.

  3. Commit the SessionStart hook / plugin entry — devs start receiving servers as they pull and restart sessions.

  4. Widen harnesses to "all", then add the MDM machine-scope job for Claude Desktop coverage.

  5. Retire a server by flipping "enabled": false (managed removal everywhere on next sync) before deleting the entry.

  • “Registry drift” in CI but not locally — someone edited a managed entry by hand; registry status names the exact file and server, sync restores it.
  • A dev’s own server disappeared? It can’t — sync only ever removes entries recorded in the lock file. If a server vanished, it was a managed entry whose catalog row was removed or disabled.
  • Conflict reports — a local entry shadows a catalog name; rename or delete one side.
  • Emergency stopRINGZERO_MCP_REGISTRY_AUTOSYNC=0 (OpenCode), remove the SessionStart hook line, or flip entries to "enabled": false and let sync clean up.