---
title: "Protect an MCP Server"
url: "https://docs.caracal.run/guides/protect-mcp/"
markdown_url: "https://docs.caracal.run/markdown/guides/protect-mcp.md"
description: "Gate MCP tool calls with Caracal mandate verification using framework-neutral transport packages."
page_type: "page"
concepts: []
requires: []
---

# Protect an MCP Server

Canonical URL: https://docs.caracal.run/guides/protect-mcp/
Markdown URL: https://docs.caracal.run/markdown/guides/protect-mcp.md
Description: Gate MCP tool calls with Caracal mandate verification using framework-neutral transport packages.
Page type: page
Concepts: none
Requires: none

---

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

```bash
npm install @caracalai/transport-mcp @caracalai/revocation
```

```ts
import { 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

```bash
pip install caracalai-transport-mcp caracalai-revocation
```

```python
from caracalai_transport_mcp import authenticate, extract_bearer
from 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.principal
```

## 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

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](/guides/protect-express/) and [Protect a FastMCP App](/guides/protect-fastmcp/).
