Bidirectional sync of MCP servers between Claude Code (~/.claude.json) and Cursor (~/.cursor/mcp.json) on macOS, via a launchd watcher.
claude-cursor-mcp-sync
Keep Claude Code and Cursor in sync on macOS. Bidirectional, automatic, idempotent. Two things are kept aligned:
- MCP servers —
~/.claude.json↔~/.cursor/mcp.json(mcpServerssection) - Global rules —
~/.claude/CLAUDE.md↔~/.cursor/rules/CLAUDE.mdc
Edit either side — the change appears on the other within ~5 seconds.
The installer also drops opinionated Cursor-only configs that have no Claude Code analogue (currently: keybindings.json with Cmd+K rebound to clear the integrated terminal). See Cursor-only configs.
How it works
- A small Python script compares each pair of files.
- If a pair already matches, it skips that pair (this is what prevents write loops).
- Otherwise, whichever file has the newer
mtimewins and is copied to the other. - A
launchdagent watches all four files and runs the script on every change, throttled to once every 5 seconds.
Only the mcpServers key is touched in ~/.claude.json; all other Claude state is preserved. The rules file is copied verbatim.
Note: Cursor does not officially support a global rules file. This tool mirrors
CLAUDE.mdinto~/.cursor/rules/CLAUDE.mdc, which Cursor picks up as a user-scoped rules file via therules/directory convention.
Requirements
- macOS (uses
launchd) python3available at/usr/bin/python3(preinstalled on modern macOS)
Install
git clone <this-repo> claude-cursor-mcp-sync
cd claude-cursor-mcp-sync
./install.sh
The installer:
- Copies
mcp-syncto~/.local/bin/mcp-syncand makes it executable. - Renders
com.user.mcp-sync.plistinto~/Library/LaunchAgents/with your$HOMEsubstituted. - Loads the launchd agent (and runs it once on load, performing the initial sync).
Uninstall
./uninstall.sh
Removes the agent and the script. Leaves both config files untouched.
Useful commands
# Force a sync right now
~/.local/bin/mcp-sync
# Watch the log
tail -f ~/Library/Logs/mcp-sync.log
# Check the agent is loaded
launchctl list | grep mcp-sync
# Stop temporarily
launchctl unload ~/Library/LaunchAgents/com.user.mcp-sync.plist
# Start again
launchctl load -w ~/Library/LaunchAgents/com.user.mcp-sync.plist
Cursor-only configs
Some preferences only make sense on the Cursor side (no Claude Code counterpart). They live under configs/ and are applied one-way by install.sh — not by the runtime sync.
| File | Installed to | Purpose |
| --- | --- | --- |
| configs/cursor-keybindings.json | ~/Library/Application Support/Cursor/User/keybindings.json | Cmd+K in the integrated terminal clears the terminal instead of opening Cursor's AI inline edit. Outside the terminal Cmd+K keeps its default behavior. |
If the destination file already exists and differs from the repo version, the installer backs it up to <file>.bak.<timestamp> before overwriting. Uninstall leaves the file in place.
Caveats
- Last-write-wins. If you edit both files within the same ~5s throttle window, the most recently saved one overwrites the other. There is no merge.
- Global scope only. Per-project MCP servers (Claude's
.mcp.jsonin a repo, or Cursor's project-local.cursor/mcp.json) and per-project rules (.cursor/rules/*.mdc, project-levelCLAUDE.md) are not synced — only the global user-level configs. - HTTP MCP servers. Both clients support
type: "http", but some servers behave differently between Claude and Cursor (auth headers, transport quirks). Verify per server. - Direction is opinionated by
mtime. Claude Code rewrites~/.claude.jsonfrequently for unrelated state, which bumps its mtime constantly. That is fine because the sync exits early whenmcpServersalready match; only actualmcpServersdivergence triggers a write.
Files
.
├── README.md
├── install.sh # idempotent installer
├── uninstall.sh # removes script + agent
├── mcp-sync # the Python sync script
├── com.user.mcp-sync.plist.template # launchd plist with __HOME__ placeholder
└── configs/
└── cursor-keybindings.json # Cursor-only keybindings applied at install
License
MIT