mudraid-platform-middleware is how a platform protects its API. It’s middleware for FastAPI and Starlette with two modes:
mode="v1"(default) — route and scope enforcement. You add it once, point it at yourmudraid_scopes.yaml, and every request is checked for a valid access token and the right scope, locally, before it reaches your handlers.mode="v2"— live decisions for MCP servers. Each protected MCPtools/callis resolved to a canonical action and decided by MudraID’s/decide. See V2 mode.
When to use it
Use the middleware on the platform side — in the API that agents call. If you’re building the agent that makes calls, you want the Python Agent SDK instead.What it does per request
- Matches the method and path against the rules in
mudraid_scopes.yaml. - Lets
publicroutes through untouched. - Returns 404 for
skiproutes and routes with no rule — they’re invisible to agents. - Reads the
Authorization: Bearertoken. - Verifies the token’s signature, issuer, audience, and timing against MudraID’s published keys — locally, with no per-request callback. Keys are cached and refreshed automatically when MudraID rotates them.
- Checks the route’s required scope is present in the token’s
scopeclaim. - Forwards to your handler, or returns a structured
{"error_code", "message"}error.
add_middleware does, and the quickstart’s verification step is how you confirm it before relying on any of the above.
Install
pyjwt[crypto], cryptography, httpx, pyyaml, and starlette.
Performance
The middleware verifies tokens locally, so the steady-state cost is small. Measured overhead over a bare FastAPI handler with a warm key cache:
The scope-gated cost is dominated by the one-time signature verification per request. Fetching MudraID’s keys happens once at startup (and on rotation), not on every call.
V2 mode: live decisions for MCP servers
On a protected path, V2 strips reservedx-mudraid-* request headers, bounds the request body, rejects JSON-RPC batches, and lets the control methods initialize, ping and tools/list through without a decision. Every tools/call is matched — exactly and case-sensitively — to a canonical action in your platform’s signed action bundle, then sent to MudraID’s /decide along with the caller’s Authorization header. Only an allow reaches your handler. A missing bundle, an unmapped tool, a deny, a timeout or an unreachable authority are all refused.
HttpDecideClient is the supported client. It fetches and verifies the signed bundle, keeps it refreshed, makes the authenticated /decide call, and reports adapter heartbeats and acknowledgements to the portal. It needs the MudraID origin for your environment and the adapter token shown once when you register the adapter; both are printed by the portal.
protected_paths to your MCP endpoints. It matches whole path segments: /mcp covers /mcp and /mcp/tools, not /mcpfoo. The V2 settings and their errors are on Configuration and Error responses.
HttpDecideClient verifies a decision signature whenever a response carries one, and require_signed_decisions=True refuses unsigned responses. MudraID does not sign decision responses by default, so leave that flag off unless MudraID has confirmed signing for your surface — with it on and signing off, every decision is refused.Next
- Configuration — settings & defaults.
- Error responses — the stable error_code contract.
- Operator playbook — running it day to day.
- Quickstart — a guided first integration.

