CLI tool to share MCP configuration between coding agents.
Synchronizes Model Context Protocol server definitions across VSCode, GitHub Copilot CLI, Claude Code, OpenAI Codex, Google Gemini CLI, Google Antigravity, and OpenCode.
# Install as a global CLI tool from GitHub
uv tool install git+https://github.com/eggboy/mcpshare.git
# Or install from a local clone of the repo
git clone https://github.com/eggboy/mcpshare.git
cd mcpshare
uv tool install .
# Then run from anywhere
mcpshare init
mcpshare pull
mcpshare sync
mcpshare status
# Upgrade to the latest version
uv tool upgrade mcpshareThe config file lives at ~/.config/mcpshare/config.yaml:
source: /path/to/master # directory for the canonical mcp.json
init-source: # tools (in priority order) that `mcpshare pull` reads from
- vscode
- copilot
mode: merge
targets:
claude:
path: ~/.claude
vscode:
path: ~/Library/Application Support/Code/User # macOS; see docs for other OS
copilot:
path: ~/.copilot
codex:
path: ~/.codex
gemini:
path: ~/.gemini
antigravity:
path: ~/.gemini/config
opencode:
path: ~/.config/opencodeinit-source controls which tools mcpshare pull collects server entries
from (and their order during conflict resolution). Any supported tool name
(vscode, copilot, claude, codex, gemini, antigravity, opencode)
can be listed. When omitted from an older config.yaml, it defaults to
[vscode, copilot].
mcpshare init– creates the config file and master directory.mcpshare pull– pulls MCP server entries from the tools listed ininit-sourceand merges them into the mastermcp.json(collect only, does not write back to targets).mcpshare sync– distributes the mastermcp.jsonto all configuredtargets, converting to each tool's native format.mcpshare status– shows the master servers,init-sourcelist, and whether each target config file exists.
Typical workflow: mcpshare pull → mcpshare sync.
Disable state is tracked exclusively in mcp.disabled.yaml, colocated with
the master mcp.json in your source directory. The master itself never
carries a per-entry disabled flag — if you add one by hand, mcpshare
strips it on the next pull / sync. The same applies to any IDE-native
disable flag (Codex enabled = false, etc.) found in target files on read:
it is stripped, and disable state is re-derived from mcp.disabled.yaml
on the next sync.
This means the disabled list survives even when you delete and regenerate
mcp.json, and there is exactly one place to look — mcp.disabled.yaml.
mcpshare disable --servers <server> # disable in all IDEs
mcpshare disable --servers <server> --ide claude # disable in one IDE only
mcpshare enable --servers <server> # re-enable in every IDE
mcpshare enable --servers <server> --ide claude # re-enable in one IDE only
mcpshare status # shows disabled listsmcp.disabled.yaml format (top-level flat mapping, colocated with mcp.json):
"*": # entries here are disabled in every configured IDE
- workiq-mcp
claude: # entries here are disabled only for Claude Code
- filesystem
codex:
- filesystemIf you previously used
~/.config/mcpshare/disabled.yaml, mcpshare moves it next to your mastermcp.jsonautomatically on the first load.
sync writes every master server to every configured IDE. For disabled
servers, mcpshare uses each IDE's native disable mechanism rather than
omitting the entry (so the server stays visible and can be re-enabled in the
tool's UI without round-tripping through mcpshare enable). Claude Code is
the exception: it has no global disable list, so disabled servers are left
out of its config.
| IDE | Native disable mechanism | What sync writes |
|---|---|---|
| Codex | enabled = false in the server's TOML block |
Server written with enabled = false |
| Claude Code | None global (/mcp toggles are stored per project in ~/.claude.json) |
Server omitted from mcpServers in ~/.claude.json |
| Copilot CLI | disabledMcpServers: [...] in ~/.copilot/settings.json |
Server in mcp-config.json plus name in settings.json array |
| Gemini CLI | mcp.excluded: [...] in ~/.gemini/settings.json (security-grade blocklist) |
Server in mcpServers plus name in mcp.excluded (same file) |
| Antigravity | "disabled": true per entry in ~/.gemini/config/mcp_config.json |
Server written with "disabled": true |
| OpenCode | "enabled": false per entry in opencode.json |
Server written with "enabled": false |
| VSCode | None (UI-only per profile) | Server is always written enabled. disable --ide vscode is recorded but warns and is a no-op on sync. |
Source of truth: mcpshare-owns. On each sync, mcpshare replaces
the disabledMcpServers array in Copilot settings.json with its own
view (other settings.json keys are preserved). If you previously ran
/mcp disable foo natively inside Copilot, the next sync will
re-enable foo and log a warning telling you the exact mcpshare disable
command to run if you want to keep it disabled.
The same overwrite-with-mcpshare's-view rule applies to Gemini's
mcp.excluded array and to Codex/OpenCode's per-entry enabled = false —
all other keys in the target files are preserved.
Every target file is updated atomically in place (temp-file + fsync +
rename, writing through symlinks and preserving file permissions). Only the
MCP servers section is replaced, so removed servers cannot linger while
unrelated keys and sections — including VSCode's top-level inputs array,
Claude's state in ~/.claude.json, Gemini/OpenCode settings, and non-MCP
TOML sections in Codex — are preserved. For Copilot, the
disabledMcpServers array in settings.json is also updated atomically in
place while preserving every other key. If an existing target file contains
malformed JSON or TOML, it is left untouched and skipped rather than
clobbered.
Claude Code reads user-scope MCP servers only from the top-level
mcpServers object in ~/.claude.json (the same place
claude mcp add --scope user writes). The configured target stays
~/.claude, Claude's config dir; mcpshare resolves it the way Claude does,
so ~/.claude maps to ~/.claude.json and any other directory (as with
CLAUDE_CONFIG_DIR) maps to <dir>/.claude.json.
- Only
mcpServersis replaced, atomically; the rest of~/.claude.jsonis Claude's own state and is left alone. - Each entry gets
"type": "stdio"or"type": "http". Claude rejects a remote server without a type. - Codex-only
toolsallow-lists are not written. - Restart running Claude Code sessions after
syncto pick up the change.
Versions before 0.17.1 wrote ~/.claude/mcp_servers.json and a
disabledMcpServers array in ~/.claude/settings.json. Claude reads
neither, so sync now deletes that file and removes that one key (other
settings.json keys are kept).
The Antigravity app, IDE, and CLI (agy) share one global file,
~/.gemini/config/mcp_config.json, so the target path is
~/.gemini/config. Older locations (~/.gemini/antigravity/ and
~/.gemini/antigravity-cli/) are not written.
- Remote servers are written with
serverUrl, the only key Antigravity accepts (urlfails only when a tool is first called). - No
typefield is written; Codex-onlytoolsallow-lists are dropped. - Disabled servers stay listed with
"disabled": true, so they can be toggled from Antigravity's UI. - After
sync, click Refresh under Installed MCP Servers in the app, or reload from/mcpinagy.
When mcpshare pull finds the same server name across init-source tools
with different settings, it prompts you to pick one. Equivalent configs
are merged silently:
- Per-entry
disabled/enabledflags are stripped before comparison (disable state is owned bymcp.disabled.yaml). - VSCode
${env:VAR}placeholders match their resolved environment values and are preserved so expanded secrets are not written back intomcp.json. - Keys a tool's schema cannot store (such as Codex
toolsallow-lists in Claude/Antigravity/OpenCode) do not count as conflicts and are preserved.
Pass --non-interactive (or run without a TTY) to fall back to last-write-wins
(in init-source order) with a warning.
| Tool | File | Top-level key | Notes |
|---|---|---|---|
| Claude Code | ~/.claude.json |
mcpServers |
Shared with Claude's state; only mcpServers is replaced. Adds "type". Disabled servers omitted |
| VSCode | mcp.json |
servers |
Preserves top-level inputs and other keys. Adds "type": "stdio"|"http". No native disable |
| Copilot CLI | mcp-config.json |
mcpServers |
Preserves non-MCP keys. Adds "type": "stdio"|"http". Disable via settings.json |
| Codex | config.toml |
[mcp_servers.*] |
TOML; preserves non-MCP sections. Native enabled = false |
| Gemini CLI | settings.json |
mcpServers |
Preserves non-MCP settings. Disable via mcp.excluded (same file) |
| Antigravity | ~/.gemini/config/mcp_config.json |
mcpServers |
url written as serverUrl; no type; Codex tools not written. Native "disabled": true per entry |
| OpenCode | opencode.json |
mcp |
Uses command array, environment. Native "enabled": false per entry |
pip install -e .
pip install pytest
python -m pytest tests/ -v