Skip to main content
The Refactron MCP server exposes exactly one tool. Every example below was captured from a real stdio session against refactron 0.3.0.

Arguments

repoRoot is the only argument the schema marks required, but the handler needs a change to verify: supply either edits or unifiedDiff. Supplying neither returns an error result, not a verdict.

Request: the edits form

Use this when the agent already holds the full new contents of each file.

Request: the unifiedDiff form

Use this when the change already exists as a patch, for example from git diff or a codemod.

Response

The tool returns the same report verify-diff --json prints, serialized as text content. A real UNPROVEN response:

Field by field

coverage.removalOnlyFiles and coverage.inertOnlyFiles list changed files with nothing for coverage to attest, because the change only removed lines or only touched comments and blank lines. coverage.uncoveredTruncated and missingTestsTruncated appear as { shown, total } whenever a list was capped, so a truncated report never reads as a complete one. An agent must check for them before concluding a file is absent from the list because it is fine.

The two UNPROVEN reasons are not interchangeable

"Tests pass, but the changed code is not exercised by any test." means the measurement ran and found nothing executing your lines. Writing the test named in missingTests moves the verdict. "Tests pass, but coverage of the changed code could not be determined." means no measurement happened. The diff was not all Python, coverage.py was unavailable, or the tests never loaded the copy under verification. No test you write moves this one. Treating those as the same sentence is how a reader talks themselves into trusting a verdict that proved nothing. They are reported separately on purpose.

Errors

Failures come back as a normal tool result with isError set, so the server keeps running and the agent can read the message.
Real messages you will see: The stale-base error has one cause that surprises people. The shadow tree is a copy of your working tree, not of HEAD, so a change you have already written to disk is already in the copy. Passing git diff of that change asks Refactron to apply it a second time, and it will not apply. Verify before you write: pass the proposal as edits, or revert the file first and pass the diff. Deletions, renames, copies, and binary changes are refused rather than partially verified. A diff that removed a module while making one innocuous edit once verified as safe on the half that could be checked, and applying it broke every import in the package. A partial verdict must never read as a verdict on the whole change.

How it maps to the CLI

verify_change and verify-diff run the same engine and produce the same report. MCP has no exit codes, so the equivalence is with the verdict field: UNPROVEN exiting 0 is deliberate. It is a warning that nothing was proven, not a finding that something is broken, so it never silently blocks a merge. An agent that wants stricter behavior branches on the verdict field itself. A tool result with isError: true corresponds to the CLI’s exit 2, bad input, which is an operational error rather than a verdict.
The verify-diff CLI is auth-gated and exits 7 when unauthenticated. The MCP handler calls the local engine directly, so it needs no login and makes no network calls.

Constraints

Coverage runs through coverage.py and is Python-only. A diff touching any non-Python file returns UNPROVEN with coverage.tool set to none, and cannot reach SAFE today. The gates still run. Coverage cannot see subprocesses. Code exercised only inside subprocess.run, a multiprocessing worker, or a spawned server does not register as covered unless you wire up subprocess coverage yourself. If the project is installed into the environment, an editable pip install -e . included, the tests may import the installed copy rather than the tree under verification, and the run proves nothing about the change. Pass PYTHONPATH=. (or PYTHONPATH=src for a src layout) in testCmd so the verified copy wins on sys.path.