Skip to main content

Installation

Requires Node.js 22+. ESM only. Zero dependencies — all verification is done with node:crypto.

Overview

@vane.build/mcp-middleware verifies Vane Agent Passports (CAP+JWT) offline using the CA public key. It never calls the Vane server during verification — the CA public key is the only thing needed. Four adapters are provided for different server frameworks:

createVaneMiddleware()

All adapters are created from a single factory. The only required option is the CA public key.
VaneMiddlewareOptions:

fetchMiddleware()

Fetch-compatible middleware for Hono, Next.js Edge, and Cloudflare Workers. Reads Authorization: Bearer <passport>, parses the MCP JSON-RPC body to extract the tool name, verifies the passport, and either forwards the request with an x-vane-receipt header or returns 401.
Reading the receipt in the downstream handler:
On failure: Returns Response with status 401 and JSON body:

expressMiddleware()

Express/Connect-compatible middleware. Assumes req.body has already been parsed by express.json(). Attaches the decoded AttestationReceipt to req.vaneReceipt on success.
On failure: Sends 401 with JSON error body. The next() middleware is NOT called — the request is terminated.

mcpHandler()

Wrapper for MCP SDK CallToolRequest handlers. The passport must be passed in request.params._meta.authorization.
On failure: Throws McpAuthError with a code property matching the passport error code. The passport is expected at request.params._meta.authorization. Set this in the MCP client transport before calling tools:

verify()

Raw passport verification — call this when you already have the token and want to verify it outside a request context.
Returns: PassportVerificationResult

decodeReceipt()

Decodes the base64url-encoded AttestationReceipt from the x-vane-receipt header.

McpAuthError

Thrown by mcpHandler() on verification failure.

AttestationReceipt type


Getting the CA public key

Fetch the key once at deployment time and store it as an environment variable:
Or use the discovery document’s jwks_uri at startup: