Testing MCP Authorization Boundaries

Test authorization denials as deliberately as successful tool calls. A request intended for another resource, a caller missing a required permission, or a cross-tenant object reference should fail at the appropriate boundary. Text returned by a tool must not become authority to expand access.

This article uses the MCP specification revision 2025-06-18 and its HTTP authorization model as the protocol reference. Check whether a newer revision changes details you rely on. Tenant isolation and the example's records:read permission are application policy, not universal MCP claim names or scope definitions.

TL;DR

Quick Example

The checks cover the intended allow case plus audience, scope, and tenant denials. The model assumes claims already came from a trusted token verifier; it does not parse or authenticate a token.

The malicious-looking text has no authority in this function because the function accepts only the explicit verified-claims input and target tenant. That is a narrow unit-test property, not evidence that a model, client or server resists prompt injection. No SDK, HTTP transport, OAuth exchange, JWT validation, database policy or live tenant was exercised.

Core Concepts

Resource identity is a protocol boundary

The identified authorization revision requires MCP servers to validate that access tokens were issued for their intended use and requires the resource parameter in relevant client authorization/token requests. A token valid somewhere else is not automatically valid for this server. MCP 2025-06-18 authorization

Test that boundary through the actual verifier and resource configuration. Use controlled test tokens from the approved test issuer, with the wrong intended resource and otherwise plausible content. Decoding an unverified JWT payload and comparing one field is not token validation; signature or introspection, issuer, lifetime and applicable verifier requirements remain essential.

Permission and object ownership are separate checks

A token can be intended for the server and still lack permission for the requested action. A caller can also have a read permission while referencing another tenant's object. Test both dimensions at the actual data-access boundary, including list, search, lookup and follow-on operations that may resolve indirect identifiers.

Do not trust a tenant identifier merely because it appears in a request body or tool argument. Resolve the authorized identity through the application's trusted context and compare it with the resource's real ownership. The toy uses strings to explain the decision; a real system needs its own verified mapping and enforcement design.

The table is a proposed integration test plan. The Python model covers only the policy decision, so each row still needs an end-to-end test against your server.

Error behavior and data disclosure both matter

The revision distinguishes invalid credentials from insufficient permissions and defines relevant HTTP error behavior. Check the actual response and ensure that a denied request has not already executed the action or disclosed protected content. A correct status code after an unauthorized database read is too late.

Use logs that help diagnose the boundary without recording raw access tokens, secrets or private object contents. A test report should identify the scenario, expected enforcement point and observed result. It should not become another store of credentials.

Untrusted output must stay outside the authority path

Retrieved text, error messages and tool responses can contain instructions or claims of permission. The client and application must preserve their own instruction and authorization boundaries. A document saying that access was approved does not establish an authenticated grant.

Test realistic output handling separately from the toy policy. Include content that requests another tool, changes the target tenant, invents approval, or asks for credential forwarding. Observe the actual client/model/tool path and effects. A unit test that never invokes a model cannot prove how a model-mediated workflow behaves.

Best Practices

Pin the revision used by examples and the SDK/server/client versions used by real tests. Preserve differences between normative protocol requirements and application policy. If documentation redirects to a later revision, identify that separately rather than silently attributing its behavior to the older reference.

Build disposable test identities and resources with clear ownership. For every successful authorized scenario, design a nearby denial that changes one boundary: resource, scope, tenant or credential validity. Check both the response and the absence of unauthorized effects. Do not run exploratory authorization tests against unrelated production tenants.

Test enforcement where the protected operation happens. A client-side filter can help the interface but cannot replace server and data-access controls. Include indirect paths such as search results and cached lookups if they can expose the same protected data through another route.

Review downstream credential handling. The identified MCP revision prohibits accepting or transiting tokens outside its specified intended-resource constraints. Do not turn a passing incoming-token check into permission to forward that token indiscriminately. The actual integration needs the approved audience and credential flow for each service.

Reverse a release-ready conclusion if any denial succeeds only in the front end, if data access occurs before validation, or if the implementation accepts tool text as authority. Passing a policy unit test is useful progress, but it does not close the HTTP, verifier, storage or model-workflow test gaps.

Common Mistakes

Checking only that a token exists

Checking permission but not ownership

Letting tool output grant access

Presenting application policy as protocol

FAQ

Which protocol revision does this example use?

The reference is MCP 2025-06-18 for HTTP authorization concepts. The example is a policy model, not a protocol implementation or a conformance test.

Does checking aud validate a JWT?

No. This function requires already-verified claims. Real token validation needs the approved verifier and its complete requirements, including the intended resource and relevant issuer/lifetime checks.

Did the untrusted-output test prove prompt-injection resistance?

No. It shows only that the explicit toy policy does not treat the text as authority. Test the real model/client/tool workflow and protected effects separately with qualified security review.

Related Topics

References