MCP security checklist: 10 controls for AI agent tools
The Model Context Protocol makes it easy to hand an AI agent a new tool: a database, GitHub, Stripe, Slack. Each server you add is new access, and every public MCP incident so far follows from that. Here is the checklist we use, built from the incidents we replay in our benchmark.
Before you connect a server
- Keep an inventory. Know which MCP servers each agent can reach, on every developer machine and in every pipeline. You can't control a path you don't know about.
- Verify the publisher and pin the version. In September 2025 a copycat
postmark-mcppackage quietly added an attacker's address as a BCC on every email it sent. Install from the vendor, pin versions, and review updates. - Use least-privilege tokens. Give the server a token scoped to what the agent needs, read-only where you can, and keep it on a gateway rather than in the agent's environment where the model can see it.
While agents use it
- Treat everything a tool returns as untrusted. In May 2025 a crafted GitHub issue got an agent using the GitHub MCP server to read private repositories and publish them in a public pull request. In July 2025 a support ticket got an agent with the Supabase MCP server to read secret integration tokens and post them into the ticket. Text from issues, tickets, emails and web pages can carry instructions.
- Watch reads followed by writes. The dangerous pattern is "read something sensitive, then send it somewhere". Flag any write to the outside world that follows outside content or a sensitive read in the same session.
- Protect the agent's own configuration. CVE-2025-54135 (CurXecute) let a Slack message rewrite
Cursor's
~/.cursor/mcp.json. CVE-2025-53773 let Copilot turn on its own auto-approve in.vscode/settings.json. Edits to agent config, hooks and permission files should always need a person. - Hold irreversible and outward-facing calls. Deletes, payments, refunds, messages, posts and bulk exports wait for an approver who sees what will happen. Reads and routine calls run on their own.
- Default unknown tools to "ask". A new server's tools shouldn't be trusted just because they were connected. Hold them until you've written a rule.
Afterwards
- Log every call, redacted. Tool, input, result, decision, rule and approver, with secrets and personal data masked before storage, in a tamper-evident log you can export for an audit.
- Know what a gateway can't see. A compromised server can add a side effect after a person approves the visible call; the postmark BCC is exactly that, and it's the one incident Squidbrake doesn't stop. For servers you don't trust at all, add a sandbox and egress limits.
Putting an MCP server behind a checkpoint
With Squidbrake, wrapping a server routes every call through your rules before it reaches the tool:
squidbrake proxy --app linear --url https://mcp.linear.app/mcp squidbrake proxy --app stripe -- npx -y @stripe/mcp --tools=all
The server's token stays on the gateway, every call is checked and recorded, and held calls go to a person in the dashboard, Slack or on their phone.
Try it on your own agents. pipx install squidbrake, then
squidbrake connect all. Start in shadow mode: nothing is blocked in week one, you see what would have been.
Quickstart · Benchmark · Book a demo