The code your users copy
Most of the code a developer-tool company ships is reviewed, tested and released on purpose. Some of it is not: the one-line install command in the README, the JSON block people paste into Claude Desktop or Cursor, the starter app they clone to get going. Nobody reads that code before running it, because it is meant to be run as written. And it rarely has an owner, so it drifts.
In October 2026 we measured two kinds of it. This page sums up what we found, why it happens, and what to check in your own docs and examples. The detailed numbers and methods are on two separate pages: install commands and example apps.
What we found
- Install commands that point to nobody's package. Of 4,830 npm READMEs of MCP and AI-agent packages, 80 (1.7%) run one of the package's own commands through
npx,bunxorpnpm dlxunder a name that no one has registered. Today that line fails. Once someone registers the name, the same line installs and runs their code, with whatever API key or wallet key the user passes to it. This is not hypothetical: one such name was registered by a third party on 31 July 2026, and npm replaced it with a security holding package less than two hours later. - Registry entries that rot. In the official MCP registry, 13 active entries declared a package version that no longer exists, 11 pointed to deprecated packages, and 1 to a package that was never published.
- Example apps that freeze vulnerable versions. We checked 517 example projects published by 12 funded developer-tool companies. 168 of them (32%) resolve a production dependency with a critical advisory, at 9 of the 12 companies. Most of it is one framework, Next.js, pinned by a committed lockfile at a version that has since received a critical fix.
None of this comes from careless teams. The repositories were active, several with commits that same week. What was missing is an owner for this kind of code, and a check that fails when it drifts.
Why it happens
npx runs whatever matches the name
Many packages ship a command whose name differs from the package name: the package @acme/mcp installs a command acme-mcp. Inside a project where the package is installed, npx acme-mcp finds that command. On a fresh machine, or inside an MCP client configuration, npx looks for a package called acme-mcp on the registry instead, and with -y installs it without asking. The README was right in the context where it was written, and wrong everywhere it was copied to. uvx has the same behaviour on PyPI.
Placeholders that are real names
Documentation needs example names. A placeholder such as example-mcp-server looks harmless, but it is a valid package name: anyone can publish it, and readers who paste the snippet unchanged will install it. In one hosting platform's docs, that exact name was unregistered on PyPI and already taken on npm by an unrelated personal package. The team is now replacing it with clear placeholders.
Lockfiles keep the past exactly
Committing a lockfile in an example is good practice: a fresh install reproduces a known-good set of versions. It also reproduces their vulnerabilities, for as long as nobody regenerates it. Of the three companies with no affected example, the one we looked at more closely does not commit lockfiles in its templates, so a fresh install picks up fixed releases. Keeping lockfiles and refreshing them works too. A committed lockfile that nobody refreshes does not.
The checklist
Install commands and MCP configurations
- Name the package explicitly when the command name differs from it:
In an MCP configuration, the same goes intonpx -y -p <package> <command> uvx --from <package> <command>"args":["-y", "-p", "<package>", "<command>"]. - Every name in a command should be one you own. If a name is on your page and you do not publish it, either register it (an empty placeholder package is enough) or change the command.
- Use placeholders that cannot resolve.
<your-package>fails in a shell instead of installing something;example-mcp-serverinstalls whatever is published under it. - Pin versions in configurations meant to be pasted (
<package>@1.4.2), and update them with your releases. A pinned version also means that a hijacked new release is not installed automatically. - Keep registry entries in step with releases. A directory or registry listing is one more copy of your install command; check it when you deprecate or rename a package.
Example apps and starters
- Give each example an owner, or mark it clearly as unmaintained and archive it. An example nobody owns will be several majors behind within a year.
- Let a bot propose updates, grouped so they stay reviewable. One pull request a week per example, minor and patch versions together:
# .github/dependabot.yml version: 2 updates: - package-ecosystem: npm directories: ["/examples/*"] schedule: interval: weekly groups: minor-and-patch: update-types: ["minor", "patch"] - Run CI on a schedule, not only on push. Examples rarely get commits, so a check that runs only on push never runs. A weekly job that installs from the lockfile, builds, and fails on high or critical advisories in production dependencies makes the drift visible:
on: schedule: [{ cron: "0 6 * * 1" }] push: jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 22 } - run: npm ci - run: npm run build - run: npm audit --omit=dev --audit-level=high - Plan the majors. Bots handle patch releases; they do not migrate a framework. When a fix only exists in a newer major, as it does for Next.js 14 examples today, someone has to do the migration and test the app. Budget one to two hours per real app, less for small examples.
What fixing it looks like
When maintainers acted, the fix was small and quick: one registered the missing npm name on the day of our report; a workflow engine stopped resolving five Python imports to unclaimed PyPI names in a single pull request, the same day; an MCP server switched its README and plugin configuration to its hosted endpoint within a week. Finding it is the hard part, because the command works on the machine of the person who wrote it.
Check your own
- The free install command check reads a README, a docs page, an MCP configuration or a GitHub URL, and checks every package its commands would install: names nobody has registered, deprecations, look-alikes, new packages and vulnerable pinned versions.
- In CI, mcp-preflight.mjs (Node 18+, no dependencies) exits non-zero when an MCP configuration launches a package that does not exist.
- For a whole docs site or a repository of examples, we review every install command and example for you, and keep them current afterwards: presendapp@gmail.com.
The measurements behind this page, their caveats and the scripts to reproduce them: install commands, example apps, false-positive rates of our checks.