Skip to content

MCP Transport

The MCP transport packages verify Caracal mandates on the server side of an MCP connection. Every MCP tool call arrives with an Authorization: Bearer <mandate> header. The transport verifies the ES256 signature against the zone JWKS, checks the revocation store, and enforces scope and delegation requirements. The result is either a typed Claims object (success) or a typed error code (failure).

Terminal window
npm install @caracalai/transport-mcp @caracalai/revocation
import { authenticate, extractBearer } from '@caracalai/transport-mcp';
async function authenticate(
token: string,
deps: AuthDeps
): Promise<AuthResult>

Verification steps (in order):

  1. Validate token as a non-empty string.
  2. Fetch zone JWKS and verify ES256 signature.
  3. Check iss, aud, exp, and optionally zone_id.
  4. Check deps.revocations.isRevoked(claims.sid).
  5. Enforce requiredScopes, requireAgent, requireDelegation, requireChainContains, maxHopCount.

Never throws. Always returns an AuthResult.

interface AuthDeps {
issuer: string; // JWKS at {issuer}/.well-known/jwks.json
audience: string; // Must match 'aud' claim
zoneId?: string; // If set, 'zone_id' must match
requiredScopes?: string[];
requireAgent?: boolean;
requireDelegation?: boolean;
requireChainContains?: string[];
maxHopCount?: number; // Default: 10
revocations: RevocationStore;
}
type AuthResult =
| { ok: true; principal: Claims }
| { ok: false; error: AuthError }
interface AuthError {
code: ErrorCode;
description: string;
}
type ErrorCode =
| 'missing_token'
| 'invalid_token'
| 'invalid_zone'
| 'insufficient_scope'
| 'session_revoked'
| 'agent_required'
| 'delegation_required'
| 'chain_mismatch'
| 'hop_count_exceeded';

Claims is the same type exported by @caracalai/identity — see Identity Package.

function extractBearer(authHeader: string | undefined): string | null

Returns the token portion of an Authorization: Bearer <token> header, or null if the header is absent or not in Bearer format.

function errorToStatus(code: ErrorCode): 401 | 403 {
switch (code) {
case 'missing_token':
case 'invalid_token':
case 'invalid_zone':
return 401;
default:
return 403;
}
}

Terminal window
pip install caracalai-transport-mcp caracalai-revocation
from caracalai_transport_mcp import authenticate, extract_bearer
async def authenticate(
token: str,
issuer: str,
audience: str,
required_scopes: list[str] | None,
expected_zone_id: str | None,
revocations: RevocationStore,
require_agent: bool = False,
require_delegation: bool = False,
require_chain_contains: list[str] | None = None,
max_hop_count: int | None = None,
) -> AuthResult: ...

Never raises. Returns AuthResult.

@dataclass(frozen=True)
class AuthResult:
principal: Claims | None # populated when ok is True
error: AuthError | None # populated when ok is False
@property
def ok(self) -> bool: ...
@dataclass(frozen=True)
class AuthError:
code: str # one of the error codes listed above
description: str

Claims is from caracalai_identity — see Identity Package.

def extract_bearer(auth_header: str | None) -> str | None: ...

missing_token, invalid_token, invalid_zone, insufficient_scope, session_revoked, agent_required, delegation_required, chain_mismatch, hop_count_exceeded.


Both packages are designed to be called in a request handler or middleware. The typical pattern:

TypeScript:

const token = extractBearer(req.headers.get('Authorization') ?? undefined);
if (!token) {
return Response.json({ error: 'missing_token' }, { status: 401 });
}
const result = await authenticate(token, {
issuer: process.env.CARACAL_STS_URL!,
audience: 'resource://my-mcp-server',
requiredScopes: ['tool:call'],
requireAgent: true,
revocations,
});
if (!result.ok) {
const status = ['missing_token', 'invalid_token', 'invalid_zone'].includes(result.error.code)
? 401
: 403;
return Response.json({ error: result.error.code }, { status });
}
const claims = result.principal;
// proceed with tool execution

Python:

token = extract_bearer(request.headers.get('Authorization'))
if not token:
return JSONResponse({'error': 'missing_token'}, status_code=401)
result = await authenticate(
token,
issuer=os.environ['CARACAL_STS_URL'],
audience='resource://my-mcp-server',
required_scopes=['tool:call'],
expected_zone_id=os.environ['CARACAL_ZONE_ID'],
revocations=revocations,
require_agent=True,
)
if not result.ok:
status = 401 if result.error.code in ('missing_token', 'invalid_token', 'invalid_zone') else 403
return JSONResponse({'error': result.error.code}, status_code=status)
claims = result.principal

The MCP transport packages are the primitive layer — they expose authenticate() and extractBearer() for use in any request handler. The connector packages (@caracalai/mcp-express, caracalai-mcp-fastmcp) call these primitives internally and expose framework-native middleware interfaces. Use the transport packages when a connector does not exist for your framework, or when you need fine-grained control over the verification logic.