MCP security risks, best practices and a checklist
On this page
MCP security means protecting the tools, data and credentials an AI agent can reach through the Model Context Protocol. The main risks are prompt injection, tool poisoning, changed tool definitions, over-broad access, token passthrough and credential theft, server-side request forgery, untrusted local servers, and missing audit trails. You reduce them by connecting reviewed servers, giving each agent only the tools it needs, using narrowly scoped credentials, and requiring a person to approve sensitive actions. Each risk is controlled at a different layer: the client, the MCP server, a gateway or the upstream account.
This guide draws on the MCP security best practices and the OWASP MCP security cheat sheet, and was checked against MCP specification revision 2026-07-28 on 30 October 2026.
How MCP changes the threat model
MCP standardizes how AI applications connect to tools and data, and those connections cross several trust boundaries at once. External content such as tickets, emails and web pages enters the model's context as text, and the model can't reliably tell an instruction hidden in it from your request. Servers publish tool names, descriptions and schemas that clients pass to the model, and instructions planted there can steer its behavior, including its calls to other servers' tools.
Then there are credentials. A tool acts with whatever its credential and upstream account allow, so broad scopes or an admin role raise the cost of any manipulated call. Ask what an agent could do with its tools if the model were tricked. The tools and accounts you connect decide that far more than the choice of model.
The main MCP security risks
| Risk | What goes wrong | Where to control it |
|---|---|---|
| Prompt injection | Untrusted content tells the model to misuse a tool it's allowed to call | Fewer tools, approval for risky ones, least-privilege accounts |
| Tool poisoning | A server's tool descriptions or results carry hidden instructions | Choosing servers, reviewing tool lists, client and gateway rules |
| Rug pulls | A server changes its tools after you approved it | Exact tool lists, comparing definitions, pinned versions |
| Over-broad access | An agent holds tools and accounts its job doesn't need | Per-agent allowlists, upstream scopes |
| Token passthrough | A server forwards a client's token to another API | Server design; a gateway that uses its own upstream tokens |
| Credential sprawl and theft | Long-lived tokens copied into config files on many machines | Central credential storage, short-lived OAuth tokens, revocation |
| Confused deputy | A proxy reuses an earlier consent to get tokens for a new client | Per-client consent in the proxy |
| SSRF | A server-side client is steered to internal addresses | Destination checks in servers and gateways |
| Local server compromise | A one-click config or install runs an arbitrary command on your machine | Client consent prompts, sandboxing, reviewed packages |
| No audit trail | Nobody can say what an agent called | Central activity logs |
MCP prompt injection
Prompt injection is text that tries to give the model new instructions. With MCP it usually arrives indirectly, inside something a tool returns. In May 2025, Invariant Labs showed an agent using the GitHub MCP server reading a malicious issue in a public repository, then copying data from the user's private repositories into a public pull request. The server had no bug to patch. The agent simply held access to both kinds of repository at once.
No layer can reliably detect injected instructions, so the defenses limit what an injected instruction can achieve:
- Give each agent only the tools its job needs. An agent that reads tickets doesn't need to send email.
- Require a person to approve tools that send, publish, pay or delete, so a manipulated call stops before it runs.
- Keep untrusted input and sensitive tools apart. Simon Willison calls the combination of private data, untrusted content and a way to send data out the lethal trifecta. In General Analysis's Supabase demonstration, a support ticket told a coding agent to read a table of integration tokens and post them back into the ticket. Removing any one of the three closes that path.
- Use upstream accounts that can't do more than the job requires.
MCP tool poisoning
The OWASP description of tool poisoning covers a malicious or compromised server that hides instructions in its tool descriptions, parameter schemas or results. Because clients show the model every connected server's descriptions, a poisoned server can influence calls to other servers' tools without its own tool ever running. That variant is called tool shadowing. A 2026 study showed that text written in Unicode tag characters has no visible glyph in common terminals, chat apps and IDEs, so a payload can be missing from the approval view and still reach the model word for word. Reading a description in your client doesn't prove what the model sees.
Defenses start with which servers you connect:
- Prefer official servers from the vendor whose data they touch, and check the URL or package name before adding one.
- Read a server's tool list before granting it, for example with the MCP Inspector.
- Tool annotations such as
readOnlyHintanddestructiveHintare set by the server's author. The MCP specification says clients must treat them as untrusted unless the server is trusted.
Rug pulls
A rug pull is a server that changes after you approved it. A new destructive tool appears, an allowed tool's description gains hidden instructions, or a package update adds malicious code. The postmark-mcp package on npm shipped fifteen clean versions before one that quietly copied every email it sent to an outside address.
Different controls catch different changes:
- New tools. Listing tools by exact name keeps a newly added tool unavailable until someone reviews it. Rules that grant a whole server pick it up silently.
- Changed definitions. An exact-name list doesn't notice when an allowed tool's description or schema changes. Snapshot each server's tool definitions and compare them on a schedule, and review any change before agents keep using the tool.
- Changed code. For local servers, pin package versions and update deliberately.
Over-broad access
A GitHub server can expose dozens of tools, from searching code to deleting repositories, while most agents need a handful. Every extra tool widens what prompt injection, a model mistake or a poisoned description can do, and it's the risk you control most directly.
Apply least privilege twice:
- Tools. Allowlist the tools each agent needs and block destructive ones explicitly. The MCP allowlist guide shows how in Claude Code, Cursor, Codex, VS Code and at a gateway.
- Accounts. Connect upstream accounts with the narrowest role and scopes that work. A tool allowlist limits which tools run. The account behind them still decides what each one can reach.
Token passthrough
An MCP server that receives a client's token and forwards it to another API is doing token passthrough, which the MCP authorization specification forbids. Servers must accept only tokens issued for them, and use a separate token for any API they call. Passthrough lets a token stolen at one service work at another, and downstream logs show the wrong caller.
If you build servers, validate the audience of every token. If you buy a gateway, check that it calls upstream servers with the connection's own credential, never the agent's token. MCP authentication explains the token audience rules.
Credential sprawl and theft
Without central management, every developer stores a token for each server in a config file or environment variable. Tokens get committed to repositories, outlive the people who created them, and are hard to rotate.
- Prefer MCP OAuth sign-in, which usually issues short-lived, revocable access tokens, over long-lived personal tokens.
- Keep credentials out of project config files that are committed.
- Store shared credentials in one place, encrypted, where you can revoke an agent without rotating the account.
To find the tokens already sitting in local configs, run the free MCP config audit, npx toolstile audit, on each machine.
Confused deputy
This affects MCP proxy servers that use one static client ID with a third-party authorization server while letting MCP clients register dynamically. If the third-party server remembers an earlier consent, an attacker's client can get an authorization code without the person seeing a new consent screen. The specification requires such proxies to get consent for each client. The security best practices add the details: show which client is asking, match redirect URIs exactly, and set the state cookie only after consent. If you only use MCP servers, check that a new app always triggers its own consent screen.
Server-side request forgery
A server-side MCP client, such as a hosted agent or a gateway, fetches URLs it learns from servers: metadata documents, authorization servers and the MCP endpoints themselves. A malicious server can point those at internal addresses such as 169.254.169.254 or localhost to reach cloud metadata services or internal admin pages.
The best practices recommend requiring HTTPS outside local development, blocking private, loopback and link-local address ranges, not following redirects blindly, and pinning the DNS result between the check and the connection, because a hostname can resolve to a different address the second time.
Local server compromise
A local stdio server is a program running with your user's permissions, and a one-click install link or a copied config entry can run any command. The security best practices require clients that offer one-click setup to show the full command and get explicit approval before running it, and recommend sandboxing.
Local helper tools carry risk too. CVE-2025-6514 in mcp-remote, a bridge many clients used to reach remote servers, let a malicious server run commands on the user's machine through a crafted authorization URL. Run local servers and bridges from packages you trust, keep them updated, and don't give them filesystem access they don't need.
No audit trail
When an agent does something surprising, you need to know what it called, with which account and when. Client-side logs live on each laptop. Keep a central record of tool calls with the agent, server, tool and outcome, and decide deliberately whether to store arguments and results, which may contain sensitive data.
Hardening checklist for MCP builders
If you build MCP clients or servers, the security best practices add a few rules on top of the risks above:
- Validate authorization URLs in clients. Open only
httpsURLs (andhttpon loopback during development), reject schemes such asjavascript:andfile:, and never open a URL through a shell command. This is the class of bug behind CVE-2025-6514. - Don't treat state handles as authentication. Revision 2026-07-28 removed protocol sessions, and servers that hand out handles for cross-call state must still authenticate every request and bind each handle to its user.
- Minimize scopes. Start with a small scope and ask for more through a
403 insufficient_scopechallenge when an operation needs it, rather than requesting everything up front. - Validate inputs and limit load. Check tool arguments against the schema and your own rules, and cap request size, execution time and call rate.
- Protect HTTP endpoints. The Streamable HTTP transport requires servers to validate the
Originheader to prevent DNS rebinding, and local servers should bind to127.0.0.1rather than every interface.
What a gateway can and can't fix
A gateway helps with over-broad access, destructive calls, credential sprawl, revocation and audit trails, and can block SSRF destinations centrally. It doesn't stop prompt injection, decide which servers you trust, or govern local servers and direct connections. The MCP gateway guide covers that split.
How Toolstile reduces MCP risk
Toolstile is a managed MCP gateway for remote MCP servers.
- Per-agent access. Each agent authorization starts with no access. For each connection you set tools to Allow, Require approval or Block, and a block wins over any allow, including full access from a broader policy. Discovery and every call are checked against the same rules. See per-agent permissions.
- New tools stay closed. When you list tools by name, a tool a server adds later stays unavailable until someone allows it.
- Approval for risky calls. A call that requires approval returns a review link. The approval covers that exact call and arguments.
- No token passthrough. Agents' tokens work only at Toolstile. Upstream calls use the connection's own credential, which is encrypted at rest and never shown to the agents that use it.
- Network boundaries. Toolstile connects only to public HTTPS servers on port 443, rejects private-network and localhost destinations after resolving the address, and doesn't follow upstream redirects.
- Activity. Every operation is logged with its agent, connection, tool and outcome. Capturing arguments and results is off by default; a capture session stops after one hour unless extended, and its contents expire within 24 hours.
Security and data handling describes storage, retention and the limits of these controls, and pricing shows which plans include reusable policies and longer retention.
MCP security checklist
- Inventory which MCP servers each AI app uses, including local ones.
- Connect official servers where they exist, and read each server's tool list before granting it.
- Give each agent only the tools its job needs, by exact name.
- Block destructive tools explicitly, and require approval for tools that send, publish, pay or delete.
- Keep untrusted input, private data and outbound tools out of the same agent where you can.
- Use least-privilege upstream accounts and short-lived OAuth tokens.
- Keep credentials out of committed config files, and be able to revoke one agent without rotating an account.
- Check that no server or gateway forwards client tokens upstream.
- Review new tools and changed tool definitions before agents use them, and pin local package versions.
- Log every tool call centrally, and capture payloads only when you need them.
To apply these controls with Toolstile, start with getting started with a first connection.