Dev.to Security πŸ” Cybersecurity πŸ‘ 0 πŸ“– 5 min read

We Checked 10,659 Public MCP Configs. Two Thirds of the Servers Are Unpinned

An MCP config file decides what code runs on a developer's machine every time their agent starts. Most people write it once, often by pasting from a README or letting the agent fill it in, and never look at it again. We

An MCP config file decides what code runs on a developer's machine every time their agent starts. Most people write it once, often by pasting from a README or letting the agent fill it in, and never look at it again.

We wanted to know what those files look like in practice. So on November 7 and 8 we collected MCP config files from public GitHub repositories and ran every one through the same checks as our free MCP Config Check.

What we checked

We searched GitHub code for the four common config files: claude_desktop_config.json, .mcp.json (Claude Code), .cursor/mcp.json and .vscode/mcp.json. That gave us 12,398 files. After removing exact duplicates, 10,850 were unique, and 10,659 contained at least one MCP server. Together they define 32,223 servers.

14,098 of those servers start from a package registry: 11,973 through npm (npx and similar) and 2,125 through PyPI (uvx, pipx). For each one we looked up the package on npm or PyPI, checked the exact version that would run against the OSV vulnerability database, and checked the rest of the entry for secrets and risky settings. Registry and OSV status is as of November 8, 2026.

Two limits to keep in mind. Public repos include tutorials, templates and test projects, so these are not all live setups. And GitHub code search returns at most 1,000 results per query, so we split searches by file size; this is a large sample, not every config on GitHub.

The headline numbers

Finding Files Share of files
At least one server unpinned 4,040 38%
Uses a deprecated package 941 9%
Points at a package that does not exist 638 6%
Uses the legacy SSE transport 323 3%
Contains a likely-real API token 152 1.4%
Runs a name npm replaced with a malware placeholder 15 0.1%

Only 5,154 of the 10,659 files (48%) had nothing to fix or review.

1. Two thirds of package servers run unpinned

9,465 of the 14,098 registry-based servers (67%) have no exact version. npx -y some-mcp-server or @latest fetches whatever is newest on every start. Nobody reviewed that code before it ran, and a compromised release reaches every machine the next time the agent restarts.

This is the same question a reader asked us last week: if a package was approved last month and changes today, is it still approved? With an unpinned config, approval never happens at all. The fix is one edit:

"args": ["-y", "@playwright/[email protected]"]

Then update on purpose, after reading the changelog.

2. The archived reference servers are still everywhere

941 files use a package npm marks deprecated. 819 of them use one of the original MCP reference servers that were archived in May 2025 and will not get security fixes:

Package Servers in our sample
@modelcontextprotocol/server-github 580
@modelcontextprotocol/server-postgres 259
@modelcontextprotocol/server-puppeteer 129
@modelcontextprotocol/server-brave-search 126
@modelcontextprotocol/server-slack 38

server-github alone appears 580 times. GitHub maintains its own server (github/github-mcp-server), and Microsoft's @playwright/mcp replaces the Puppeteer server.

3. 638 files name packages that do not exist

1,381 servers point at a package name that is not on the registry at all, so they fail to start. The most common:

Name in the config Servers What exists instead
@modelcontextprotocol/server-fetch 110 mcp-server-fetch on PyPI, run with uvx
@modelcontextprotocol/server-git 56 mcp-server-git on PyPI
@modelcontextprotocol/server-sqlite 50 mcp-server-sqlite on PyPI
@modelcontextprotocol/server-time 16 mcp-server-time on PyPI

The pattern is clear: the official fetch, git, sqlite and time servers are Python packages, and someone, or some agent, guessed an npm name by analogy with the npm ones. These scoped names are safe from squatting, because only the @modelcontextprotocol organization can publish under that scope.

Not every wrong guess is that safe. 145 servers in 53 files use names under @anthropic/, such as @anthropic/mcp-server-puppeteer. Anthropic publishes on npm as @anthropic-ai. The @anthropic scope belongs to an unrelated organization, so whoever controls it could publish those exact names. And unscoped guesses, like task-master-mcp or firecrawl-mcp-server, can be registered by anyone.

4. Some guesses already met malware

The unscoped version of that same mistake has already been exploited. In June 2026, Amazon Inspector reported malicious npm packages named mcp-server-fetch, mcp-server-git, mcp-server-notion, mcp-server-postgres and mcp-server-redis (MAL-2026-5476, 5478, 5480, 5481, 5482). The advisories say the names were claimed to catch npx calls from AI coding agents. The mcp-server-git package, for example, ran a postinstall script that sent the machine's hostname, working folder, platform and Node version to an outside server. Its author called it canary research; GitHub's advisory says to treat any machine that installed it as compromised.

npm replaced those five packages with empty security placeholders on August 20. 15 files in our sample still run a name npm has replaced with a security placeholder, 13 of them one of these five, through npx. They get a placeholder now. Before the takedown, the same line would have installed the malicious version.

5. Tokens pasted into the file

1,122 files have something in an env, args, headers or URL field that our checker flags as a possible secret. Many of those are placeholders or local database passwords, so we counted again with strict rules: only known token formats (OpenAI, Anthropic, GitHub, Google, AWS, Slack, Stripe), and nothing that looks like a placeholder or an example. That left 152 files with what look like real tokens, including 96 OpenAI-format keys, 26 Google API keys, 18 Anthropic keys and 23 GitHub tokens.

We did not test any of them, and we are not publishing which repos they are in. If your config ever went into a repo, a gist or a dotfiles backup with a key in it, rotate the key. Most clients can read the value from your environment instead: Claude Code expands ${VAR} in .mcp.json, and VS Code can prompt for a value once with ${input:id} and store it securely.

6. Smaller things worth fixing

  • Legacy SSE: 453 remote servers (6% of remote ones) still use the SSE transport the MCP spec replaced with Streamable HTTP in March 2025.
  • Plain HTTP to remote hosts: 74 servers send tokens and tool results unencrypted.
  • Auto-approved write tools: 68 servers auto-approve tools whose names say they write, send or delete.
  • Unpinned Docker images: 684 Docker-based servers use latest or no tag.

What we would do this week

  1. Open your MCP configs and pin every version. Exact versions for npm and PyPI, a tag or digest for Docker.
  2. Remove the archived reference servers and switch to the vendor-maintained ones.
  3. Check every name actually exists, on the registry you think it is on. Python servers run with uvx, not npx.
  4. Move keys out of the file and rotate any that were ever committed or shared.
  5. Stop the agent from adding new ones unreviewed. Put the approved server list in CLAUDE.md or AGENTS.md, and block installs of anything else with a pre-tool hook.

You can do steps 1 to 4 in about a minute: paste your config into the MCP Config Check. It runs in your browser, sends only package names to the public npm, PyPI and OSV APIs, and flags everything in this article.

Originally published at x1y1.co/journal.

πŸ“° Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.