Skip to content

mirror-stack/mirror-stack-mcp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🪞🔎🪪 mirror-stack-mcp

One MCP server for the whole Mirror Stack. Install once, add one server, and an agent has all four mirrors: claims, actions, provenance, and a stack-level verify-all.

💬 Discussions — questions · ideas · independent reproductions welcome.

🔎 See it on real records → the Sealed-Record Reading Room — a human-readable viewer over actual sealed ledgers: each experiment shows the kill-condition sealed before the run, the verdict (pass / kill / retracted / inconclusive), and every number auto-recomputed from the ledger. You can even tamper with a sealed value in the browser and watch the hash break. Shows what the discipline looks like in practice, including the failures and retractions — not just the wins.

Get all mirrors at once

pip install git+https://github.com/mirror-stack/mirror-stack-mcp

That single install pulls measure-mirror + action-mirror + provenance-mirror as dependencies — you don't clone four repos. (Apache-2.0, zero-dep cores.)

Add one MCP server

{
  "mcpServers": {
    "mirror-stack": { "command": "mirror-stack-mcp" }
  }
}

No cwd, no PYTHONPATH — it's a proper installed entry point. Works in Claude Code, Cursor, Windsurf, any MCP client.

Tools (19)

Tool Mirror Does
mm_preregister 🪞 claims seal a claim + kill-condition before measuring (response carries an auto seal-quality lint)
mm_verify 🪞 umbrella verify — every probe whose input key is present
mm_audit 🪞 audit a result vs its sealed registration
mm_power_check 🪞 false-negative guard — is n big enough? (design-time)
mm_falsifiability_check 🪞 Popper gate — kill-condition registered & not tripped?
mm_prereg_lint 🪞 seal quality lint (㉗) — leaked kill-condition, bar at/below declared chance, unstructured kill, low n, undeclared pre-seal checks; the compute gate BLOCKs on a lint FAIL
mm_leakage_check 🪞 train∩test contamination
mm_multiseed_check 🪞 unstable signal / lucky seed
mm_retract 🪞 chain-linked retraction (cannot be silently deleted)
mm_anchor 🪞 tamper-evident snapshot to store outside the ledger (local)
mm_anchor_bitcoin 🪞⏱️ real external anchor — timestamp ledger heads into Bitcoin (OpenTimestamps)
mm_anchor_upgrade 🪞⏱️ retrieve the Bitcoin block attestation once a calendar has committed (~1–3h)
mm_anchor_verify 🪞⏱️ verify a Bitcoin anchor via a public block explorer — no local node needed
mm_preflight 🪞 GO/BLOCK gate primitive — wire into a compute launcher / pre-commit hook
am_record 🪪 actions seal an action; target=<claim_id> ties it to a claim
am_witness 🪪 pin a peer's ledger head (catches whole-file replacement)
am_verify 🪪 verify an action ledger's hash chain
pm_verify 🔎 provenance verify a file's provenance across 5 signals
stack_verify_all 🪞🔎🪪 whole stack in one call: chain (L1) + anchors (L3) + witness (L2)

(More granular measure-mirror probes are reachable via mm_verify — it dispatches by data key.)

External anchor: Bitcoin (OpenTimestamps) ⏱️🔗

mm_anchor writes a local snapshot — useful, but it's still your file. mm_anchor_bitcoin upgrades the L3 layer to a real external clock: it timestamps your ledger heads into the Bitcoin blockchain via OpenTimestamps, so anyone can later prove your record existed before a given block — independent of you and of GitHub.

Honest scope (this is the whole point, so we say it plainly):

  • proves your ledger heads existed before a Bitcoin block time → no backdating, no silent rewrite.
  • does NOT prove the content is true (GIGO — an early-sealed lie is still a lie).
  • does NOT summon an external judging witness (that's the social layer, L2). The clock is run now for a verifier who may arrive later.

Cryptography here doesn't block dishonesty — it makes a rewrite detectable.

Use it

pip install "mirror-stack-mcp[bitcoin] @ git+https://github.com/mirror-stack/mirror-stack-mcp"
# (pulls the `ots` CLI; needs network to reach the public OpenTimestamps calendars)

Then, via the MCP tools (or the agent calling them):

  1. Stampmm_anchor_bitcoin(ledger_paths=["/path/seara.jsonl", …], out_dir="…/anchors_ots") → builds a manifest of the heads, submits it, returns state="pending" + the .ots path.
  2. Upgrade — in ~1–3h, mm_anchor_upgrade(ots_path)state="bitcoin_confirmed" + block_height.
  3. Verifymm_anchor_verify(ots_path) cross-checks the block's merkle root on a public explorer (default blockstream.info) — no Bitcoin node required — and returns whether it matches.

Anyone can independently re-check: curl https://blockstream.info/api/block-height/<height>.

See docs/ANCHORING.md for the full walkthrough, CLI fallback, and the L1 / L2 / L3 model.

The discipline travels with the tools

When an agent connects, the server injects a compact honest-measurement discipline via the MCP instructions handshake — so the methodology arrives with the tools, not as a separate doc someone has to find. It carries the one rule that matters most: separate the tool from your judgment — say "mm flagged X" only when a probe returned a Finding you can quote; say "applying the discipline, I suspect X" when it is your reasoning. Plus: seal-before-compute (preregister + kill-condition), power before spending, verify-before-reporting, and "a missing ledger is itself a signal."

(MCP clients that surface server instructions — e.g. Claude Code — show this on connect. It is guidance, not enforcement: the hard guarantee is still the chain + witness, not the prompt.)

Reminders at each beat (configurable)

The connect-time instructions fade over a long session, so the server also re-grounds the discipline at the moment it matters — a one-line reminder appended to the relevant tool's result. mm_preregister → "the result must be sealed too, not just prose"; mm_verify / mm_audit / stack_verify_all → the before you state a number checklist (the language rule, both directions, scope, seal negatives); am_record, mm_retract, mm_power_check, mm_falsifiability_check → their own one-liner. It fires at the seal/verify/publish beat, not every turn — a nudge, not noise.

Control it with the MIRROR_REMINDERS env var:

value behaviour
once (default) append each reminder only the first time per session
all append the reminder on every relevant call
off never append

once is the default so a long loop doesn't re-pay for the same reminder every turn (context hygiene). Override per server:

{ "mcpServers": { "mirror-stack": {
    "command": "mirror-stack-mcp",
    "env": { "MIRROR_REMINDERS": "all" }
} } }

Output compaction (loop context hygiene)

Verification output piles up across a loop's iterations — context rot + cost. The server compacts it without hiding signal: OK/INFO findings collapse to one summary line, while every WARN/FAIL is kept verbatim (a dropped negative would defeat the whole point).

MIRROR_VERBOSITY behaviour
compact (default) ✓ N check(s) OK: … + every WARN/FAIL in full
full every finding verbatim

Per-call compaction is the server's job; summarising the running log across iterations is the loop/harness's — the server is stateless per call.

Hard gate: seal-before-compute / seal-before-publish (opt-in)

Reminders are soft. For a hard gate, mm_preflight returns a GO/BLOCK decision you wire into the action site:

  • mm_preflight(ledger, claim_id, gate="compute")BLOCK unless a preregistration with a kill-condition is sealed. Wire it into your training/experiment launcher so it refuses to spend compute on an unsealed claim.
  • mm_preflight(ledger, claim_id, gate="publish", am_ledger=…)BLOCK unless the result is also sealed (a retraction, or am_record(target=claim_id)). Wire it into a pre-commit / pre-publish hook so unresolved claims can't ship.

The MCP only judges GO/BLOCK — your launcher/hook does the actual blocking. The server cannot intercept external compute or commits, and that is by design: the discipline is opt-in (a missing ledger is itself a signal), not something the channel forces on you.

The enforcer ships with the package. mm_preflight judges; the mirror-stack-gate CLI is the part that actually exits non-zero, so a shell can do the blocking the MCP can't:

mirror-stack-gate compute --ledger L.jsonl --claim my_claim && python run.py
# exits 1 (run.py never starts) unless a kill-conditioned preregistration is sealed
mirror-stack-gate publish --ledger L.jsonl --claim my_claim --am-ledger A.jsonl
# exits 1 unless the result is sealed too (a retraction or am_record(target=claim))

For git, drop in hooks/pre-commit.sample: it runs the publish gate so a result can't be committed until its claim is resolved. The CLI and the MCP tool share one decide() (gate.py), so they can never drift apart.

Why this is sound

The tamper-evidence comes from the hash chain + external witness, not from the MCP channel — so exposing the action ledger over MCP is fine: an edit still breaks the chain. This server makes honesty easy to prove; it does not (and cannot) prevent an agent that simply never records.

See what the stack guarantees — and the one it can't (the four pillars: integrity · non-erasure · falsifiability · verifiability), and the Mirror Stack conventions + case study.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors