contractpin

Pin the contract of every MCP tool you depend on. Fail CI when it changes behind your back.

Your package lockfile pins the code an MCP server ships. It does not pin what that server tells your model to do — the tool names, descriptions and schemas your model reads as instructions on every connection. Rug-pulls, tool poisoning, schema widening and annotation flips are all text diffs on data you already receive. contractpin hashes that contract (RFC 8785 canonical JSON → SHA-256) into a committed contractpin.lock and exits 1 the moment anything moves.

curl -O https://open.getaxionlabs.com/contractpin/contractpin.py
python contractpin.py init npx -y @acme/mcp-search   # writes contractpin.lock — commit it
python contractpin.py verify                          # exit 1 the moment anything moves

Python 3.9+, standard library only, one file, MIT. A TypeScript twin produces byte-identical digests; 19 conformance vectors make independent implementations checkable rather than trusted.

Not a trust signal — a pinned tool is a tool that has not changed since you read it. Not a registry — no service, no account, nothing to go down. If MCP adopts server-signed contract digests upstream, contractpin should be deleted; that is the intended ending.

Files

GitHub repository and package-manager installs: coming; this page is the canonical source until then.