cd /news/ai-agents/your-ai-coding-tools-run-software-yo… · home topics ai-agents article
[ARTICLE · art-139056] src=blog.devgenius.io ↗ pub= topic=ai-agents verified=true sentiment=↓ negative

Your AI coding tools run software you never pinned. Here is the lockfile.

Mcp-audit version 0.18.0 adds a lockfile for MCP servers, addressing unpinned npx dependencies that fetch whatever version the npm registry calls latest on every tool start, according to the tool's author. A measurement by Prachet Poddar resolved 250 MCP server root packages twice with the same resolver — against the registry as of September 7 and again on September 17 — and 184 of the 250 produced a different set of packages, with the corpus growing only from 2,867 to 2,882 distinct name-and-version pairs. Of the fifteen official @modelcontextprotocol/server-* packages on npm, eleven are deprecated while their latest tag still resolves and npx -y still runs them.

by read8 min views3 publishedSep 24, 2026

Open the MCP config for whichever AI coding tool you use. Cursor, Claude Code, VS Code, Windsurf, it does not matter which. You will find lines like this:

"filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."] }

Read that line the way a package manager would. Every time the tool starts, npx fetches whatever version of that package the registry currently calls latest, runs it, and hands it read and write access to the directory you are sitting in. No version. No hash. No record of which version you were running last week, or that it changed.

You would never ship a Node or Python project that way. package-lock.json and poetry.lock exist because "install whatever is newest" turned out to be a supply-chain problem and a reproducibility problem at the same time. Your MCP servers are the one dependency on your machine that still works the old way, and they are the dependency with the most access.

This is the problem I built mcp-audit lock to solve. mcp-audit is a free, open-source security scanner for MCP servers. MCP servers are what give AI agents like Claude access to your files, databases, and APIs. Version 0.18.0 adds a lockfile for them.

Two threads from the official MCP servers repository, in the maintainers’ own issue tracker:

In July, a user reported that after a component auto-updated to version 2026.7.10, “every Filesystem tool call in desktop chat fails with a bare [error]” (modelcontextprotocol/servers#4545). In November of last year, a different user described a server that stopped working with an agent SDK “after upgrading the server” (servers#3051).

Neither person did anything. Something under them changed, and the first they heard of it was a broken agent. Those are the benign cases. The malicious version is the same mechanism with a different author.

In August, on a Hacker News thread about tens of thousands of exposed MCP servers, one commenter listed what MCP is missing, by analogy to npm: “lockfiles, audit commands, and signed provenance” (thread). That is the shortest correct description of the gap I have seen.

One more number, because I checked it while writing this. Of the fifteen official @modelcontextprotocol/server-* packages on npm, eleven are deprecated. Their latest tag still resolves. npx -y still runs them. Nothing in the config tells you, and until this week nothing in my own tool did either.

And here is what happens when nothing is deprecated at all. Prachet Poddar, who is building the install-tree generator for the same lockfile, took 250 MCP server root packages from npm’s mcp-server keyword search (a frame that excludes deprecated packages) and resolved each one twice with the same resolver: once against the registry as it stood on September 7, rebuilt from publish timestamps, and once against the registry on September 17. 184 of the 250 came out with a different set of packages. The corpus barely grew, from 2,867 distinct name and version pairs to 2,882. Nothing was added. Versions were swapped underneath: routine releases of zod, hono, proxy-addr, fast-uri and ip-address account for most of it, and every changed tree differs in at least one package that actually runs. Two caveats are his, and they cut the same way: the sets come from his resolver, which matches npm’s selection rules on every test vector he has, not from a real install; and the rebuilt registry cannot see versions unpublished since the 7th, so 184 is closer to a floor. His measurement, his frame, his caveats, on issue #88 of the repo, and the best argument for this file I have seen.

I spent a while on this question, because a lockfile that records the wrong things is worse than none. It creates the feeling of control without the substance. Here is where I landed.

It records, per server: Which client it belongs to, the server name, the package name, the exact version the floating spec resolved to at lock time, an integrity hash of that package where the registry provides one, the server’s declared capabilities, and the names of the environment variables and headers it uses.

It never records: The values of those environment variables or headers, absolute filesystem paths, your hostname, or your username. A lockfile gets committed. Anything in it is in your git history forever. mcp-audit has a test that reads every lock file it writes and fails the build if it finds a home path, the current username, or anything that matches its own secret patterns.

The file is plain JSON in a canonical form (RFC 8785), so two machines locking the same config produce byte-identical output and git diff shows only real changes.

mcp-audit lock              # write mcp-lock.json from your project's MCP configsmcp-audit lock --verify     # exit 1 if anything drifted, or could not be verifiedmcp-audit lock --accept     # "I reviewed this": rewrite the lock from the current state

--verify runs offline. It compares the configs on disk against the lock and exits non-zero when a locked server changed (LOCK-001), a server appeared that was never locked (LOCK-002), or the lock file itself was hand-edited (LOCK-005). A server that disappeared is reported but does not fail the build on its own; removal is not automatically suspicious. Add --resolve and it also asks the registry whether latest now points somewhere else than the version you locked.

In CI it is one step:

- run: mcp-audit lock --verify

That step is the whole point. A pull request that changes an MCP server now fails until someone runs --accept and commits the new lock. The change becomes visible in review, next to the code, where it should have been all along.

I would rather you find these out here than in the issue tracker.

It does not stop a client from updating itself. If your desktop app auto-updates a bundled component, the lock will tell you the next time you verify that the version you approved is not the version present. It cannot intercept the update. Runtime enforcement is a different product; this is a review-time control.

It does not yet record what a server’s tools actually do. The lock has a tools section reserved for hashes of each tool's contract, so a server whose description quietly changes would fail verification. That section ships empty in this release. A July proposal on mcpindex.ai for a per-tool contract hash is the right shape for it.

It does not build the install tree. package-lock.json records every transitive dependency. mcp-audit deliberately never executes a package manager, because that is what makes it safe to point at a repository you do not trust. So the trees section of the file belongs to a separate generator that Prachet Poddar is building. Two independent tools write one file, and neither touches the other's section. That was a design argument we had in public, in the issue tracker, and his version of the rule was better than mine.

PyPI integrity hashes are not populated yet. npm tarball hashes are.

It now tells you when the version it locked is deprecated on its registry. That finding (SC-005) exists because the demo fixture in my own README used @modelcontextprotocol/server-github, whose latest version has been deprecated since April 2025, and the lock recorded it without a word. I found that by extracting frames from the demo recording, three days before this article, and the finding shipped as v0.18.1 the same day. The fixture now uses a maintained package, and the tool says so when yours does not.

And it is not the first attempt at this. MCPTrust signs a snapshot of a server’s tool surface. mcpguards’ mcp-lock pins npm versions and integrity, with a verify command and a GitHub Action. I looked at both before building. What mcp-audit’s version adds is the offline verify with CI exit codes, the hard rule about never recording secret values, the two-producer file, and the fact that it lives in the same tool that scans your configs for credentials, poisoned tool descriptions, and cross-server data flows. lock is marked experimental in this release. The file shape may change once before it is frozen.

One more thing you should know. The --verify command in the previous release returned exit 0 for a lock whose entries had never been resolved. It printed an honest warning, then told CI everything was fine. Prachet found it while building the tree generator. It is fixed in 0.18.0, and the changelog explains why the old behaviour was wrong rather than burying it as a bug fix. I am not an engineer. I build this with coding agents and review every change, and that bug is the clearest example I have of why a second set of eyes matters more, not less, when agents write the code.

Three things, in order of effort.

First, open your MCP configs and pin what you can. @modelcontextprotocol/server-filesystem@2026.8.31 instead of the bare name. It is one line per server and it removes the "whatever is newest" behaviour entirely. While you are in there, run npm view <package> deprecated on each one. You may be surprised.

Second, commit a record of which servers your team approved. Even a Markdown list in the repo is better than the current state, which is usually nothing.

Third, make a change to that set visible in review. If you want the automated version:

pip install mcp-audit-scannermcp-audit lock . && mcp-audit lock --verify .

The repository has a fixture under demo/lock/ that reproduces the exact drift-and-catch sequence shown in the README, so you can see what a failure looks like before you wire it into anything.

mcp-audit is free and open source under the Apache 2.0 license. If you run lock on a real repository and something breaks, open an issue. That is the feedback I want most.

Your AI coding tools run software you never pinned. Here is the lockfile. was originally published in Dev Genius on Medium, where people are continuing the conversation by highlighting and responding to this story.

── more in #ai-agents 4 stories · sorted by recency
── more on @mcp-audit 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/your-ai-coding-tools…] indexed:0 read:8min 2026-09-24 ·