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).
TypeScript — @caracalai/transport-mcp
Section titled “TypeScript — @caracalai/transport-mcp”npm install @caracalai/transport-mcp @caracalai/revocationauthenticate(token, deps)
Section titled “authenticate(token, deps)”import { authenticate, extractBearer } from '@caracalai/transport-mcp';
async function authenticate( token: string, deps: AuthDeps): Promise<AuthResult>Verification steps (in order):
- Validate
tokenas a non-empty string. - Fetch zone JWKS and verify ES256 signature.
- Check
iss,aud,exp, and optionallyzone_id. - Check
deps.revocations.isRevoked(claims.sid). - Enforce
requiredScopes,requireAgent,requireDelegation,requireChainContains,maxHopCount.
Never throws. Always returns an AuthResult.
AuthDeps
Section titled “AuthDeps”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;}AuthResult
Section titled “AuthResult”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.
extractBearer(authHeader)
Section titled “extractBearer(authHeader)”function extractBearer(authHeader: string | undefined): string | nullReturns the token portion of an Authorization: Bearer <token> header, or null if the header is absent or not in Bearer format.
HTTP status mapping
Section titled “HTTP status mapping”function errorToStatus(code: ErrorCode): 401 | 403 { switch (code) { case 'missing_token': case 'invalid_token': case 'invalid_zone': return 401; default: return 403; }}Python — caracalai-transport-mcp
Section titled “Python — caracalai-transport-mcp”pip install caracalai-transport-mcp caracalai-revocationauthenticate(token, ...)
Section titled “authenticate(token, ...)”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.
AuthResult
Section titled “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: strClaims is from caracalai_identity — see Identity Package.
extract_bearer(auth_header)
Section titled “extract_bearer(auth_header)”def extract_bearer(auth_header: str | None) -> str | None: ...Error codes (same set as TypeScript)
Section titled “Error codes (same set as TypeScript)”missing_token, invalid_token, invalid_zone, insufficient_scope, session_revoked, agent_required, delegation_required, chain_mismatch, hop_count_exceeded.
Usage pattern
Section titled “Usage pattern”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 executionPython:
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.principalRelationship to connector packages
Section titled “Relationship to connector packages”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.