Pinning an MCP server to a release tag feels like control. Corelight’s research suggests it is not. In a post dated 10 November 2026, James Lagermann reports that a community MCP server pinned to a single release still ran with 15 different dependency sets over five weeks, because the way it was launched (the uvx one-step launcher) resolved its dependencies again from PyPI whenever it rebuilt its environment. This guide summarizes the finding and the freeze method Corelight describes, and adds our own cautions.
What Corelight measured
- Most of the 162 launches in one week only checked the pinned tag and reused a cached environment. Some launches rebuilt it when PyPI had newer releases within allowed ranges: 19 builds of the same release and commit over five weeks produced 15 distinct environments, and 23 of the 69 packages changed version.
- Of 35 MCP servers Corelight reviewed (from two vendor catalogs and its own lab), 23 had a recommended install that would resolve dependencies fresh from a public registry, either at every launch or at each install or image build. Corelight also notes some hosted-server proxies are started with
npx <proxy>@latest, and that this is a setup choice, not a flaw in MCP. - The point is structural: the server’s own version is fixed, but its transitive dependencies are whatever the registry serves at launch. A malicious or broken release of any dependency can reach you the next time the environment rebuilds, with the privileges of the MCP server (often access to files and tokens).
This is Corelight’s measurement of the servers it reviewed. We have not reproduced it, and the 35-server sample is not a census.
The freeze method
Corelight describes five steps:
- Pin to a commit, not a tag. Tags can be moved; a commit hash cannot.
- Install from a hash-pinned lock file into a dedicated environment, with hash checking enabled, so a changed artifact fails the install.
- Install the server itself without resolving dependencies, so nothing outside the lock file is pulled in.
- Launch the installed server directly, rather than through a command that resolves and fetches at start.
- Turn off startup update checks.
Corelight reports that five frozen servers started 457 times over two weeks with identical package lists, and started in about 2 seconds rather than 4 to 11 seconds.
Corelight’s post, as we read it, does not name specific tool flags. Mapping these steps to your tooling (pip, uv or another installer) is your job; check your installer’s documentation for hash-checking and no-dependency install options and test that a tampered hash actually fails.
The cost: you own the lock file
Freezing stops silent change, and it also stops silent fixes. Corelight found that one frozen server had 40 packages older than what the launcher would have pulled that day. Our recommendation:
- Name an owner for each frozen MCP server.
- Re-lock on a schedule, review the diff, and scan the new set for known vulnerabilities before rollout.
- Keep the lock files in version control so a change is a reviewable commit.
Practical checklist (ours)
| Check | Pass condition |
|---|---|
| Server source | Pinned to a commit hash |
| Dependencies | Installed from a hash-checked lock file |
| Launch | Starts the installed binary, no fetch at start |
| Update checks | Disabled |
| Ownership | A named person and a re-lock date |
| Inventory | Every MCP server in use is listed with its launch command |
Start with the inventory. You cannot freeze what you have not listed: know which MCP servers run on developer machines and CI agents, and how each one starts.
Related reading
See our other coverage of MCP and software supply chain risk on this site before applying this to production.