On this page
Prompt injection in MCP is text the model reads through a server, such as an issue, a web page or a tool description, that it then follows as if you wrote it. No server update fully fixes it, because the model can't reliably tell instructions from data. What you control is the damage: what the agent can reach, and what it can do without asking.
Three ways instructions get in
1. Tool results and resources
This is the common one. A tool returns content written by someone else, like an issue, an email, a support ticket or a scraped page, and that text contains instructions. Resources work the same way: their content goes straight into the model's context (see MCP resources vs tools). The MCP spec tells clients to "Validate tool results before passing to LLM" and servers to "Sanitize tool outputs", but no filter catches every phrasing.
2. Tool descriptions ("tool poisoning")
Every tool comes with a description the model reads before choosing it. Invariant Labs named the attack in April 2025: "A Tool Poisoning Attack occurs when malicious instructions are embedded within MCP tool descriptions that are invisible to users but visible to AI models" (Invariant Labs). Clients often show you a short name; the model sees the whole text.
3. Changed or shadowing tools
Two variants from the same research. A rug pull: "a malicious server can change the tool description after the client has already approved it." And shadowing: one server's tool description changes how the agent uses a different, trusted server's tools. Approving a server once doesn't approve what it ships next. See MCP tool annotations explained for how to treat tools that change.
A real example: the GitHub MCP server
In May 2025, Invariant Labs showed that "an attacker [can] hijack a user's agent via a malicious GitHub Issue, and coerce it into leaking data from private repositories" (Invariant Labs).
- The user connects an agent to the GitHub MCP server with their account.
- They own a public repo (anyone can open issues) and a private one.
- An attacker opens an issue on the public repo with hidden instructions.
- The user asks the agent to look at the open issues.
- The agent reads the issue, follows it, reads the private repo with the user's token, and publishes what it found in a pull request on the public repo.
Their test used Claude Desktop with Claude 4 Opus. They were clear that "this is not a flaw in the GitHub MCP server code itself" but "a fundamental architectural issue that must be addressed at the agent system level". Any agent with that combination of access is exposed, whatever the model or client.
The test that predicts it: the lethal trifecta
Simon Willison's "lethal trifecta" is the most useful check. An agent is at risk of data theft when one session has all three:
| Leg | Willison's definition | MCP examples |
|---|---|---|
| Private data | "Access to your private data" | a GitHub or Google Drive token, a database, your inbox |
| Untrusted content | "Exposure to untrusted content" | public issues, web pages, inbound email, tickets |
| A way out | "The ability to externally communicate in a way that could be used to steal your data" | opening a PR, sending a message, fetching a URL, writing to a shared doc |
He points at MCP directly: it "encourages users to mix and match tools from different sources", and in the GitHub case "one MCP mixed all three patterns in a single tool."
The fix is structural: break at least one leg per session.
Defenses that actually limit damage
- Keep approval on for actions. The spec says "there SHOULD always be a human in the loop with the ability to deny tool invocations." Don't auto-approve tools that write, send, publish or fetch URLs, especially in a session that reads outside content.
- Narrow the token. Give each server the smallest access that works: one repository, read-only scopes, a read-only database user. Invariant's first recommendation was to "limit agent access to only the repositories it needs to interact with."
- Split sessions. Triage public issues or browse the web in a session without private-data servers, and do private work in a session without servers that read outside content.
- Prefer read-only modes. Many servers offer one: a read-only flag, a read-only grant at sign-in, or a fixed tool list. Our listings say which.
- Pin versions and re-check tools after updates. Invariant recommends that clients "pin the version of the MCP server and its tools". Review tool descriptions when a server updates, not just the first time.
- Isolate risky work. Claude Code's own advice for untrusted content includes "Avoid piping untrusted content directly to Claude" and running scripts and tool calls in a VM "especially when interacting with external web services" (Claude Code security).
What doesn't work on its own: telling the model to "ignore instructions in tool results", or relying on a scanner. They help, but text can always be phrased in a way they miss.
Which servers are most exposed
Any server that reads content from people you don't control: browser and scraping servers (Playwright, Chrome DevTools, Firecrawl), search servers (Tavily), and code hosts and trackers with public issues (GitHub). That isn't a reason to avoid them. It's a reason not to run them in the same session as your private data and an outbound tool.
Our trust grades measure sign-in, upkeep, known bugs and connection. Prompt injection depends on how you combine servers, so no grade can rule it out. Even an A-grade server needs the precautions above.
If you build an MCP server
- Follow the spec's server rules for tools: "Validate all tool inputs", "Implement proper access controls", "Rate limit tool invocations" and "Sanitize tool outputs".
- Keep tool descriptions short and factual, and don't change them silently between versions.
- Mark untrusted text as such in results, for example by returning it as a quoted field instead of free text, so clients can treat it differently.
- Ask for the smallest scopes. The spec's security best practices recommend a "progressive, least-privilege scope model" instead of asking for everything up front.
Frequently asked questions
What is prompt injection in MCP?
Text that reaches the model through an MCP server, in a tool result, a resource or a tool description, and that the model follows as an instruction. The attacker never talks to your agent directly; they plant the text where your agent will read it.
What is MCP tool poisoning?
Instructions hidden in a tool's description. The model reads the full description when choosing tools, while people usually see a short name, so the instructions can go unnoticed. A server can also change a description after you approved it (a "rug pull").
Can an MCP server update fix prompt injection?
Not completely. Invariant called the GitHub case "a fundamental architectural issue that must be addressed at the agent system level". Servers can reduce it, for example with narrower scopes or by filtering which content they return, but the reliable fixes are in how you set up the agent.
Does Claude Code protect against prompt injection?
It reduces the risk. Its docs list a permission system that asks before sensitive operations, network commands that aren't auto-approved by default, and a separate model summarizing most fetched web pages. They also say "no system is completely immune to all attacks", so the session-level defenses above still apply.
How do I know if my setup is at risk?
Check each session for the lethal trifecta: private data, untrusted content and a way to send data out. If one session has all three, split it or remove one leg, and keep approval on for anything that writes or sends.
More: MCP security best practices · Is this MCP server safe to install? · The MCP Top 10