Skip to content

Protect an Express App

Use @caracalai/mcp-express when an Express app should verify Caracal mandates before route handlers run.

Terminal window
npm install express @caracalai/mcp-express @caracalai/transport-mcp @caracalai/revocation

Use a Redis-backed revocation store in production. The in-memory store is only suitable for local development and tests.

import express from "express";
import { caracalAuth, type CaracalRequest } from "@caracalai/mcp-express";
import { createMandateVerifier } from "@caracalai/transport-mcp";
import { InMemoryRevocationStore } from "@caracalai/revocation";
const app = express();
const verifier = createMandateVerifier({
issuer: process.env.CARACAL_ISSUER!,
audience: process.env.CARACAL_AUDIENCE!,
zoneId: process.env.CARACAL_ZONE_ID!,
revocations: new InMemoryRevocationStore(),
});
await verifier.warmup();
app.use("/mcp", caracalAuth({ verifier }, {
requiredScopes: ["mcp:tool:call"],
requiredTargets: ["https://mcp.example.com"],
}));
app.post("/mcp/tools/list", (req: CaracalRequest, res) => {
res.json({
principal: req.caracalClaims?.sub,
tools: ["search", "summarize"],
});
});

The middleware attaches verified claims to req.caracal and req.caracalClaims, plus the propagation context at req.caracalContext.

OptionUse it for
requiredScopesTool or route-level scope checks.
requiredTargetsResource-target checks.
requireAgentReject non-agent mandates.
requireDelegationRequire delegated authority.
maxHopCountLimit delegation depth.
  1. Exchange for a mandate that targets the resource.
  2. Call the protected route with Authorization: Bearer <mandate>.
  3. Remove a required scope and confirm the route returns 403.
  4. Revoke the session and confirm the route rejects the old mandate.

Related pages: Mandates and Sessions and Revocation.