Protect an MCP Server
Use the verify packages when your MCP framework does not have a dedicated Caracal adapter or when you want to build your own boundary.
Prerequisites
Section titled “Prerequisites”- A resource mandate audience and tool-scope map.
- Issuer, zone ID, shared revocation storage, and a hook that runs before tool dispatch.
- A consistent mapping from verification errors to the framework’s unauthorized/forbidden response.
Build the Verifier
Section titled “Build the Verifier”npm install @caracalai/verify @caracalai/revocationimport { createMandateVerifier } from '@caracalai/verify'import { InMemoryRevocationStore } from '@caracalai/revocation'
const verifier = createMandateVerifier({ issuer: 'https://sts.pipernet.example', audience: 'resource://pipernet', zoneId: '0195f2a9-1b22-7c3d-9e4f-5a6b7c8d9e0f', revocations: new InMemoryRevocationStore(),})
export async function verifyToolRequest(authorization: string | undefined) { const result = await verifier.authorization(authorization, { requiredScopes: ['mcp:tool:call'], requiredTargets: ['resource://pipernet'], requireSession: true, })
if (!result.ok) { throw new Error(`${result.error.code}: ${result.error.description}`) }
return result.principal}pip install caracalai-verify caracalai-revocationfrom caracalai_verify import authenticate, extract_bearerfrom caracalai_revocation import InMemoryRevocationStore
revocations = InMemoryRevocationStore()
async def verify_tool_request(authorization: str | None): token = extract_bearer(authorization) result = await authenticate( token or "", issuer="https://sts.pipernet.example", audience="resource://pipernet", required_scopes=["mcp:tool:call"], expected_zone_id="0195f2a9-1b22-7c3d-9e4f-5a6b7c8d9e0f", revocations=revocations, require_session=True, required_targets=["resource://pipernet"], ) if result.error is not None: raise RuntimeError(f"{result.error.code}: {result.error.description}") return result.principalVerification checklist
Section titled “Verification checklist”| Check | Why it matters |
|---|---|
| Issuer and audience | Prevents accepting mandates from the wrong zone or target. |
| Required scopes | Enforces tool-level authority. |
| Required targets | Prevents cross-resource token reuse. |
| Session or Delegation requirements | Keeps application-root and delegated calls separate. |
| Revocation store | Rejects revoked sessions and Delegations. |
Production revocation
Section titled “Production revocation”Use Redis-backed revocation packages for multi-instance MCP servers:
- TypeScript:
@caracalai/revocation-redis - Python:
caracalai-revocation-redis - Go:
github.com/garudex-labs/caracal/packages/backends/redis/go
Run a consumer for the caracal.sessions.revoke stream so every resource server instance learns about revoked anchors.
Validate the boundary
Section titled “Validate the boundary”Test missing token, wrong audience, wrong target, missing scope, required Session, required Delegation, hop limit, and revoked Session before enabling traffic. Expected result: no rejected call reaches tool code and every allowed principal is derived from verified claims rather than request metadata.
For exact verifier functions and error types, use Verify Package reference.
Next Step
Section titled “Next Step”Wrap the framework hook, then run Test Caracal Integrations with a revoked-anchor case.

