MCP security

MCP security best practices

Security considerations for MCP start from one fact: an MCP server acts with your credentials, on the instructions of a model that reads untrusted text all day. These ten controls keep that arrangement safe across Claude, ChatGPT, Claude Code and Cursor.

Setting this up from a terminal? Read the developer guide

Why MCP needs its own controls

Security considerations for MCP

The Model Context Protocol gives an AI app a standard way to discover tools and call them. That is what makes it useful, and it is also what makes the security questions different from those of an ordinary API integration. The AI app does not call the tool; a model does, choosing the tool and composing the arguments from whatever is in its context, including text it has just read from the previous tool result.

Three things follow. The server runs with real credentials, often your own, so whatever the model asks it to do, it can do. The model's instructions can come from anywhere its context does, including web pages, tickets and documents fetched by other tools. And the configuration is scattered: each AI app on each machine keeps its own list of servers, its own copies of secrets and its own partial history, so there is no single place to see what is connected or what happened.

The ten practices below address those problems in turn: knowing and limiting what is connected (practices 1 and 2), containing what the model can be talked into (3), handling credentials and supply chain properly (4 to 6), and being able to see, control and prove what happened (7 to 10). They apply whether you run one MCP server in Claude Desktop or fifty across a team, and none of them needs a security team to start.

The ten MCP security best practices

Each practice closes a common class of incident. The pitfall under each one is the way it usually goes wrong in practice.

01

Know every MCP server on every machine and in every app

MCP configuration lives in many places at once: claude_desktop_config.json for Claude Desktop, .mcp.json at project and user scope for Claude Code, .cursor/mcp.json for Cursor, .vscode/mcp.json and user settings for VS Code, and account settings for ChatGPT connectors. Each entry can start a server on every launch, and project-scoped files travel with the repository to every laptop that clones it. Start by listing what is actually configured, per person and per app, and repeat the exercise whenever a team adopts a new AI app. You cannot apply least privilege to a server you do not know is there.

Common pitfall

A project .mcp.json committed months ago is still starting a server on every developer's laptop, and nobody remembers adding it.

02

Least privilege per tool: switch off what you do not use

A single MCP server often exposes dozens of tools, and the model may call any one that is visible to it. Most tasks need a handful of reads, not the full set of writes and deletes. Turn off the tools a workflow does not use, so that a wrong guess by the model, or an injected instruction, has nothing dangerous to reach for. A shorter tool list also means fewer tool descriptions in the prompt, which leaves less room for misleading ones and helps the model choose correctly.

Common pitfall

Connecting a full read/write server to answer read-only questions, with the delete tools left switched on.

03

Treat tool results as untrusted input

Whatever a tool returns, a web page, an issue comment, an email body, a database row, goes straight into the model's context, and the model cannot reliably tell data from instructions. Text planted in any of those places can tell the model to call another tool, leak what it has just read, or ignore its earlier instructions. The same applies to tool descriptions: a malicious or compromised server can hide instructions in the description the model reads before it calls the tool, a technique usually called tool poisoning. Limit what the model can do with any instruction it meets, keep high-impact tools such as send, pay and delete switched off or behind a warning, and check results for patterns that legitimate data would never contain.

Common pitfall

A read-only research server next to a send-email server is an exfiltration path, even though each is harmless on its own.

04

Keep secrets out of config files

The quickest way to get a server working is an API key in the env block of a JSON file in your home directory. That file is readable by every process running as you, is swept up by backups and sync tools, and is one careless commit away from a public repository. Keys in config files are also long-lived and rarely rotated, because rotating them means editing every laptop. Keep credentials in a vault or the operating system keychain, or hand them to one gateway connection so that no laptop holds the key at all.

Common pitfall

A project-scoped .mcp.json with a live token in it, committed because the file is meant to be shared.

05

Prefer OAuth to static tokens for remote servers

A static token is the same secret for everyone who holds it, for as long as it exists. An OAuth grant is bound to a user, scoped to what they allowed, expires, and can be revoked without touching anyone else. Where a remote MCP server supports it, connect through OAuth rather than pasting a token into a header. The MCP specification's authorization model is built on OAuth 2.1 with PKCE; the section further down explains what that means when you review a server.

Common pitfall

Pasting a personal access token into a shared team config to make a server work, then forgetting whose it was.

06

Pin and verify the servers you run

A local (stdio) MCP server is a program the AI app starts on your machine, with your user's permissions. A launch command such as npx -y some-package fetches whatever version the registry serves that day and runs it. Run servers from publishers you trust, pin versions, read the source of anything small, and be wary of unknown npm or pip packages with names close to popular ones. For remote servers, check who operates the endpoint and that it uses HTTPS, because you are handing it whatever credentials it needs to do its job.

Common pitfall

Installing an MCP server from a search result because it had the right name, and never checking who published it.

07

Record every tool call, with arguments, results and the policy outcome

The chat transcript is not an audit trail. Each AI app keeps its own partial history in its own format, tool results scroll past, and nothing ties a call to a policy decision. Record every tool call centrally: which user and which app called which tool on which server, with what arguments, what came back, and whether a policy blocked, warned or redacted. That record is how you answer "what did the agent do" after an incident, and it is the evidence a security or compliance review will ask for.

Common pitfall

Logging that a tool was called, but not its arguments or result, so an incident cannot be reconstructed.

08

Redact personal data at the boundary, before it reaches the model

Tools return more than the question needed: a customer lookup brings back phone numbers, dates of birth and addresses, not just a status. Everything in that result is sent to the model provider and kept in the conversation history. Redact at the point where the result leaves your systems, before the model sees it, with pattern rules for the formats you handle (card numbers, sort codes, National Insurance numbers, email addresses) plus detection for names and addresses. Asking the model politely not to repeat sensitive data is not a control.

Common pitfall

Redacting in the model provider's logs after the fact; the data has already left and the transcript still holds it.

09

Approval mode: new tools arrive switched off

An MCP server's tool list is not fixed. The server can add, rename or re-describe tools at any time, and the client simply picks up the new list. The server you reviewed with twelve tools can expose fifteen tomorrow, including a write you never agreed to. Treat every new tool as unapproved until a person has looked at it and switched it on, and treat a changed description as a new tool.

Common pitfall

Approving a server once and treating that as approval for every tool it will ever expose.

10

One governed connection for all your AI apps

Configuring the same servers separately in Claude, ChatGPT, Claude Code and Cursor multiplies every problem on this list: several copies of each credential, several places where tools can be switched on, several logs in several formats, and no single point to revoke anything. The gateway pattern puts one connection in front of all of them: the apps connect to one MCP URL, the gateway holds the credentials, applies the same tool switches and policies whichever app is calling, and writes one log. Governance then lives in one place instead of in every app on every laptop.

Common pitfall

Five copies of the same server configured five ways, with five keys, none of which can be revoked in one step.

Remote servers

MCP authorization: OAuth 2.1, PKCE and what to check

The MCP specification's authorization model applies to servers reached over HTTP. Local stdio servers are expected to take their credentials from the environment they start in, which is why practice 4 matters so much for them.

For remote servers the model is built on OAuth 2.1. The MCP server is the resource server: it publishes protected resource metadata that names the authorization server protecting it, the client discovers that server's endpoints, and the user signs in and consents through the normal browser flow. Where the authorization server supports dynamic client registration, a client such as Claude or Cursor can register itself with a server it has never seen before, which is why adding a new remote server does not always need a developer to register an app first.

Three details are worth checking when you review a remote server. PKCE is required for every client, so a desktop or browser app has no client secret to leak. The client must bind each token to the specific MCP server it is for, using the resource parameter, so a token issued for one server cannot be replayed against another. And the server must not pass your token through to the upstream API it wraps: it should hold its own credentials for that, so a compromise of one layer does not expose the next.

Where a remote server only offers OAuth and the AI app or in-house agent you are using cannot run the flow, a gateway can act as the OAuth client on your behalf and give the apps one connection of their own. Access tokens always travel in the Authorization header, never in a query string, and that applies to the gateway too.

FAQ

MCP security, answered

What are the main security risks of MCP servers?

Four stand out. Over-permissioned tools, where a server exposes writes and deletes that the task never needed. Prompt injection, where text in a tool result or a tool description steers the model into calling other tools or leaking data. Credential sprawl, where API keys sit in plain JSON on laptops and in repositories. And a missing audit trail, where nobody can say afterwards which tool was called, with which arguments, and what came back.

Is MCP secure by default?

No more than any other integration standard. MCP defines how an AI app and a tool server talk to each other; it leaves authentication, access control, tool permissions and logging to the server, the client and the people configuring them. A local server runs with your user's permissions, and the model calling it can be steered by text it reads. The specification includes an OAuth 2.1 based authorization model for remote servers, but adopting it, and the other controls on this page, is up to you.

How do you audit what an MCP tool call did?

You need a record made at the point where the call passes, not reconstructed from chat history afterwards. Each entry should hold the user, the AI app, the server and tool, the arguments, the result (redacted where it held personal data) and the policy outcome, with a timestamp. A gateway that every app connects through can write that record once, in one format, for every call. Without one, you are stitching together each app's own transcript files.

Should MCP servers share one API key across a team?

No. A shared static key cannot be attributed to a person, cannot be revoked for one leaver without breaking everyone else, and tends to be copied into more config files over time. Prefer OAuth where the server supports it, so each person has their own grant. Where a key is unavoidable, keep it in a vault or in one gateway connection rather than on each laptop, and record who made each call through it.

What is an MCP gateway?

An MCP gateway is a single MCP server that your AI apps connect to, which in turn connects to the real servers and tools behind it. Because every call passes through it, it can hold the credentials so the apps do not, switch individual tools on or off, apply policies that block, warn or redact, and log every call in one place. ContextGate is one example: Claude, ChatGPT, Claude Code, Cursor, Copilot and other MCP apps share one connection, and the same governance applies whichever app makes the call.

Are local (stdio) or remote MCP servers safer?

They carry different risks. A local stdio server is code running on your machine with your user's permissions, so the risks are supply chain (what you installed and from where) and secrets kept in config files. A remote server runs elsewhere, so the risks are who operates it, what credentials you hand it and how it authenticates you; the MCP specification's OAuth 2.1 model addresses the last of these. Neither is safe by default. Pin and verify local servers, and prefer OAuth and a known operator for remote ones.

Get started

Put one governed MCP connection in front of your AI apps

One URL for Claude, ChatGPT, Claude Code, Cursor and the rest. Keys in a vault, tools switched on one at a time, policies that block, warn or redact, and every call recorded. The free workspace is enough to start.