Home / Posts

Do MCP server READMEs tell you which version to run?

By Muhammad Basit Ali ·

Almost nobody installs a local MCP server from first principles. You open the repository, scroll to the snippet for your client, and paste something like "command": "npx", "args": ["-y", "some-server"] into a config file. From then on, whatever that line names is the code your agent starts every session, with your permissions and usually with an API token in its environment.

Last week, the state of public agent skills and MCP servers found that 159 of 346 repositories (46.0%) that commit a local MCP configuration start at least one server with no pinned version. That is the downstream picture. This week I went upstream, to the snippet people copy, and asked a narrower question: when an MCP server's own README tells you how to launch it, does it name a version?

The headline numbers

Counted by command rather than by repository, 817 of the 835 distinct launch commands I found (97.8%) float.

Why an unpinned line matters, and why it is not a vulnerability

A floating launch command hands the choice of what code runs to the package registry, on the day you start the client. If a maintainer's account is taken over, or a release ships a bug or a quietly changed tool, everyone on a floating command picks it up on their next restart. In a normal application build, a lockfile stands between you and that. In an MCP client config, the README line is often the only thing there.

Not every floating line is equally loose. A bare npx -y some-server or uvx some-server runs whichever version your machine cached first, and does not update itself later, so it is a lottery about the day you installed, and two colleagues following the same README can run different code. A moving tag like @latest is the opposite: it re-resolves on every launch, so a release reaches you within hours of publication. Neither is a pin, which is why I report the moving-tag share on its own.

None of this says any package is malicious. It is a default. The README is the template, people copy the template, and the 46.0% of unpinned configurations in last week's report is what that template looks like once it lands in other people's repositories. The fix is cheap and sits with the maintainer: print the exact version in the README and bump it at release time, as the 12 repositories that already do show. The MCP project's own quickstart and example pages use the unpinned form too, which is what issue #3431 on the specification repository is about.

How I measured it

I took the 399 repositories in last week's random sample that ship an MCP server.json, the same set as the tool annotations report, and fetched only their README and server.json files at the exact commits recorded in the dataset. 391 were still available. Nothing was installed, built or run.

A short standard-library script reads the root README and the README next to each server.json, and finds commands that fetch a published package or image and run it: npx, bunx, pnpm dlx, yarn dlx, uvx, uv tool run, pipx run and docker run, in client configs (JSON, TOML and YAML), in shell lines and in inline code. Prose that merely mentions npx does not count, and neither do development tools such as the MCP Inspector, test runners or scaffolders, local paths, placeholders like pkg@<version> or images the same README builds locally. Each command's version is classed as exact, a range, a moving tag or absent.

Repository-level shares carry 95% Wilson intervals. Command-level shares carry intervals from resampling whole repositories, because one monorepo alone holds 116 commands. I read 60 commands drawn at random against their READMEs: all 60 were real instructions to fetch and run a published package, 56 of the 60 start the MCP server itself (the other four are a driver setup step, an installer and an unrelated command-line tool, all still unpinned), and the version class matched my reading in all 60.

The full method, every rule, the hand-check file and the limitations are on the report page, Do MCP server READMEs tell you which version to run?. The data is in data/2026-10/readme-pins: one row per command, one row per repository, and a results file with every number and its interval. A test checks that every share on the report page matches that file.

What to check before you install an MCP server

If you keep MCP configs in a repository, skill-scan-gate flags unpinned servers in committed configs in CI, the same rule family last week's report used.

What the data does not show

It reads READMEs, not documentation sites, so a project that pins in its docs but not its README is counted as floating. It is static pattern matching, so a command built from variables or written in a form I did not anticipate is missed; the hand check bounds what was found, not what was missed. Monorepos with many READMEs weigh heavily in the command counts, which is why the repository-level shares are the ones to quote. And this is a subset of a sample of what GitHub code search surfaces, not a census.

The data

Everything is in basitalisandhu/agent-skills-state-2026, now at version 1.2.0, under CC BY 4.0 for the data and MIT for the scripts. No number in the first report or the tool annotations report changed. If a number here looks wrong, or you know a launch form I missed, an issue is the best way to tell me.

Tools in this post

All tools