MCP security is the set of runtime controls that decide which agents may connect to Model Context Protocol (MCP) servers, which tools those agents may invoke, and how every call is attributed and logged. The protocol does not enforce those decisions: authorization is optional in the current specification (2026-07-28), STDIO servers pull credentials from the environment, and HTTP servers that opt in still leave audience binding, scope, and audit to the operator.
A CISO who already runs SSO, TLS, and an EDR fleet is being asked whether that stack covers Claude Code, Cursor, and Copilot calling tools against production. Companion pages cover the architecture of an MCP gateway, tool poisoning, prompt injection, and the NSA MCP security baseline. This page is the production checklist: six controls a security team requires of MCP.
Why does the protocol leave enforcement to the operator?
MCP is a messaging pattern for how an agent discovers tools, calls them, and reads the result. The authorization specification states that authorization is optional. Implementations using HTTP should follow OAuth 2.1, RFC 9728 Protected Resource Metadata, and RFC 8707 resource indicators. Implementations using STDIO should not follow that flow at all. They take credentials from the environment.
The honest objection is that the organization already terminates TLS and requires SSO at the client. TLS encrypts the channel. It does not bind a token to a named MCP server, and it does not record which tool ran. The spec forbids token passthrough: an MCP server must not accept a token issued for some other audience and forward it downstream. SSO at session start, if the session then carries a broad credential into every tool call, is ambient authority. That is the failure OWASP MCP02 (privilege escalation via scope creep) and MCP07 (insufficient authentication and authorization) name.
The NSA Cybersecurity Information Sheet of 20 May 2026, Model Context Protocol (MCP): Security Design Considerations for AI-Driven Automation, is 15 pages, from the NSA Artificial Intelligence Security Center, and advisory. It states that authentication, authorization, and input validation remain necessary, and that agentic MCP still requires controls those three do not supply. Our field read of the four operational requirements stays on that post: message integrity, per-call scope, a tamper-evident record, and a trust chain.
What does production MCP require?
A security team that will sign off on MCP in production is asking for six countable controls. They map onto the OWASP MCP Top 10 (v0.1, in beta) and onto the NSA baseline.
- Authentication bound to enterprise identity. Tokens issued for a specific MCP server (RFC 8707
resource), short-lived, with PKCE on the authorization code flow. No long-lived personal API keys inmcp.json. Closes MCP01 and MCP07. - An inventory of every MCP server an agent can reach. Registered servers, plus the ones that live only in a laptop dotfile. Closes the discovery half of MCP09.
- Tool allowlists. Named servers, named tools, named roles. A call that is not on the list is denied. Closes MCP02.
- An audit log of every invocation. Actor, tool, arguments, result, policy decision, timestamp. Exportable to the SIEM the organization already runs. Closes MCP08. The NSA baseline asks for that record to be tamper-evident.
- A kill path for shadow MCP. Unapproved servers found, disconnected, and kept off the next laptop image. Closes MCP09. The broader category is shadow AI.
- Inspection at the tool boundary. Tool descriptions, schemas, and results are untrusted input. That is where tool poisoning (MCP03) and prompt injection (MCP06, LLM01:2026) arrive.
A policy wiki that names these six and a runtime that does not enforce them is the same gap the NSA CSI flags: established cyber defense that does not see dynamic tool invocation.
How should MCP authentication work?
Start from the spec, then add the enterprise identity the spec does not name.
For HTTP MCP, the server is an OAuth 2.1 resource server. The client is an OAuth 2.1 client. On a 401, the client reads Protected Resource Metadata, discovers the authorization server (RFC 8414 or OpenID Connect Discovery), and runs the authorization code flow with PKCE (S256 when the client can). Every subsequent request carries Authorization: Bearer <access-token>. The token’s audience is that MCP server. The security best practices document flags confused-deputy risk when a proxy uses one static client ID toward a third-party API and skips per-client consent.
That is the protocol floor. Production adds three things the spec leaves to the operator:
- A named human. Map the agent session to the employee in Okta, Microsoft Entra ID, or Google Workspace. A service account shared across a team is MCP01 waiting to be copied out of a config file.
- Per-call scope. The NSA least-privilege requirement is that a read of one table does not authorize a write to another. OWASP MCP02 is the same idea from the other direction: temporary permissions that expand.
- No passthrough. If the MCP server calls an upstream API, it uses a token issued for that API. It does not forward the client’s token.
STDIO servers never enter this flow. They inherit whatever is in the process environment. A coding agent with a production GITHUB_TOKEN in the shell is carrying an identity grant. Those servers belong on the allowlist with a scoped, rotatable secret, or they do not belong on the laptop.
How do you inventory servers, allowlist tools, and log every call?
MCP configurations live in user-space files. They do not install an application, they do not open a well-known port, and they do not appear in a CMDB the way a sanctioned SaaS app does. Inventory that waits for a software record will report zero servers while fifty engineers have GitHub, Postgres, and a Discord-linked MCP in ~/.cursor and ~/.claude.
Inventory is a client-side problem first. Agent hooks on Claude Code and Cursor see the server name, the tool, and the arguments at PreToolUse. MDM (Jamf, Intune, Kandji, Fleet, JumpCloud) is how that hook configuration, and a reviewed server list, lands on the laptop at enrollment. The shadow AI page is the detection architecture. You cannot allowlist a server you have not named.
The allowlist is three columns:
| Column | What it names | What a miss looks like |
|---|---|---|
| Server | Hostname or package identity, pinned by hash | A rug pull on a server that passed review last quarter (MCP03) |
| Tool | get_customer is allowed; delete_customer is not | Ambient access to every function the server exported |
| Role | Which IdP group may call that tool | An intern’s coding agent with the same GitHub scopes as platform engineering |
A config-file allowlist that a developer can edit is an honor system. The deny has to happen on the path the tool call takes, or it does not happen.
The log is the evidence the SOC and the auditor will actually use. MCP08 asks for tool invocations, context changes, and user-agent interactions, with an immutable trail. A production record, per call, is:
- enterprise identity (user, group, agent client)
- MCP server and tool name
- arguments and result status (redact secrets; do not drop the fact of the call)
- policy decision (allow, deny, step-up)
- timestamp and correlation id that ties the tool call back to the prompt
Conversation logs from the model vendor cover the chat. They omit delete_repository at 14:03 UTC against the organization’s GitHub org. The NSA baseline’s third requirement is that this trail be signed and chained.
How do you close shadow MCP and inspect the tool boundary?
OWASP MCP09 names shadow MCP servers: unapproved instances spun up with default credentials, permissive configuration, or unsecured APIs. They are the MCP-shaped slice of shadow AI. Closing them is three operations, in order:
- See them. Hooks plus a registry of what was provisioned. The difference between those two lists is the shadow set.
- Stop them. Disconnect the server, revoke the secret, and refuse the next connection from that client.
- Keep them off the next image. MDM-provisioned agent config with a reviewed catalog. A laptop that ships with the approved GitHub server, and a policy path that ignores an extra URL in
mcp.json, is the durable fix.
A quarterly audit is not a control. The install takes thirty seconds.
Inspection at the tool boundary is a separate control because the payload does not come from the employee. LLM01:2026 Prompt Injection, published 4 August 2026 in the OWASP GenAI LLM Top 10, is explicit that tool output is an injection channel. MCP06 is prompt injection via contextual payloads. MCP03 is the MCP-specific form: instructions hidden in a tool description, a schema, or a later update (a rug pull). Model-layer classifiers watch the user prompt. They do not watch tools/list.
Treat tool metadata and tool results as untrusted input. Inspect descriptions and schemas before the model reads them. Pin versions by hash so a mutated description is a different object. Scope the call so a successful injection inherits a narrow grant. Worked examples live on the tool poisoning and prompt injection pages. The requirement here is that those inspections run on the same path as the allowlist and the log.
Simon Willison’s lethal trifecta is the containment test: private data, untrusted content, and an outbound channel. An MCP tool that can read a customer table and POST to an external URL has all three. An allowlisted tool that holds all three is an exception that should be named and recorded.
Where are these controls enforced?
The six controls all fire at the moment an agent calls a tool. The enforcement point is a proxy on that path: identity checked, allowlist evaluated, description inspected, call logged, then forwarded or denied.
That proxy is an MCP gateway. Architecture, the LLM-gateway distinction, and vendor comparison live on that page, once the six controls have owners.
The Speakeasy AI Control Plane is the platform that runs those controls in one place. Agents connect to Speakeasy-hosted MCP endpoints rather than to each upstream server. Authentication flows through the identity provider the organization already runs. Policy (which team, which server, which tool) is evaluated on every call. Agent hooks cover the coding-agent clients where STDIO and local tools never hit HTTP. Every invocation writes a structured event. Unregistered servers surface next to the governed ones, which is the shadow MCP list.
Acceptable-use policy stays in GRC. Okta stays the IdP. The platform is where the six controls run on the request, which is the gap the NSA CSI and the OWASP MCP Top 10 leave to the operator.
If the current state is fifty mcp.json files and a wiki page titled “AI acceptable use,” the next step is to name the six owners and put an enforcement point on the tool-call path.