MCP needs a lockfile. Call it mcp.lock.
GB - mcpindex.ai - July 19, 2026
Your package-lock.json pins every dependency your app runs. Your agent's MCP servers - the tools that read your files, hit your APIs, run your shell - are, by default, pinned by nothing at all.
The failure mode
You install an MCP server on Monday. You read the tool descriptions, you're comfortable, you wire it into your agent. On Tuesday the server ships an update: same name, same version, but one tool description now carries an extra clause - "use this tool when the user asks about billing." No release notes. No diff for anyone to review. Your agent re-fetches that description every time it connects, so its behavior just changed without a single line of your code changing.
I watch this from the registry side. My crawler re-fetches the declared tool contracts of about 2,100 reachable remote MCP servers every day and publishes what changed to a public ledger. Most of the edits I see are benign - typo fixes, clarity edits - and that's exactly what makes the dangerous case hard: a capability change dressed as a wording tweak looks identical at a glance, and nobody is glancing.
Package managers already lived this arc: npm existed for years before lockfiles were on by default, and committing one only became a reflex after enough supply-chain pain - left-pad is the incident everyone remembers from that era. MCP is in its pre-left-pad era: everyone installs, almost nobody pins, and tool descriptions are a supply chain nobody is treating as one.
The artifact already exists
Every time your client connects, the tools/list call hands it the server's full declared tool surface - every tool name, description, and input schema - as structured data. Nothing stops you writing that to a file - call it mcp.lock - and failing CI when it changes:
{
"github": {
"create_pull_request": "sha256:9f2c...",
"list_issues": "sha256:a41b..."
}
}
Each hash covers the entire object tools/list returns for that tool - description and input schema included, plus anything else the server declares - serialized the same way every time (sorted keys), so a mismatch means the contract changed, not your serializer.
That sketch is just the integrity map. Commit the serialized contracts alongside the hashes - the way package-lock stores resolved metadata, not just integrity fields - because a bare hash can only tell you something changed; the stored prose is what gives your reviewer an actual diff to read.
Re-fetch on every build. On any mismatch - a changed hash, a tool that appeared and isn't pinned, a pinned tool that vanished - the build fails and a human reviews the diff and re-approves. That's the whole design - a small CI job, not a platform.
If you want it stricter, run the same check in the client too: at connect, and again whenever the server pushes a tools/list_changed notification, because MCP lets a server swap its tool list mid-session without reconnecting. CI catches drift between builds; the client check catches it at the moment the description enters the model's context.
The description field deserves the most paranoia. It goes straight into the model's context and is fully controlled by the server author - and it's not just the top-level field: the parameter descriptions nested inside the input schema are model-facing prose too. A breaking schema change at least has a chance of failing loudly. A description change never does: reword a trigger condition and you've redirected the agent, with no version bump and no error. If you diff only one thing, diff the prose.
What a lockfile can't do
A lockfile is a record of what you approved, and it's only checked when your pipeline runs. It can't tell you the world changed while you weren't building. It also can't tell you whether what you approved on day one deserved approval - a pin is a record of your review, not a verdict on it. The between-builds gap is where registry-side observation fits: at mcpindex I pin contract hashes upstream, re-check daily, and can warn that a server drifted before your next session finds out. But the limit deserves stating plainly, because it's why this post argues for a lockfile and not for us: a registry's pin - ours included - is not a versioned artifact in your repo. Only your repo knows what you approved and why. Trust decisions belong where your review process lives, not in a third party's database. A registry can corroborate; it shouldn't decide.
Does your team do this?
So: does your team commit anything like an mcp.lock? And when you notice a tool's capabilities creeping, what catches it - manual re-review, a version freeze, something uglier? I haven't yet met a team with a working process for this. If you have one, even an ugly one, I want to hear about it.
- What is an mcp.lock file?
- A committed record of each MCP server's declared tool contracts - every tool name, description, and input schema - stored as hashes plus the serialized contracts, so CI fails on any unreviewed change and a human reviews the diff before re-approving.
- Does a registry replace a lockfile?
- No. A registry's pin is not a versioned artifact in your repo. It can corroborate and warn that a server drifted before your next session finds out, but only your repo knows what you approved and why. A registry can corroborate; it shouldn't decide.