The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Safe Fix MCP listing page.
A real MCP server that finds dead code in a Python repository and proposes a branch + PR for the one class of finding that's actually safe to auto-remove: unused imports on a single-name import line. Everything else it finds — unused functions, classes, unused dependencies — stays report-only. A human always merges. This tool never merges anything itself.
Most "dead code" tools stop at reporting. The ones that go further usually delete with no safety net. This does neither: it drafts a real, minimal, reviewable PR, gated on the target repo's own full test suite actually passing after the removal — not a heuristic, a real pytest run. If the suite fails, nothing is committed or pushed; the repo is left exactly as it started.
scan_dead_code(repo_path=".", min_confidence=60)Read-only. Runs vulture (dead code) and deptry (dependency issues) and returns a human-readable list of findings. Never modifies anything.
propose_removal_pr(repo_path=".")from x import y, z is skipped — removing the whole line would silently remove z too).gh pr create.gh isn't installed/authenticated, the branch is still committed and pushed for real — only PR creation degrades, with the real error returned so you can open it manually.Add to your MCP client config (e.g. Claude Code):
Or run directly for local testing:
Installing from source instead of PyPI:
A SKILL.md ships inside this same package — not a separate download — and teaches Claude when and how to use the two tools correctly (e.g. that propose_removal_pr only ever auto-removes single-name unused imports, never functions/classes/dependencies). Install it into your project:
Run it from the project root you want the skill active in — it writes to .claude/skills/safe-fix-mcp/SKILL.md relative to your current directory.
git on PATHgh (GitHub CLI) on PATH and authenticated, if you want propose_removal_pr to actually open the PR — without it, the branch still gets pushed for real, and the tool tells you to open the PR by hand.vulture flags scan_dead_code/propose_removal_pr themselves as "unused" — a known false-positive class, not a real bug: they're dispatched by the @mcp.tool() decorator at runtime, not called directly anywhere in the source, so static call-graph analysis can't see the real caller (the MCP framework itself).
scripts/verify_real_client.py launches the packaged server as a real subprocess and talks to it with the real mcp.client.ClientSession — the same path a real MCP client uses. Useful as a smoke test after any change: