MCP server that exposes Lean proofs in the Paperproof boxes format, without installing Paperproof
Project description
paperproof-mcp
MCP server that exposes Lean proofs in the Paperproof "boxes" format (NaturalProofTree) - without requiring Paperproof to be installed in the user's project.
Given a Lean file, the paperproof_proof_tree tool returns each theorem's proof as a hierarchical tree of boxes, where each box is one proof goal with the tactics that transform or close it - exactly the structure Paperproof draws.
How it works
The server runs Paperproof's real parser inside your Lean project, without you installing anything:
- It injects
import Lean+ Paperproof's bundled parser + a#ppjson incommand into your file in-memory (via the LSP, same trick#info_trees inuses). - Runs the parser on the target theorem and reads the resulting JSON off the diagnostics.
The bundled parser depends only on core Lean (no Mathlib), so it elaborates in any project. Because it's Paperproof's actual BetterParser, have/calc/case-splits are handled faithfully - including hypothesis-origin (from) links.
No Paperproof dependency, no lakefile edit, no rebuild. Only a working lake serve is needed (same requirement as lean-lsp-mcp).
Setup
Prerequisites
- uv
- A Lean project that builds (
lake build)
Claude Code - add once, works in every project
claude mcp add -s user paperproof uvx paperproof-mcp
(-s user installs at user scope so you don't repeat it per-project; the server infers each project root from the file path you pass.)
VS Code / Cursor - add to mcp.json
{
"servers": {
"paperproof": {
"type": "stdio",
"command": "uvx",
"args": ["paperproof-mcp"]
}
}
}
Tool
paperproof_proof_tree
Parameters:
file_path(required) - absolute path to a.leanfiletheorem_name(optional) - a specific theorem; omit to parse all theorems in the fileformat(optional, default"paperproof") -"paperproof"returns the hierarchical box tree (NaturalProofTree);"infoview"returns a flat before/after list per tactic (see below)include_theorems(optional, defaultfalse) - also return the signatures of every theorem/def/axiom the proof references, in each tree'sused_theorems
Returns: { lean_version, trees: [{ theorem_name, proof_tree, used_theorems }] }, where each proof_tree is in the requested format.
format: "infoview"
A flat, tactic-by-tactic before/after view, like Lean's infoview. Every goal shows its full hypothesis context (not a diff), and the theorem's initial hypotheses are listed once and never repeated:
{
"initialHypotheses": [{ "name": "a", "type": "Nat" }, { "name": "h", "type": "a = b" }],
"tactics": [
{
"tactic": "cases n with",
"beforeGoals": [{ "hypotheses": [], "goal": "n = n" }],
"afterGoals": [
{ "hypotheses": [], "goal": "0 = 0" },
{ "hypotheses": [{ "name": "k", "type": "Nat" }], "goal": "k + 1 = k + 1" }
]
}
]
}
A tactic that closes its goal has an empty afterGoals; a case split or have obligation produces multiple afterGoals.
used_theorems
When include_theorems=true, each tree carries the lemmas it uses:
"used_theorems": [
{ "kind": "def", "name": "AddCircle.liftIco", "signature": "{𝕜 : Type u_1} → ..." },
{ "kind": "theorem", "name": "Function.comp_apply", "signature": "∀ {β δ α} {f : β → δ} {g : α → β} {x}, (f ∘ g) x = f (g x)" }
]
Referenced constants are collected by walking the proof's info tree and keeping every identifier the user wrote that resolves to a global constant - this targets exactly the lemmas named in the source and drops notation plumbing (HAdd.hAdd, OfNat.ofNat, ...) that Expr.getUsedConstants would include. kind is derived from the type (Prop-valued => theorem), so it stays correct even under Lean's module system where imported proofs are erased and constants otherwise appear as axioms.
Example for have h2 : b = a := by rw [h]; exact h2:
{
"tactic": "have h2 : b = a := by",
"newHyps": [{ "name": "h2", "type": "b = a" }],
"haveBoxes": [
{
"goal": "b = a",
"newHyps": [],
"tactics": [
{ "tactic": "rw [h]", "newGoal": "b = b" },
{ "tactic": "rw [rfl]", "closed": true }
]
}
]
}
NaturalProofTree shape
NaturalProofTree (root box)
goal : string - goal at the top of this box
newHyps : NaturalHyp[] - hypotheses introduced on entry
tactics : NaturalStep[] - proof steps
format : "unicode"
NaturalHyp
name : string
type : string
from? : string - name of the hyp this one derives from (drives the arrow)
NaturalStep
tactic : string
dependsOn? : string[] - hyp names this step consumes
newHyps? : NaturalHyp[] - hyps this step introduces
newGoal? : string - new goal if the goal transformed
closed? : true - this step closes the current goal
newSubgoals? : NaturalBox[] - sub-boxes, one per case after a split
haveBoxes? : NaturalBox[] - sub-proof(s) of a `have`/anonymous `by`
Lean version support
The parser must compile against your project's Lean version. Parsers are hand-maintained Lean files in src/paperproof_mcp/lean_parsers/vX.Y.Z.lean, each containing Paperproof's parser plus the #ppjson runner. The server picks the one matching your lean-toolchain; with no exact match it tries the nearest lower version, then the nearest higher.
To add a version, copy the closest existing parser to vX.Y.Z.lean and fix the Lean-API errors for that toolchain (they are usually small stdlib renames; e.g. for 4.25 vs 4.27: Substring.Raw -> Substring, .trimAscii -> .trim, .dropEndWhile -> .dropRightWhile).
Bundled versions: v4.25.0, v4.27.0. Module-system toolchains (Lean's module / public import / public section) are handled by the runner automatically: it marks the parser meta and meta imports the file's own imports.
Development
src/paperproof_mcp/
server.py - MCP tool; orchestrates the pipeline
lean_runner.py - in-memory injection + revert, reads JSON off diagnostics
converter.py - port of Paperproof's converter.ts (LeanProofTree to ConvertedProofTree)
natural.py - port of copyAsNaturalProofTree.ts (ConvertedProofTree to NaturalProofTree)
lean_parsers/ - hand-maintained Paperproof parser + runner, one per Lean version
License
MIT (see LICENSE). This package bundles Paperproof's Lean parser, which is MIT licensed, Copyright (c) 2023 Anton Kovsharov.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file paperproof_mcp-0.1.1.tar.gz.
File metadata
- Download URL: paperproof_mcp-0.1.1.tar.gz
- Upload date:
- Size: 22.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
155b263e9e8e3e3af064ab5e5a4c7422d95f1da7702abd273958eaa3785f23d6
|
|
| MD5 |
331850638183640cfd230c5a59277fdc
|
|
| BLAKE2b-256 |
642a7ca8dd600fbeb7836e9e8d4f69350306bcb66ba07824ca1e721ae0d2290d
|
File details
Details for the file paperproof_mcp-0.1.1-py3-none-any.whl.
File metadata
- Download URL: paperproof_mcp-0.1.1-py3-none-any.whl
- Upload date:
- Size: 32.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09f7d016efcb8de9f342a41fe65453bf2a4608e22518cbc981a67dbd76e768ab
|
|
| MD5 |
f209d9e98738a6ceaac148018e6e872a
|
|
| BLAKE2b-256 |
485e4fa18c7be8a59c27cbaba3a8c5d304c636ac8a50f2690349e4e5ea44dd6d
|