I pasted the same MCP server into 4 config files. Then I wrote a tool to clean up the mess.
If you use Claude Desktop, Cursor, VS Code, and Codex side by side, your MCP setup is probably a mess. Mine was. The same filesystem server lived in three different config files. One copy had different args than the others. And one entry pointed at a command I'd uninstalled months ago — a dead link sitting there silently.
Editing four JSON/TOML files by hand to fix this is nobody's idea of fun. So I built mcp-config-dedupe: a stdlib-only Python CLI that scans every client config, reports duplicates, drift, and dead links, and dedupes them in one command.
- GitHub: https://github.com/hahahahahahahahah6/mcp-config-dedupe
- PyPI:
pip install mcp-config-dedupe(https://pypi.org/project/mcp-config-dedupe/)
What it does
# Scan all clients (read-only) and print findings
mcp-dedupe scan
# Preview what dedupe would change (default; writes nothing)
mcp-dedupe dedupe
# Actually dedupe — backups first, explicit confirmation required
mcp-dedupe dedupe --apply --yes
A typical scan looks like this:
MCP config scan
============================================================
- claude-desktop 3 server(s)
- cursor 2 server(s)
- vscode 1 server(s)
- codex 2 server(s)
------------------------------------------------------------
[DUPLICATE] filesystem (claude-desktop, cursor, codex): identical config in multiple clients; safe to dedupe
[DRIFT] brave-search (claude-desktop, vscode): same name but different config across clients
[DEAD-LINK] old-tool (cursor): command not found on PATH: old-tool-bin
Three kinds of rot, three responses:
-
DUPLICATE — same name, byte-identical config in multiple clients. Dedupe keeps one canonical copy (priority: Claude Desktop → Cursor → VS Code → Codex, overridable with
--prefer) and removes the rest. -
DRIFT — same name, different config. This is the dangerous one: which copy is "right" is a judgment call, so the tool only reports it by default. Pass
--include-drift(plus--prefer <client>to pick the winner) to resolve it. -
DEAD-LINK — the configured
commandisn't onPATHor the path doesn't exist, orcwdis gone. Reported always; removed only with--prune-dead.
The safety model
Config-writing tools earn trust by being boring about safety:
-
scanand defaultdedupe(dry-run) never write anything. -
--applyrefuses to run without--yes. - Every touched file is backed up to
~/.mcp-dedupe/backups/<timestamp>/before rewriting. - Only configs that parsed cleanly are ever rewritten; malformed files are reported as
UNREADABLEand left alone. - Drifted duplicates are never auto-merged.
How it's different
- vs config security auditors (e.g. mcp-audit-tool): auditing tells you a config looks risky. This tool takes action — it removes the duplicate and dead entries across clients in one command.
- vs editing JSON by hand: one scan gives you a unified cross-client view with drift highlighted, instead of diffing four files in four different locations.
- vs merge-everything sync tools (e.g. mcp-config-sync): syncing unions every server into every client. Dedupe does the opposite job — collapse redundant copies to one canonical entry and prune what's dead.
Notes
- Stdlib only:
argparse,json,tomllib,shutil,pathlib. No dependencies, no network calls, no telemetry. - Codex's
~/.codex/config.tomlis parsed withtomllib; a minimal built-in TOML emitter writes it back (backups taken first, as always). - URL-based (remote) servers are listed as
REMOTEfor visibility but never flagged dead — they can't be verified offline. - 14 smoke tests, all green.
python3 -m unittest discover -s tests -v.
If your MCP configs have quietly rotted across clients, pip install mcp-config-dedupe and run mcp-dedupe scan. You might be surprised what's in there.
Top comments (0)