An authenticated MCP connection does not authorize every tool action behind it. Secure MCP as a chain of independent trust boundaries: validate who issued a token and which resource it targets, authorize the principal for the exact tool and resource, bind application state to that principal, distrust server-provided URLs and tool content, and constrain the process and credentials that execute the action.
The central rule is simple: the model may propose a tool call, but identity and policy outside the model must decide whether it runs.
This guide targets MCP protocol version 2026-07-28. Older releases used different session and authorization behavior; verify the version before applying a control.
Draw the trust boundaries before choosing controls
A remote MCP deployment can contain at least these actors:
user│▼MCP client ── authorization request ──> authorization server│ ││ access token │ identity and consent▼ │MCP server ── policy decision ──> state store ││├── downstream credential ──> third-party API└── constrained execution ──> tool runner / host resources
For each arrow, record the principal, credential audience, attacker-controlled fields, enforcement point, audit event, and maximum effect. The production agent architecture patterns help place the MCP layer inside the larger planning, routing, approval, and execution flow.
Local stdio servers change the transport, not the need for a threat model. They may skip the HTTP authorization flow while gaining direct access to files, environment variables, subprocesses, and the user's network. Treat installation and process execution as high-authority boundaries.
Separate three decisions that are often collapsed
Authentication establishes which principal a verified credential represents.
Authorization decides whether that principal can invoke this tool on this resource with these arguments now.
Downstream delegation gives the MCP server a credential suitable for the third-party API without leaking or reusing the wrong token.
A bearer token can be valid and still be wrong for the MCP server because its audience targets another resource. A user can be authorized to call orders_get and forbidden from calling refund_create. A refund permission can still be invalid for an order belonging to another tenant.
Keep identity out of model-controlled arguments. Derive user_id and tenant_id from the verified security context, then check resource ownership and action policy after schema validation. The agent tool design guide covers the schema, permission, and error contracts that make this enforcement legible to the orchestrator.
Reject token passthrough
The current MCP security guidance defines token passthrough as accepting a client token without verifying it was issued for the MCP server and forwarding it to a downstream API. It explicitly forbids the pattern because it breaks audience boundaries, weakens accountability, and can turn the server into a confused deputy. See the protocol's MCP security best practices and authorization specification.
At the MCP boundary:
- Validate signature, issuer, audience, time claims, and the authorization method required by the deployment.
- Map the verified identity to an internal principal.
- Evaluate tool, resource, tenant, arguments, and requested effect.
- Obtain or use a downstream credential intended for that API and constrained to the required operation.
- Correlate the user, MCP client, policy decision, tool call, and downstream receipt in the audit trace.
Do not log raw bearer tokens. Log a non-secret credential identifier, issuer, audience decision, subject mapping, scopes, and policy result.
Bind consent, issuer, client, and redirect
MCP proxy servers can become confused deputies when one static third-party client identity is shared across many MCP clients and consent is not tracked per client. The current protocol guidance requires per-client consent in the vulnerable proxy pattern and exact redirect URI validation.
The 2026-07-28 protocol also hardened authorization around issuer validation. RFC 9207 defines authorization-server issuer identification to mitigate mix-up attacks, while RFC 9700 records current OAuth 2.0 security best practice.
Test the negative path. A client should reject an authorization response from the wrong issuer even when the code looks structurally valid. A server should reject a redirect URI that differs by path, port, or scheme from the registered value. Consent must identify the requesting client and exact scopes, not merely say that “an AI tool” wants access.
Constrain discovery, redirects, and outbound network access
MCP clients and authorization servers may fetch metadata from URLs supplied by parties they do not trust. DNS names that look public can resolve to loopback, link-local, private, or cloud metadata addresses. Redirects can cross from an allowed host to an internal target.
Apply URL controls at every hop:
- allow only expected schemes; production authorization endpoints require HTTPS;
- reject embedded credentials and malformed authorities;
- resolve and block loopback, private, link-local, multicast, and metadata ranges;
- validate every redirect instead of trusting the first URL;
- constrain egress at the network layer, not only in application code;
- account for DNS time-of-check/time-of-use changes.
Never open an authorization URL by passing it through a shell. Current MCP guidance calls out malicious schemes and command injection as paths from a server-supplied URL to client-side code execution.
Treat state handles as references, not credentials
The 2026-07-28 core is stateless at the protocol level. Applications can still mint explicit handles for carts, workflows, files, or long-running tasks. Possession of a handle does not authenticate its presenter.
Generate non-predictable handles, expire them where appropriate, and bind them server-side to the authenticated principal:
state_key = verified_tenant_id + ":" + verified_user_id + ":" + handle
Reject a valid handle presented by a different principal. Do not accept user_id next to the handle and assume they belong together. The MCP 2026-07-28 release notes explain the shift from protocol sessions to explicit application state.
Distrust tool descriptions, arguments, and results
Tool metadata can influence which action the model selects. Tool results can contain instructions that attempt to redirect the next step. Arguments can be structurally valid and semantically unauthorized.
Maintain an approved server and tool inventory. Review material tool-description changes. Namespace tools to avoid ambiguous collisions. Validate arguments with a closed schema, then enforce resource and action policy independently. Treat returned text as untrusted data and prevent it from acquiring application authority.
For consequential actions, bind approval to the exact validated tool, resource, arguments, and expected effect immediately before execution. If any field changes, require a new decision. Use the agent prompt-injection test plan to follow malicious content from MCP resources or tool results through to attempted side effects.
Contain local MCP servers
A local server is executable code on the user's machine. Review the package source and provenance before installation, pin versions and integrity, and show the user what the process can access.
Run with a dedicated low-privilege identity or sandbox where possible. Provide only the required environment variables, directories, commands, and network destinations. Do not expose a general cloud credential when one scoped token or brokered operation will do. Prevent other local processes from silently reusing an unauthenticated endpoint.
Updates are security events. A previously reviewed package can gain new tools, broader filesystem access, or a new dependency. Re-run the trust-boundary tests after a version or configuration change.
Run these 12 negative tests
Each test needs an expected enforcement point and audit record. A polite model refusal does not pass if the unauthorized operation reached the server.
| Test | Malicious or invalid condition | Expected result |
|---|---|---|
| Wrong audience | Valid token issued for another API | MCP server rejects before tool routing |
| Wrong issuer | Authorization response/code from an unexpected issuer | Client rejects before token exchange |
| Redirect mismatch | Callback differs from registered URI | Authorization flow stops with no code disclosure |
| Token passthrough | Client supplies a downstream API token | Server rejects; token is never forwarded |
| Cross-user state | User B presents User A's valid workflow handle | Server returns denial without revealing state existence |
| Excess scope | Client requests broad scopes unrelated to the tool | Minimum scopes requested or elevation explicitly justified |
| Discovery SSRF | Metadata URL resolves to a private/metadata address | Fetch blocked at application and egress layers |
| Dangerous auth URL | Server returns javascript:, file:, or shell metacharacters | Client rejects and never invokes a shell |
| Unauthorized side effect | Model requests a write outside user/resource policy | Policy layer rejects before execution |
| Poisoned tool result | Tool output tells the model to exfiltrate data | Content remains data; forbidden tool call is blocked and logged |
| Local privilege escape | Local server attempts an undeclared file, command, or destination | Sandbox/OS/network policy denies it |
| Missing correlation | Tool effect lacks principal, client, policy, and receipt linkage | Release test fails; operation is not production-ready |
Automate the deterministic cases. Preserve protocol version, client and server version, policy version, trace ID, and sanitized evidence so a failure can become a regression test. The production observability guide shows the task-level trace needed to connect an authorization decision to its external effect.
Know what this checklist cannot prove
These tests do not prove that every dependency is trustworthy, every prompt injection will fail, or every legal obligation is satisfied. They also do not replace ordinary API security, dependency review, secret management, secure build pipelines, host hardening, incident response, or human review.
Protocol behavior changes. Re-check every normative MUST and SHOULD against the version you deploy, especially while MCP clients and servers support multiple revisions.
Start by drawing one real deployment and running the wrong-audience, cross-user-state, token-passthrough, SSRF, and unauthorized-side-effect tests. If the design spans identity, policy, sandboxing, observability, and downstream delegation, book a meeting with JoinAI to review the production architecture and implementation plan.




