Protect an MCP Server
Use the MCP transport packages when your MCP framework does not have a dedicated Caracal connector or when you want to build your own boundary.
TypeScript verifier
Section titled “TypeScript verifier”npm install @caracalai/transport-mcp @caracalai/revocationimport { createMandateVerifier } from "@caracalai/transport-mcp";import { InMemoryRevocationStore } from "@caracalai/revocation";
const verifier = createMandateVerifier({ issuer: "https://sts.example.com", audience: "https://mcp.example.com", zoneId: "zone_prod", revocations: new InMemoryRevocationStore(),});
export async function verifyToolRequest(authorization: string | undefined) { const result = await verifier.authorization(authorization, { requiredScopes: ["mcp:tool:call"], requiredTargets: ["https://mcp.example.com"], requireAgent: true, });
if (!result.ok) { throw new Error(`${result.error.code}: ${result.error.description}`); }
return result.principal;}Python verifier
Section titled “Python verifier”pip install caracalai-transport-mcp caracalai-revocationfrom caracalai_transport_mcp 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.example.com", audience="https://mcp.example.com", required_scopes=["mcp:tool:call"], expected_zone_id="zone_prod", revocations=revocations, require_agent=True, required_targets=["https://mcp.example.com"], ) 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. |
| Agent or delegation requirements | Keeps user-root and delegated calls separate. |
| Revocation store | Rejects revoked sessions and delegation edges. |
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/connectors/redis/go
Run a consumer for the caracal.sessions.revoke stream so every resource server instance learns about revoked anchors.
Related pages: Protect an Express App and Protect a FastMCP App.

