Releases: jcreinhold/lean-host-mcp
Releases · jcreinhold/lean-host-mcp
v0.4.1
Fixed
search_for_proofsemantic-lane candidates now return the clean Lean name (e.g.
FirstOrder.Language.BoundedFormula.IsDelta0.bdAll) with themodulefield populated, instead of leaking the
downstreamorigin:module:declNamecorpus key as thename(e.g.
lean-host-mcp:KanProofs.ModelTheory.Delta0.Basic:FirstOrder…bdAll). The prefixed key broke the documented key-free
contract and thesearch_for_proof→inspect_declarationhandoff.
v0.4.0
Added
search_for_proofnow has a semantic retrieval lane for file/declaration-backed queries. When a request includes
source context, the tool askslean-semantic-searchfor proof-goal features, extracts declaration features from the
candidate modules, ranks semantic candidates, and merges them with the existing declaration-search fallback. Public
evidence stays key-free: semantic matches surface as stablesemantic:*match_reasonlabels such as
semantic:role_conclusion_constorsemantic:conclusion_fingerprint; raw feature keys and capability command names
stay private. If the semantic command is unavailable or fails, the tool returns the existing structural fallback with
a warning instead of failing the MCP call. The capability now comes from the package-owned
lean-semantic-search-runtimecrate, so consumer projects do not expose or importLeanSemanticSearch.Capability.- Cross-process admission control for semantic/elaborating work. Parallel server processes sharing a lock directory now
coordinate before running heavy worker calls, so semantic proof search and other elaborating requests do not stampede
the machine. New[broker]knobs and env overrides:semantic_permits/LEAN_HOST_MCP_SEMANTIC_PERMITS,
semantic_waiters/LEAN_HOST_MCP_SEMANTIC_WAITERS,semantic_admission_timeout_millis/
LEAN_HOST_MCP_SEMANTIC_ADMISSION_TIMEOUT_MILLIS, andsemantic_lock_dir/LEAN_HOST_MCP_SEMANTIC_LOCK_DIR.
Saturation returns retryable structured errors such assemantic_admission_fullorsemantic_admission_timeout.
Changed
- Bumped the
lean-semantic-search-*crates to 0.3.0 and adapted to the storage-neutral retrieval API
(retrieve_across(&[&dyn Corpus], ...)instead ofSemanticIndex::retrieve(...)).lean-semantic-search-runtimeis
now published, so the host consumes it from crates.io; the temporary local-path[patch.crates-io]override is gone. - Bumped
lean-rs-worker-parentandlean-rs-worker-childto 0.2.0 andlean-toolchainto 0.2.1. This pulls link-free
lean-rs-abimetadata into the parent-side dependency graph, socargo nextest run --workspace --no-fail-fastno
longer builds the parent test binary with an accidentallibleansharedload command through workspace feature
unification. The worker crate still linkslibleanshared; the parent crate remains link-free. - Updated the host for additive
lean-rs0.2.0 telemetry fields: RSS/resource fields are ignored where the envelope
does not yet expose them, declaration inspection leaves the new proof-search facts disabled by default, and module
query cache-fact fixtures setresource: None.
Fixed
- Workspace-wide nextest no longer aborts while listing parent tests on macOS with
Library not loaded: @rpath/libleanshared.dylib; the parent test binary is again free of Lean runtime linkage when
built together with the worker.
v0.3.0
Changed
find_referencesatscope: "project"now reads Lean's on-disk.ileanreference index instead of elaborating every
.leanfile through the worker. The old path issued one worker module-query per file (~3 s/file → ~27 min on a
~500-file project) and only returned an arbitrary truncated prefix when it hit the request-time budget. The index read
is sub-second, returns the complete result (only thelimitcap truncates, on a stable sorted prefix), and
involves the worker not at all. Project-scope results are now build-fresh — they reflect the lastlake build—
whilefilescope stays on the worker path and remains edit-fresh (current source); the asymmetry is documented
in the tool catalog. An unbuilt project degrades to the existingneeds_buildtop-level warning (not an empty "no
references", not a hard error), and an index stale relative to current source rides a freshness note. The
files_scanned/files_skippedcounters now report.ileanmodules indexed / skipped at project scope. The now-moot
per-file wall-clock scan deadline and its "hit the request time budget" warning are gone.- The default proof position is now the pristine entry goal — the state before any tactic runs.
proof_stateand
try_proof_steppreviously disagreed:proof_state'sgoals_beforeshowed the entry goal, buttry_proof_step
spliced a candidate after the first tactic, so a from-scratch tactic block read offproof_statefailed with
introN failed: ... no additional binders to introduce. Nowproof_stateat the default reports the entry goal
(goals_before == goals_after) and a defaulttry_proof_stepsnippet elaborates against that same goal, so
from-scratch blocks work at the default. The old first-tactic state stays reachable as{kind:"index","index":0}.
Behavioral change for callers that relied on the default mapping to the post-first-tactic state. - Bumped the
lean-rs-worker-parent/-childandlean-toolchaindependencies to 0.1.20, which adds the upstream
Entryproof-position selector this reconciliation maps the default onto.
Added
- For explicit
{kind:"index"}/after_textpositions, a failed candidate carrying a binder-introduction diagnostic
now surfaces a cue pointing at the entry default (or continuing fromgoals_after), so the trap is signposted even
off the default path. - Worker provenance now records the building
lean-host-mcpversion. Worker and host are version-locked, so a worker
built by a different host is flagged as stale — closing a skew that previously served an ABI/protocol-mismatched
worker silently (it would fail at call time instead of with a clear message).install-worker --listgains ahost
column (current/stale/unknown), and a project served by a host-skewed worker now rides a rebuild warning in
every envelope. install-worker --auto(the default) now rebuilds stale workers — host-version skew,lean.hheader drift, or a
failed/absent smoke record — not just missing ones, and skips out-of-window toolchains instead of failing on them. So
re-running it after alean-host-mcpupgrade brings every worker back in step.--forcerebuilds current workers
too.install-worker --clean [--toolchain <id>]removes all installed workers (or one);install-worker --pruneremoves
only unservable workers (outside the supported window, or with a failed smoke test), keeping servable-but-stale ones.
Both are idempotent and only touch the install root.- Configurable per-request timeout:
runtime.request_timeout_millis(envLEAN_HOST_MCP_REQUEST_TIMEOUT_MILLIS),
default 120 s. Replaces the worker's fixed 10-minute long-running profile. On expiry the worker is recycled and
the call returns a retryable runtime error; raise it for unusually heavy modules, lower it to bound calls. find_referencesat project scope is now bounded by that same budget as an overall wall-clock deadline, not just per
file. It fans one worker query out across every module in the project (hundreds in a large tree), so the per-request
timeout alone left the aggregate sweep able to run for many minutes and appear to hang. The deadline now runs
concurrently with each in-flight query, so even a single stalled module cannot block the call; whatever was indexed
before the deadline is returned with a truncation warning and a cue to narrow withfilesor raise the budget.
v0.2.0
Changed
- Tools no longer advertise an
outputSchema. Handlers return a bareCallToolResult, sotools/listcarries no
nested$defs(~52 KB → ~9.6 KB). The Anthropic Messages API dropped the field before the model anyway, and deep
$defsbroke strict clients (Claude Desktop, Zed) — proof agents read the JSON envelope as text either way.
Breaking for any client that validated tool responses against the advertised schema. - Per-call telemetry is now config-gated and omitted by default.
Freshnesssplits into the always-emitted
FreshnessIdentity(project_root,session_id,lean_toolchain) and an optionalTelemetryblock
(project_hash, the fullimportslist, workerRuntimeFacts) that is dropped under the new default
telemetry.verbosity = quiet; setfullto restore today's output.proof_state'squery_factsand
search_for_proof's search funnel (stage counts, cache status) likewise appear only underfull. The one actionable
signal a worker restart carries still surfaces as a top-levelwarning. - New
server.response_carrierknob (textdefault,structured,both) selects whether the JSON envelope rides in
contenttext,structuredContent, or both, instead of always duplicating intostructuredContent.
Removed
- The per-call tuning knobs
max_field_bytes,max_total_bytes, andheartbeat_limitleft theinspect_declaration,
try_proof_step, andverify_declarationrequest schemas; they now live in[output]server config with the same
defaults. Breaking for callers that set them per request — configure them server-side instead.
v0.1.0
Added
cargo install lean-host-mcpnow works without a source checkout. When the server binary was not built from a
checkout,install-workerbuilds each per-toolchain worker from the publishedlean-host-mcp-workercrate
(cargo install lean-host-mcp-worker --version =<ver>) instead of erroring; from a checkout it still builds the
worker from workspace source, and--source-diroverrides the choice. The worker is still compiled locally per
toolchain (its rpath is machine-specific) and smoke-tested before use. Both crates are now published to crates.io.- Unified TOML config file for every tunable knob. A
lean-host-mcp.toml(found by walking up from the working
directory, like the lakefile) or the home~/.config/lean-host-mcp/config.tomlcan set the[runtime],[broker],
and[server]knobs that were previously env-var-only, plus the existingprimary_project. When both files exist
they merge per key (local wins); precedence isCLI > env var > file > built-in default, so existing
LEAN_HOST_MCP_*setups are unaffected and an env var still overrides the file. Malformed files are logged and
ignored. See docs/operations.md. lean-host-mcp config initwrites a documented starter config file — every option at its current default, each with a
comment explaining it — to./lean-host-mcp.toml(or~/.config/lean-host-mcp/config.tomlwith--home, or a
--path). The file, the per-knob reference table in the docs, and the built-in defaults are all generated from one
in-code catalogue, so they cannot drift.- Worker-recycle observability: each recycle is now logged to stderr with structured fields (
cause,reason,
worker_generation,rss_kib,limit_kib,restarts_total) at a signal-appropriate level (warnfor
abnormal/crash,infofor memory-pressure cycles,debugfor hygiene), and every response'sruntimecarries
lifetimerestarts_totalplus a per-causerestarts_by_causebreakdown so recycle frequency is visible. See
docs/operations.md. - Structured
tracingacross the server's high-value paths (tool entry, project open/eviction, the idle reaper, the
per-call job span, RSS headroom, toolchain resolution, and verdict-relabel decisions), all on stderr so the stdio
transport's stdout stays clean. Default level isinfo;RUST_LOG=lean_host_mcp=debugsurfaces per-call detail. - RSS-config guard rails: the server validates
import_switch <= post_job <= hard_killat startup and refuses to start
with a clearinvalid RSS config: …message on an inverted ordering, so e.g. raising
LEAN_HOST_MCP_WORKER_RSS_POST_JOB_RESTART_KIBabove the hard-kill ceiling fails fast instead of degrading silently. - Honest
worker_recycledverdict: when the worker is recycled or restarted during a semantic call (a memory-pressure
recycle on a heavy module, or a crash-and-retry), the verdict was computed under infrastructure duress.
verify_declarationnow relabels a non-positive verdict toverification_status: "worker_recycled"with
facts_trustworthy: falseinstead of a misleadingnot_found, andtry_proof_step/proof_statecarry a retry
warning. Averifiedverdict is never relabeled (verification is monotone). The signal is derived from the call's
runtime facts (call_restart) and excludes benign pre-job/planned cycles. - Initial release of
lean-host-mcp, an MCP server that hosts Lean 4 in a supervised worker child
(lean-rs-worker-parent+lean-rs-worker-child) and reaches the elaborator and kernel directly rather than through
an external LSP. - Two-crate workspace: a parent that does not link
libleansharedand a per-toolchain worker binary that does —
keeping the parent free of the Lean dylib so one server can host multiple toolchains. - Multi-toolchain dispatch: each Lake project resolves its own
lean-toolchainpin to a worker binary under
~/.local/share/lean-host-mcp/workers/<id>/;install-workersubcommand builds and installs them. - A six-tool declaration-centric proof workflow:
proof_state -> search_for_proof -> inspect_declaration -> try_proof_step -> verify_declaration, plus
find_referencesfor semantic lookup.proof_statedegrades to{ "status": "unsupported" }when the optional host
shim is absent. - Closure-channel actor over the worker child, with a
ProjectBrokerper-project pool and idle reaper. - Stdio (default) and loopback-only Streamable HTTP transports.
- Response envelope contract (
result+freshness+ optionalwarnings/next_actions) shared by every tool;
Lean-domain failures are part of theOkpayload, not MCP errors. - Worker RSS supervision: a post-job restart policy and an in-flight hard-kill watchdog, plus the
rss_threshold_sweep.pytuning tool. - Honest resolution verdicts: an incomplete project build degrades to a single
needs_buildverdict carrying a
lake buildcue acrossverify_declaration,inspect_declaration,proof_state,try_proof_step,
find_references, andsearch_for_proof— never a misleadingambiguousstatus or a hard transport error. Genuine
ambiguity instead names the competing declarations, andfacts_trustworthyflags any verdict computed against an
incomplete or unresolved environment. - Builds on
lean-rs-worker-parent/-child0.1.19 (worker protocol 8), supporting the Lean toolchain window
4.26.0 ..= 4.31.0-rc1(head4.31.0-rc1).
Notes
- Pre-1.0: minor versions may carry breaking changes; patch releases stay compatible.