An MCP server exposes tools to agents, and each tool calls another system with the server’s own credential. That makes the server an identity in its own right, and its reach is inherited by every agent allowed to call it.
{
"servers": {
"crm": {
"command": "npx",
"args": ["-y", "crm-mcp-server"],
"env": { "CRM_TOKEN": "••••••" }
}
}
}Published Last reviewed
MCP server security is about one question: what can this server reach, and who can make it reach. The protocol gives an agent a clean way to call tools. It does not change the fact that each tool calls another system with a credential, and that credential is where the access actually lives.
This is why a server with ten careful agents in front of it is not safer than its own token. For the protocol risks themselves, step by step, read the MCP security checklist. This page is about the server as an identity.
Every agent that calls a server inherits everything that server’s credential can reach.
Not protocol flaws. These are properties of how servers are configured and shared in real environments.
Every tool the server exposes calls another system with the server’s own key, token or service account. Ten agents calling one server all act with that identity, so the server’s reach is the reach of all of them, and its log lines cannot be attributed to any of them.
A local server is configured in a file with an env block, and the token goes in that block. The file lives on a developer machine next to the agent, which means anything that can read the machine can read the token, including the agent itself.
A server with six tools usually holds one credential wide enough for all six. The read-only summary tool and the write-anything tool share it, so using the harmless tool and using the dangerous one are the same permission.
An agent decides which tool to call from the descriptions the server returns. A server you do not control therefore gets to influence the agent’s behaviour, which makes server provenance an access question rather than a preference.
A server added to try something out keeps its entry in the config and its credential in the env block. It is the most common way an MCP server becomes a shadow agent with standing access.
The common question is which one is safer. The useful question is which failure you would rather be able to detect.
| Local server | Remote server | |
|---|---|---|
| How it runs | As a process on the user machine, usually over stdio. | Over HTTP, operated by somebody else. |
| Where credentials live | In the config file, often plain text in an env block. | With the operator, reached through OAuth or an API key. |
| What to check first | Which machine holds the file, and what else can read it. | Which scopes the grant carries, and who the operator is. |
| What a compromise reaches | Everything readable on that machine, plus the token’s own reach. | Every customer of that server, through the operator. |
| Who can revoke it | The developer, by editing the file. | You, by revoking the grant, if you know it exists. |
In this order. Step one is the one most teams skip, and it is the one that makes the rest possible.
Search for MCP configuration on the machines and in the repositories that matter: the config files agents read, and workflow files that start a server in CI.
One credential per server, and where the client supports it one per agent and server pair, so rotating one does not break the rest and the log says who called.
Decide the scope from the tools you actually use, not the tools the server offers. A server you only read from does not need a credential that can write.
Use the client’s secret storage or a short-lived credential where the server supports it. Where it does not, record that as an accepted risk with an owner rather than leaving it undocumented.
One server in the middle, every agent that calls it and the data behind its token.
Short answers on securing Model Context Protocol servers.
In practice yes. It calls other systems with credentials such as API keys, OAuth tokens or service accounts, and those credentials define what it can reach. Treating it as an identity rather than as a tool is what makes the access question answerable.
Neither by default, they fail differently. A local server puts a long-lived token on a developer machine, so the question is what else can read that machine. A remote server moves the credential to an operator, so the question becomes what a breach at that operator would reach across all of their customers.
Start with the configuration files the clients read, then the repositories and CI workflows that start servers, then the model provider and API keys that appear with new client identifiers. The first list will be incomplete, which is itself the finding.
The pages that belong to the same picture.
Book a demo and we walk through the access paths in an environment like yours.