{"slug": "i-looked-at-1384-tools-across-28-mcp-servers-here-s-what-the-attack-surface-like", "title": "I looked at 1,384 tools across 28 MCP servers. Here's what the attack surface actually looks like.", "summary": "A developer surveyed 1,384 tools across 28 popular Python MCP servers and found that 14 of the 28 expose at least one untrusted-content source and one high-impact sink in the same agent context, while 59 individual tools both ingest external content and perform actions. The analysis, based on a reproducible harness reading public source code as of 2026-10-20, also found that all 9 pattern-based tool-poisoning matches across four vendors were benign, since legitimate servers routinely write descriptions as direct instructions to the model.", "body_md": "Quick context if you're new to this: an **MCP server** is a plug-in that gives an AI agent a set of **tools** it can call, like \"fetch this URL,\" \"run this database query,\" or \"send this email.\" There are hundreds of open-source MCP servers now. This writeup measures what those tools actually let an agent do, and how often the risky combinations sit side by side.\n\nMethod note. The numbers are a **snapshot taken on 2026-10-20** of 28 popular Python MCP servers (plus the reference-servers repo), produced with a [reproducible harness](https://github.com/agentsploit/agentsploit/tree/main/examples/mcp-survey). Upstream repos change over time, so re-running this later gives somewhat different counts. Everything below is read from **public source code**. No server was connected to or executed. The capability labels are rough heuristics (see the caveats), and this writeup deliberately does **not** call anything a vulnerability.\n\nI kept running into MCP servers where one tool fetches a web page and another tool runs a command, both handed to the same agent, with nothing telling the model which one is dangerous. Instead of guessing how common that is, I decided to measure it.\n\nSo I pulled the tool definitions straight from the source code of the most popular Python MCP servers on GitHub (AWS Labs, Google Workspace, Atlassian, Home Assistant, Snowflake, the Neo4j / Redis / Qdrant / Chroma / Milvus database servers, the Office / Excel document servers, Telegram, and more), and ran [AgentSploit](https://github.com/agentsploit/agentsploit)'s inventory checks plus a simple source/sink classifier over them. That comes to **1,384 tools across 28 servers.** The reproducible harness is at the bottom.\n\nA tool's description is just text, and the AI reads it. The \"tool poisoning\" attack is built on that fact: if an attacker can slip instructions into a description, the model may follow them. (Think of it like hiding a note in a manual that the reader obeys without question.)\n\nWhat the survey shows is that **normal, legitimate servers already write their descriptions as direct orders to the model.** These are real examples, and all of them are completely harmless:\n\n\"Before using this tool, provide a 1-3 sentence explanation…\" (AWS Labs)\n\n\"CRITICAL: YOU MUST CALL inspect_doc_structure FIRST…\" (Google Workspace)\n\n\"🔴 PREREQUISITE: Before calling this tool, you MUST first call `…`\" (AWS Labs)\n\nThose are good-faith usage notes. The problem is that, at the level of plain text, they look exactly like an injected `IGNORE ALL PREVIOUS INSTRUCTIONS`. A pattern-based scanner (AgentSploit's included) flags both the same way. I went through all **9** matches by hand, spread across **4 independent vendors** (AWS, Google, Home Assistant, arXiv), and every single one was **benign**. That is the real finding: there's no clean way to tell a harmless instruction-style description from a malicious one, because the whole ecosystem already uses that same channel on purpose.\n\nI sorted every tool into two buckets:\n\n`url`, `uri`, `path`, or `document`, or its name looks like `fetch` / `read` / `search` / `crawl`.` exec` / `run` / `query` / `write` / `send` / `delete`, or an argument like `command`, `code`.\nThe danger isn't either bucket on its own. It's having both in front of the same agent, so that something the agent *read* can flow into something the agent *does*.\n\nAcross 1,384 tools:\n\n|  | count | \n|---|---|\n| untrusted-content **sources** | 239 | \n| high-impact **sinks** | 384 | \n| tools that are **both** (they ingest*and* act) | **59** | \n| servers that expose at least one source **and** one sink in the same context | **14 / 28** | \n\nThe 59 \"both\" tools are the sharpest edge. A single tool that pulls in a URL or a file and also runs a query or a command is a one-call bridge from untrusted input straight to a real action, if the content it pulls is attacker-controlled. For example `search_table(url)` that also takes a `query`, or `run_query(db_endpoint, sql)`, or the Google Workspace and Office document tools that read a document and write it back. And 14 of the 28 servers put sources and sinks in the same agent context with nothing marking one as untrusted or the other as dangerous. (The harness prints the full list so you can check it yourself. A few are weak matches. For instance AWS IAM's `create_user` trips the filter on an IAM `path` argument, which isn't really outside content.)\n\nPlenty of the sink tools take a raw string with **no `enum`, `pattern`, or `format` constraint** on it, like `executeQuery(query)`, `run_opencypher_query(query)`, or `read_documentation(url)`. (Those constraints are the schema's way of saying \"only these specific values are allowed.\" Without them, the field accepts anything.) That's by design for a query tool. It's also exactly the kind of wide-open sink that turns \"the agent read a poisoned page\" into \"the agent ran the attacker's SQL.\"\n\nTo be clear: none of the above is a bug in these servers. A source-to-sink chain only becomes a real exploit when two things both happen: untrusted input actually reaches a source, and the agent actually carries it over to a sink. Both of those depend on how the server gets deployed and wired together, not on the code itself. Proving a real chain needs a live agent, which is what AgentSploit's permission-graph mapper and canary runner are for. That's out of scope for a static survey like this one.\n\n`enum` / `pattern` / `format`) rather than taking any raw string.\nThe quickest way to run this against a server yourself (shipped in v1.7):\n\n```\npip install agentsploit\nagentsploit survey ./path/to/mcp-server   # a repo directory or a single .py file\n```\n\nOr reproduce the full multi-repo survey with the harness:\n\n```\ngit clone https://github.com/agentsploit/agentsploit && cd agentsploit\npip install -e .\ncd examples/mcp-survey            # edit servers.yaml to pick targets\npython survey.py collect          # read tool definitions from public source\npython survey.py scan             # run agentsploit's inventory checks\npython survey.py aggregate        # print the findings table\npython survey.py surface          # run the source/sink classification\n```\n\n`scrape` names), and the matching is token-based. It's still a guess at what a tool can do, not a traced data-flow. So read the counts as \"could plausibly be,\" and trust the overall shape more than any single number. The shape is the sturdy part: most servers mix ingestion and action, and 59 tools do both in one call.\nThe tool is Apache-2.0: [github.com/agentsploit/agentsploit](https://github.com/agentsploit/agentsploit). Ideas and pull requests welcome.", "url": "https://wpnews.pro/news/i-looked-at-1384-tools-across-28-mcp-servers-here-s-what-the-attack-surface-like", "canonical_source": "https://dev.to/dishant_desle/i-looked-at-1384-tools-across-28-mcp-servers-heres-what-the-attack-surface-actually-looks-like-4il0", "published_at": "2026-10-22 23:04:48+00:00", "updated_at": "2026-10-22 23:11:22.183046+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "ai-safety", "ai-tools"], "entities": ["AgentSploit", "AWS Labs", "Google Workspace", "Atlassian", "Home Assistant", "Snowflake", "Neo4j", "Telegram"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/i-looked-at-1384-tools-across-28-mcp-servers-here-s-what-the-attack-surface-like", "markdown": "https://wpnews.pro/news/i-looked-at-1384-tools-across-28-mcp-servers-here-s-what-the-attack-surface-like.md", "text": "https://wpnews.pro/news/i-looked-at-1384-tools-across-28-mcp-servers-here-s-what-the-attack-surface-like.txt", "jsonld": "https://wpnews.pro/news/i-looked-at-1384-tools-across-28-mcp-servers-here-s-what-the-attack-surface-like.jsonld"}}