> ## Documentation Index
> Fetch the complete documentation index at: https://docs.refactron.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP server

> Refactron over the Model Context Protocol: one tool, verify_change, that returns SAFE, UNSAFE, or UNPROVEN on a proposed change before an agent lands it.

Refactron ships an [MCP](https://modelcontextprotocol.io) server that exposes exactly one tool: **`verify_change`**. An agent hands it a repository root and a proposed change, and gets back a verdict backed by your real test suite, run in an isolated shadow tree.

The server speaks **stdio**, identifies itself as `refactron` version `0.3.0`, and runs entirely on your machine. It never writes to your repository: applying the change stays the agent's job, after a verdict the agent trusts.

The fastest way in is to let your agent do the setup. Every client page below opens with a copy-only prompt that installs the server, registers it, reloads the client, and gets a first real verdict, written for that client specifically.

Prefer to do it by hand? Pick your client below, or follow the [MCP quickstart](/mcp/quickstart).

<Frame caption="An agent proposes a change, calls verify_change, and decides whether to land it based on the verdict.">
  <img src="https://mintcdn.com/refactron/X73JMJH6Xlirf-6H/assets/mcp.svg?fit=max&auto=format&n=X73JMJH6Xlirf-6H&q=85&s=664c26b015c19cfd19ea2924bceb2984" alt="An AI agent calling Refactron's verify_change MCP tool and receiving a SAFE, UNSAFE, or UNPROVEN verdict before landing the change" width="640" height="380" data-path="assets/mcp.svg" />
</Frame>

## Why an agent calls it

A coding agent has no independent way to tell a change that works from a change that only looks right. `verify_change` gives it one: run the project's own tests against the proposal, in a copy, and report what that run actually proved.

* **`SAFE`**: every gate passed and your tests exercised the changed code. Suite-approved, not proven correct: the verdict inherits exactly what your tests check.
* **`UNSAFE`**: a gate failed. The change broke something.
* **`UNPROVEN`**: the gates passed, but the evidence for `SAFE` is missing. A warning, not a rejection.

The full model, including how coverage fuses with the gates and what `SAFE` does not claim, is in [Verdicts](/verification/verdicts).

## Install

Requires Node.js 18 or newer. For a coverage-backed `SAFE` verdict you also need Python 3.8+ with `pytest` and `coverage.py`.

Install globally and get both binaries on your `PATH`:

```bash theme={null}
npm install -g refactron@0.3.0
```

That gives you `refactron` (the CLI) and `refactron-mcp` (this server).

To skip the install and let the client fetch the package on demand:

```bash theme={null}
npx -y -p refactron@0.3.0 refactron-mcp
```

The `-p` flag is required. `refactron-mcp` is a second binary of the `refactron` package, not a package of its own, so `npx refactron-mcp` on a machine without the global install looks for a package named `refactron-mcp` and fails with a registry 404.

<Note>
  `pip install refactron==0.3.0` installs a wrapper that still requires Node.js 18+, and it provides
  the `refactron` command only.
</Note>

The PyPI wrapper does not ship `refactron-mcp`. If you found Refactron through PyPI and want the MCP server, install the npm package as well.

## Connect your client

<CardGroup cols={2}>
  <Card title="Claude Code" icon="https://mintcdn.com/refactron/9E__K3qPt8uQOWLT/assets/clients/claude.svg?fit=max&auto=format&n=9E__K3qPt8uQOWLT&q=85&s=5be60463498e85d66c6a15b02f2d07dd" href="/mcp/claude-code" width="24" height="24" data-path="assets/clients/claude.svg">
    One `claude mcp add` command, or a project `.mcp.json`.
  </Card>

  <Card title="Claude Desktop" icon="https://mintcdn.com/refactron/9E__K3qPt8uQOWLT/assets/clients/claude.svg?fit=max&auto=format&n=9E__K3qPt8uQOWLT&q=85&s=5be60463498e85d66c6a15b02f2d07dd" href="/mcp/claude-desktop" width="24" height="24" data-path="assets/clients/claude.svg">
    Edit `claude_desktop_config.json` and restart the app.
  </Card>

  <Card title="Codex CLI" icon="https://mintcdn.com/refactron/9E__K3qPt8uQOWLT/assets/clients/openai.svg?fit=max&auto=format&n=9E__K3qPt8uQOWLT&q=85&s=21179f04778c363094636778c1263b18" href="/mcp/codex" width="256" height="260" data-path="assets/clients/openai.svg">
    `~/.codex/config.toml`, in TOML, under `[mcp_servers.refactron]`.
  </Card>

  <Card title="Cursor" icon="https://mintcdn.com/refactron/9E__K3qPt8uQOWLT/assets/clients/cursor.svg?fit=max&auto=format&n=9E__K3qPt8uQOWLT&q=85&s=cc4574ad50af3221089e30662978acb3" href="/mcp/cursor" width="24" height="24" data-path="assets/clients/cursor.svg">
    Project `.cursor/mcp.json` or the global `~/.cursor/mcp.json`.
  </Card>

  <Card title="GitHub Copilot in VS Code" icon="https://mintcdn.com/refactron/9E__K3qPt8uQOWLT/assets/clients/githubcopilot.svg?fit=max&auto=format&n=9E__K3qPt8uQOWLT&q=85&s=225b5dc6ecb49879ca51b1d0867feecd" href="/mcp/vscode" width="24" height="24" data-path="assets/clients/githubcopilot.svg">
    `.vscode/mcp.json`, whose root key is `servers`, not `mcpServers`.
  </Card>

  <Card title="Gemini CLI" icon="https://mintcdn.com/refactron/9E__K3qPt8uQOWLT/assets/clients/googlegemini.svg?fit=max&auto=format&n=9E__K3qPt8uQOWLT&q=85&s=579ba0f8b5f0a64be73fc96362c8078f" href="/mcp/gemini-cli" width="24" height="24" data-path="assets/clients/googlegemini.svg">
    One `gemini mcp add` command, or `~/.gemini/settings.json`.
  </Card>

  <Card title="Windsurf" icon="https://mintcdn.com/refactron/9E__K3qPt8uQOWLT/assets/clients/windsurf.svg?fit=max&auto=format&n=9E__K3qPt8uQOWLT&q=85&s=63e0eac1c049f0e77505e0cb7e79a47e" href="/mcp/windsurf" width="24" height="24" data-path="assets/clients/windsurf.svg">
    Cascade reads `~/.codeium/windsurf/mcp_config.json`.
  </Card>

  <Card title="Any other client" icon="https://mintcdn.com/refactron/9E__K3qPt8uQOWLT/assets/clients/mcp.svg?fit=max&auto=format&n=9E__K3qPt8uQOWLT&q=85&s=9da4ff6ddb40b1baa3da9092b32439ee" href="/mcp/other-clients" width="24" height="24" data-path="assets/clients/mcp.svg">
    Anything that can launch a stdio MCP server can run this one, Zed and Cline included.
  </Card>
</CardGroup>

## Make it verify, not just connect

Registering the server only adds a tool the agent may never reach for. These two prompts are what turn it into a habit. Both are written for the agent, not for you.

### Verify before you apply

Defines the loop: propose, verify, then act on the verdict. Lasts the current conversation.

<div className="agent-prompt is-rule">
  ```text theme={null}
  From now on, in this repository, verify every code change with the Refactron
  verify_change MCP tool BEFORE you write it to disk.

  The loop:

  1. Work out the change you want to make. Do not apply it yet.

  2. Call verify_change with:
       repoRoot  the ABSOLUTE path to this repository
       edits     [{ path, newContent }] with the full proposed contents of each
                 file you want to change, OR unifiedDiff, a unified diff of the
                 change against the CURRENT working tree
       testCmd   the project's test command, if it is not obvious. For a Python
                 project installed into the environment (an editable
                 `pip install -e .` included), prefix it with PYTHONPATH=. so the
                 tests import the copy being verified. Use PYTHONPATH=src for a
                 src layout.

  3. Read the `verdict` field and act on it.

     SAFE     Apply the change. Report the verdict and quote the `reason`. Also
              say what SAFE does not cover: every changed FILE had at least one
              changed statement executed, not every changed statement. If
              coverage.changedStatements shows a low covered/total ratio, say so
              rather than presenting SAFE as full coverage.

     UNSAFE   Do NOT apply anything. A gate failed, which means your change broke
              something. Read `reason` and the failing entry in `gates`, fix YOUR
              change, and call verify_change again. Repeat until it is not UNSAFE.
              Never work around this by weakening or deleting a test. If you touch
              a test file, the report lists it in testFilesChanged and I will check.

     UNPROVEN Do NOT apply yet. Read `reason` to find out which kind this is:

              "the changed code is not exercised by any test" means the suite ran
              and nothing executed your lines. Write the tests named in the
              `missingTests` array, add them to the same verify_change call, and
              re-verify. Aim to turn this into SAFE. If a missingTests hint says a
              line is excluded from coverage (`# pragma: no cover`, `if
              TYPE_CHECKING:`), do NOT try to write a test for it. No test can
              reach it. Flag it for human review.

              "coverage of the changed code could not be determined" means no
              measurement happened at all. Coverage is Python-only today, so a
              TypeScript, JavaScript, or mixed-language change always lands here
              and no test you write moves it. The gates still passed. Report this
              plainly and let me decide. Do not present it as SAFE.

              "no test runner detected" or "baseline tests already fail" means
              nothing could be proven either way. Stop and tell me.

  4. Never describe a SAFE verdict as "verified correct", "proven correct", or
     "guaranteed safe". It means the project's own tests ran the changed code and
     stayed green. It inherits exactly what those tests check.

  5. If the tool returns an error instead of a verdict, read the message. "no
     edits provided" means you passed neither `edits` nor `unifiedDiff`. "diff did
     not apply (stale base?)" means you already wrote the change to disk, so the
     diff no longer applies to the tree being copied: pass `edits` instead, or
     revert first. A message about deletions, renames, copies, or binary files
     means the change uses an operation the tool refuses to verify, so tell me and
     verify that part by hand.
  ```
</div>

### Make it stick across sessions

Writes that rule into the project, so every session and every teammate inherits it.

<div className="agent-prompt is-project-rule">
  ```text theme={null}
  Add a Refactron verification rule to this project's agent rules file, so the
  behavior persists across sessions.

  Pick the right file for this repo, and create it if it is missing:
    - AGENTS.md at the repo root, the cross-tool convention
    - CLAUDE.md at the repo root, for Claude Code
    - .cursor/rules/refactron.mdc, or .cursorrules on older Cursor, for Cursor
    - .windsurfrules for Windsurf
    - .github/copilot-instructions.md for GitHub Copilot
    - GEMINI.md at the repo root, for Gemini CLI

  Append this section verbatim. Do not remove anything already in the file.

  ## Verification (required)

  Verify every code change with the Refactron `verify_change` MCP tool before
  writing it to disk. Pass `repoRoot` as an absolute path and the change as
  `edits` or `unifiedDiff`. Verify before the change exists on disk: the shadow
  tree copies the working tree, so a diff of an already-written change will not
  apply.

  - `SAFE`: apply it, and report the verdict. `SAFE` means the project's tests ran
    the changed code and stayed green. It is suite-approved, not proven correct,
    and it is a per-file check: every changed file had at least one changed
    statement executed, not every changed statement.
  - `UNSAFE`: do not apply. Fix the change and re-verify. Never weaken a test to
    turn a verdict green.
  - `UNPROVEN`: do not apply yet. If the reason names uncovered code, write the
    tests listed in `missingTests` and re-verify. If the reason is that coverage
    could not be determined, say so and ask a human. Coverage is Python-only, so a
    non-Python change cannot reach `SAFE` today.
  ```
</div>

### Why the wording in these prompts matters

Every prompt tells the agent, more than once, not to report `SAFE` as "correct". That is deliberate.

`SAFE` means the gates passed and your suite exercised the changed code. It does not mean the change is right. A real example from Refactron's own hardening runs: changing `<=` to `<` in Jinja2's `truncate` filter genuinely changes behavior at the boundary, all 911 tests still pass, the changed line is covered, and the verdict is `SAFE`. The verdict is correct about what it claims and is still not a proof of correctness.

An agent that reports `SAFE` as "verified correct" has laundered a test-suite result into a guarantee. That is the one failure mode this tool exists to prevent, so the prompts spend words on it.

## Then use it

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/mcp/quickstart">
    Install, register, confirm the tool is listed, and get a first real verdict.
  </Card>

  <Card title="Verify before you apply" icon="clipboard-list" href="#verify-before-you-apply">
    The standing rule that makes your agent verify instead of guess.
  </Card>

  <Card title="Tool reference" icon="book" href="/mcp/tool-reference">
    Every `verify_change` argument, the response shape, and the error shape.
  </Card>

  <Card title="Verdicts" icon="scale-balanced" href="/verification/verdicts">
    What each verdict is allowed to claim, and what it is not.
  </Card>
</CardGroup>

## What the server does and does not do

* **It runs entirely local.** Verification happens on your machine, in a shadow tree. Nothing about your code leaves it, and the handler makes no network calls.
* **It never mutates your repository.** `verify_change` reads your tree and applies the change in an isolated copy. Landing the change is the agent's job, after a verdict it trusts.
* **It is deterministic.** The same repository state and the same change produce the same verdict every time.
* **It needs no login.** The `verify-diff` CLI is auth-gated, but the MCP handler calls the local engine directly.

## Limits worth knowing before you start

Coverage attestation runs through `coverage.py`, so it is Python-only today. A TypeScript, JavaScript, or mixed-language change passes through the same three gates but caps at `UNPROVEN` with `coverage.tool` set to `none`, because Refactron cannot measure whether the changed statements ran. It will not guess, and a guess here would be a false `SAFE`.

Coverage also cannot see code that only runs in a subprocess. A change exercised solely through `subprocess.run` or a `multiprocessing` worker reads as `UNPROVEN` unless you wire up subprocess coverage yourself.

Diffs that delete, rename, or copy a file, or that change a binary file, are refused rather than partially verified. See [Unsupported operations](/verification/verify-diff#unsupported-operations).

There is no hosted CI gate. Refactron runs where you run it: your machine, or your own CI job.
