# safe-fix-mcp [Health: Active]

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/pamela-0/safe-fix-mcp  
**GitHub Stars:** 1  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/safe-fix-mcp

## Description
Finds real dead code and proposes a safe, test-gated branch+PR to remove it.

## Tools
Capabilities this server exposes over MCP:

- **z**
- **gh**

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `uvx` (confidence: high):

```json
"mcpServers": {
  "safe-fix-mcp": {
    "command": "uvx",
    "args": ["safe-fix-mcp"]
  }
}
```

## Documentation & README

# safe-fix-mcp

<!-- mcp-name: io.github.pamela-0/safe-fix-mcp -->

[![PyPI](https://img.shields.io/pypi/v/safe-fix-mcp)](https://pypi.org/project/safe-fix-mcp/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

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.

## Why this exists

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.

## Tools

### `scan_dead_code(repo_path=".", min_confidence=60)`

Read-only. Runs [vulture](https://github.com/jendrikseipp/vulture) (dead code) and [deptry](https://github.com/fpgmaas/deptry) (dependency issues) and returns a human-readable list of findings. Never modifies anything.

### `propose_removal_pr(repo_path=".")`

- Refuses on a dirty working tree — never edits on top of uncommitted work.
- Filters to unused imports at ≥90% vulture confidence, on single-name import lines only (`from x import y, z` is skipped — removing the whole line would silently remove `z` too).
- Creates a real branch, removes the qualifying imports, runs the repo's real full test suite.
- Only on a real pass: commits, pushes, and tries to open a PR via `gh pr create`.
- If `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.

## Install

```bash
pip install safe-fix-mcp
```

Add to your MCP client config (e.g. Claude Code):

```bash
claude mcp add safe-fix-mcp -- safe-fix-mcp
```

Or run directly for local testing:

```bash
python -m safe_fix_mcp.server
```

Installing from source instead of PyPI:

```bash
pip install -e .
```

## Skill

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:

```bash
safe-fix-mcp-install-skill
```

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.

## Requirements

- Python ≥ 3.10
- `git` on PATH
- `gh` (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.

## Development

```bash
pip install -e ".[dev]"
pytest
```

## Known limitation

`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).

## Verifying it for real

`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:

```bash
python scripts/verify_real_client.py
```

