MCP Security: Threats, Controls and Verification
MCP security controls for tokens, tools, discovery, sessions and execution, with a threat matrix and runnable reference tests for request-bound authorization.
MCP security protects the boundaries between a client, its model context, MCP servers and the systems those servers can reach. Start by authenticating the intended caller, validating the token's intended resource, limiting available tools and checking each consequential action before execution. Add controls for discovery URLs, untrusted tool content, sessions, credentials and uncertain outcomes. A successful MCP connection does not establish permission for every business action.
This guide is for engineers implementing or evaluating MCP connections. It owns the protocol-security topic; the MCP gateway guide covers gateway architecture and selection, while the AI agent authorization guide covers permission for the exact business request. Use the three together without treating any single component as the complete security boundary.
MCP security boundaries and threat model
Inventory the components that can introduce data, grant access or cause an external effect. Include local servers launched as processes, remote servers reached over HTTP, identity providers, gateway operators, tool registries and downstream APIs. A server description, tool response or retrieved document is an input to assess, not an authority to expand the agent's permissions.
Untrusted documents and tool descriptions
| data, never permission
v
Client and model -> authenticated MCP boundary -> approved server
| |
exact tool/action policy separate downstream access
| v
approval and reservation -> protected business system
|
outcome and reconciliation evidence
The official MCP security guidance addresses confused-deputy behavior, token passthrough, SSRF and session attacks. The controls below combine those protocol concerns with an original enterprise-action design. The business approval and operation-state model is not an additional requirement imposed by the MCP specification.
Threat and control matrix
| Threat | Enforcement point | Acceptance test | Recovery owner |
|---|---|---|---|
| Token intended for another resource | Resource server authentication | Reject before tool dispatch | Identity team |
| Forged or missing principal context | Authentication adapter | No tool access with unverified identity | Identity team |
| Tool invocation exceeds approved purpose | Action authorization | Denied call never reaches upstream | Security and process owner |
| Tool arguments change after approval | Request normalization and approval binding | Changed payload invalidates approval | Process reviewer |
| Discovery or redirect reaches private services | Outbound network boundary | Block disallowed destination on every hop | Platform team |
| Session identifier reused by another caller | Session and principal binding | Different caller cannot inherit access | Server operator |
| Tool output tries to expand authority | Agent runtime plus external enforcement | Untrusted instruction cannot unlock a new tool | Application team |
| Outcome lost after dispatch | Durable operation state | Retry reconciles rather than blindly repeating | Operations team |
Assign each row to an actual component. A product name in a diagram is insufficient: identify the configuration, its owner, how it is deployed and what happens when the dependency is unavailable. Also check direct routes around the enforcement point. A tightly configured proxy cannot constrain credentials that let the agent contact the upstream system independently.
Token and downstream credential separation
Use the MCP authorization specification, version 2025-11-25, for HTTP transport authorization requirements. Validate that access is intended for the resource receiving it. Do not accept a token simply because it is well formed or because some trusted issuer signed it. Issuer, recipient, expiration and required permissions have separate meanings.
For a proxy calling a downstream API, design downstream access independently. The official security guidance prohibits the token-passthrough pattern it describes. A credential accepted at one boundary must not silently become a general credential for every service behind it. Keep reusable secrets outside model inputs, generated text and tool results. Review traces and error responses for accidental credential exposure.
The downloadable lab below deliberately starts after identity verification. Its verified field is an injected test premise, not a cryptographic check. In a real integration, derive principal context from a validated credential and trusted server-side state. Never accept a client's claim that its own identity or approval has already been verified.
A tested reference configuration
Download the agent control lab 1.0.0. It contains a small policy engine, tests, a synthetic signed evidence fixture and a verifier. Extract the archive and run the commands with Node.js 20 or later. There are no dependencies or network calls.
node --test lab.test.mjs
node verify.mjs evidence.json demo-public-key.pem
The reference policy in control.mjs permits one tool, one tenant, one agent and one destination. Its example configuration is:
const policy = {
audience: 'https://gateway.example.test/mcp',
tenant: 'example-lab',
agent: 'evidence-worker',
tool: 'publish_evidence_draft',
destination: 'https://records.example.test/drafts',
maxBytes: 4096,
};
These addresses are test labels. The policy is executable configuration for the reference simulator, not configuration for Kong, Portkey or another vendor. It demonstrates how one authorized action can have a small, explicit surface. The request digest binds a fixed tuple of tenant, agent, tool, destination, body and idempotency key. The encoding is specific to this example and is not an OATI or JCS profile.
The suite tests a permitted draft, a matching retry, changed content, cross-tenant access, prohibited tools, invalid approval, outages and a timeout after dispatch. Denied fixtures assert zero simulated upstream dispatches. The timeout case remains uncertain and a retry does not call the stub again. These properties are useful acceptance criteria to carry into an integration test against the real gateway and protected system.
Discovery, sessions and local servers need separate tests
The lab does not implement network discovery, a DNS resolver, HTTP redirects, OAuth, an MCP transport or process isolation. Add tests for those surfaces instead of describing a passing policy unit test as end-to-end MCP security.
For discovery, enumerate every URL your implementation retrieves. Check allowed schemes and destinations, resolved addresses, redirects and connection-time behavior. A hostname check before DNS resolution does not by itself establish that the eventual connection is safe. Restrict network reachability as well as application configuration. Record blocked attempts without logging credentials in the requested URL.
For sessions, bind session state to the authenticated caller and required resource context. Exercise reconnection, expiration, identity change and concurrent clients. Avoid treating possession of a session identifier as independent permission to use tools. For local servers, review the executable, version, launch arguments, environment variables, filesystem access and inherited credentials. A local process can have a substantial attack surface even when no remote endpoint is exposed.
Failure behavior and release evidence
Write down the safe state for each dependency failure. A missing policy result should not be translated into permission for a consequential write. When an upstream response is lost, preserve the operation identifier and distinguish an unknown result from a rejected request. Reconcile against the protected system before deciding whether another execution is safe.
Store enough evidence to explain the decision and subsequent observation: principal reference, normalized request digest, policy version, approval reference, operation identifier, dispatch status and observed outcome. Minimize sensitive payload capture. The audit-trail guide explains why a valid signature establishes integrity under a key but does not establish that every signed assertion is true.
Before release, rerun the tests after tool-schema, authentication-library or policy changes. Observe the protected system directly during denied cases. Include bypass routes and operator access in the review. The reference simulator uses an in-memory map in one synchronous process; it does not prove distributed atomicity, crash recovery, durable evidence retention or production readiness.
Current implementation boundary and next action
Intelliger's Agent Trust architecture separates reasoning from authorization and execution. OATI remains a developer preview. The reference lab is educational material, not the deployed OATI service or a certified implementation. Independent security review and tests of your actual environment remain necessary before a production release.
Start with the downloadable lab, then map each acceptance criterion to the component that will enforce it. For whole-system risks, continue to AI agent security. The guide library and Agent Trust overview provide the surrounding architecture and implementation context.