MCP server security basics: what to check before an agent gets a tool

An MCP server is a process that holds your credentials and does what a model asks. Most of its security comes down to what it can reach, who can talk to it, and what reaches the model.

14 October 2026 · 6 min read

The Model Context Protocol made it easy to hand an agent a tool: add a few lines to a config file and the model can query your database, read your repository or send a message. That ease is the point, and it’s also how a setup ends up running with an owner’s database URL and every tool switched on.

This post is the short list we’d want any team to check before an agent gets an MCP tool that touches real data. None of it needs a product. Most of it is about three questions: what can the server reach, who can talk to it, and what can reach the model.

What an MCP server is, from a security view

Strip away the protocol and an MCP server is a process that:

  • holds credentials (a database URL, an API token, a filesystem path),
  • exposes operations (tools) a model can call with arguments the model chooses,
  • returns results that go straight back into the model’s context.

That last point is the one people underrate. Whatever a tool returns, a database row, an issue body, a web page, becomes input to the model’s next decision. If any of that content was written by someone outside your team, it can carry instructions.

The lethal trifecta

Simon Willison’s post The lethal trifecta for AI agents (16 June 2025) describes the dangerous combination: access to your private data, exposure to untrusted content, and the ability to externally communicate.1 All three in one session means a crafted piece of content can ask the agent to read something private and send it somewhere, and the agent may comply.

General Analysis showed it in a July 2025 demonstration, with dummy data: a support ticket carrying instructions aimed at the developer’s assistant led an assistant using the Supabase MCP server under a service_role credential to read the integration_tokens table and add its contents as a new message in the same ticket, where the attacker could see it.2 The ticket was the attacker’s content, the service_role credential, which bypasses row-level security, was the private access, and the new message in the ticket, which the attacker could read, was the way out.2

The fixes below are mostly ways of taking one leg away.

1. Know exactly what you run

List every MCP server in every client config your team uses: .mcp.json, .cursor/mcp.json, ~/.cursor/mcp.json, Claude Desktop’s config. Claude Code’s claude mcp add --scope project stores a server in .mcp.json at the project root6, and Cursor reads .cursor/mcp.json in a project and ~/.cursor/mcp.json globally.7 A project file is shared through the repository, so it’s also where a teammate’s experiment becomes everyone’s tool.

For each server: who maintains it, which version you run, and whether it’s still maintained. Anthropic archived its reference Postgres server, @modelcontextprotocol/server-postgres, on 2025-05-28.5 Pin versions, and remove anything archived.

2. Give each server the narrowest credential

The server’s credential is the agent’s real permission set. Prompts, tool descriptions and client settings come after it.

  • A database server gets its own role, with only the grants its job needs, never the owner, a superuser or a key that bypasses row-level security (like Supabase’s service_role).
  • An API server gets a token scoped to one project and the fewest operations.
  • A filesystem server gets the one folder it needs, not your home directory.

Our post on safe Postgres access for agents has the tested SQL for the database case, including a gap that’s easy to miss: if the agent can send its own SQL, it can change its own session settings.

3. A read-only mode is not a boundary

Many database servers offer a read-only mode. Treat it as a second fence. Datadog Security Labs showed that the archived reference Postgres server’s read-only mode ran each query in a read-only transaction that a stacked COMMIT; ends, after which later statements run with the role’s full rights.4 With a role that holds only SELECT, the same trick gets nothing. Put the boundary in the credential.

4. Lock down local HTTP servers

An MCP server that speaks HTTP on your laptop is reachable by any web page your browser opens, unless it checks. The MCP specification says servers must validate the Origin header and answer 403 when it’s present and invalid, and should bind to localhost when running locally.3 Check both for every HTTP server you run, and prefer stdio for local servers when you can: a server your client starts over stdio talks to it through the process’s input and output, not through a network port.

5. Split the trifecta

Look at each agent session and ask which legs it has:

  • Private data: database tools, file access to code or secrets, email or CRM tools.
  • Untrusted content: web fetch, issue trackers, support tickets, inbound email, any table customers can write to.
  • A way out: anything that sends: HTTP requests, email, chat messages, comments, even creating an issue.

Then split them. The agent that reads support tickets doesn’t get the database tool with customer records; it gets a narrow tool that looks up one order by id. The agent that can query everything doesn’t get web fetch or a send tool. Separate sessions, separate configs, separate credentials.

6. Decide destructive tools outside the model

Client-side approval prompts help, but they can be clicked through or switched off. For tools that change data:

  • Hide what the agent never needs. A tool the agent can’t see can’t be called.
  • Refuse destructive operations outright, with a rule that runs outside the model: DROP, TRUNCATE, deletes without a WHERE, deleting a volume.
  • Require a person for the few writes that matter, with the exact arguments shown.

In Deedglass, rules decide each tool call before it runs, a person can approve in Slack, email or the Console, and each action is sealed into a record.9 Putting an existing server behind those rules is one wrapper in the client config:

deedglass mcp wrap --connector <name> -- <server command>

The client then lists the server’s tools, and the tools a rule denies are hidden.

7. Isolate and record

Isolate the process. Run servers with the least the operating system will give them: their own user, a container, no access to your home directory or SSH keys. Docker’s MCP Gateway, for example, runs each server in an isolated container with restricted privileges and logs and traces calls.8

Record what happened, not just what was asked. A trace of tool calls tells you the model asked for UPDATE … WHERE id = 42. It doesn’t tell you what the database committed. For tools that write, record the result from the system of record, and keep the record somewhere the agent’s credentials can’t edit.

A short version to paste into your team’s notes

  1. Inventory every MCP server and pin its version; drop archived ones.
  2. One narrow credential per server; never owner, superuser or RLS-bypassing keys.
  3. Read-only modes are a second fence; the credential is the boundary.
  4. Local HTTP servers bind to localhost and check Origin; prefer stdio.
  5. No session gets private data, untrusted content and a way out together.
  6. Destructive tools are hidden, refused or approved by a person, outside the model.
  7. Servers run isolated; results are recorded from the system of record.

To see rules hide and refuse tools in front of a real Postgres, try the playground. To list the MCP servers and write-capable tools in your own setup, run the free scan, npx deedglass scan; it reads your client configs locally, nothing leaves your machine, and the grade is explained here.

Sources

  1. 1Simon Willison: The lethal trifecta for AI agents · simonwillison.net · checked 14 October 2026
  2. 2General Analysis: Supabase MCP can leak your entire SQL database (8 July 2025) · generalanalysis.com · checked 14 October 2026
  3. 3MCP specification 2026-07-28: Streamable HTTP transport · modelcontextprotocol.io · checked 14 October 2026
  4. 4Datadog Security Labs: SQL injection in the Postgres MCP server · securitylabs.datadoghq.com · checked 13 October 2026
  5. 5modelcontextprotocol/servers-archived on GitHub · github.com · checked 5 October 2026
  6. 6Claude Code documentation: Connect Claude Code to tools via MCP · code.claude.com · checked 13 October 2026
  7. 7Cursor documentation: Model Context Protocol · cursor.com · checked 13 October 2026
  8. 8Docker documentation: MCP Gateway · docs.docker.com · checked 13 October 2026
  9. 9Deedglass docs: Govern an MCP server · docs.deedglass.com · checked 14 October 2026

Published 14 October 2026, last checked 14 October 2026. If something here is out of date, write to hello@deedglass.com.

Try it on your own setup

npx deedglass scan

Grades only your own setup. Nothing is uploaded. The package opens with the public release.

Pricing