# mcp

Every agent tool reads its MCP servers from a different file in a different shape. `brigade mcp`
keeps one canonical catalog and merges it into each tool's native config, so the same servers are
wired everywhere from a single source.

If you are comparing approaches before installing anything, start with the plain-English answer page:
[sync MCP servers across coding agents](/compare/sync-mcp-servers-across-coding-agents).

It is the one place Brigade writes runtime config into tool-owned files, so it stays bounded:
explicit (never automatic), dry-run by default, merges by server key (servers you added by hand
are preserved), and it never inlines secrets - env values are written as `${VAR}` references.

## The canonical catalog

`.brigade/mcp.json` is tracked and shared. Ownership of which server keys Brigade manages in each
tool file is tracked in the gitignored `.brigade/mcp/state.json`.

```jsonc
{
  "version": 1,
  "servers": {
    "github": {
      "transport": "stdio",
      "enabled": true,
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": { "ref": "GITHUB_TOKEN" } },
      "timeout": 60
    }
  }
}
```

## Supported tools

| Tool | File | Shape |
|------|------|-------|
| Claude Code | `.mcp.json` | JSON `mcpServers` |
| Cursor | `.cursor/mcp.json` | JSON `mcpServers` |
| Codex CLI | `.codex/config.toml` | TOML `[mcp_servers.*]`, surgical merge |
| VS Code | `.vscode/mcp.json` | JSON `servers` + `inputs[]` for secrets |
| OpenCode | `opencode.json` | JSON `mcp`, command-array shape |
| Antigravity | `~/.gemini/config/mcp_config.json` | JSON `mcpServers`, `serverUrl` for remote (user-scoped) |

## Commands

```bash
brigade mcp init                       # scaffold the catalog + sidecar, update .gitignore
brigade mcp add --name github \
  --command npx --args "-y @modelcontextprotocol/server-github" \
  --env GITHUB_TOKEN=ref:GITHUB_TOKEN --timeout 60
brigade mcp list
brigade mcp plan                       # preview (read-only)
brigade mcp sync                       # dry-run across every configured tool
brigade mcp sync --write               # merge into each tool's config
brigade mcp sync --write --user-scope  # also write Antigravity's user-global config
brigade mcp doctor
brigade mcp import cursor --merge      # read an existing config into the catalog
brigade operator sync-mcp --write      # validate -> sync -> summary, one receipt
```

## Merge and ownership

Brigade owns only the server keys it recorded. A server you added to a tool config yourself is
preserved untouched. A server Brigade manages but you then edited is a conflict, skipped unless you
pass `--force`. Servers removed from the catalog are deleted only with `--prune`, and only when they
still match what Brigade wrote. If the sidecar is lost (a fresh clone), a live server identical to
what Brigade would write is reconciled back to owned, so re-syncing does not spuriously conflict.

Secrets are written as references, never values: `${VAR}` for most tools, a `${input:VAR}` plus a
top-level `inputs[]` entry for VS Code. `brigade mcp import` demotes any literal-looking secret in an
existing config to a reference and never copies the value into the catalog.