Skip to content

CLI

The npm package ships an mcp-authz binary. It reads a JSON policy file, so a Python project can use it on the same file.

Terminal window
npx mcp-authz explain policy.json --identity alice.json --capabilities caps.json
alice@acme.com
Matched rules
rule 0 domain=acme.com -> reader
rule 1 email=alice@acme.com -> editor
rule 2 org.groups=qa-leads -> admin
Effective roles
reader
editor
admin
Permissions
cases:read
cases:write
* (every permission)
Capabilities
get_case
update_case
prompt:triage_case

--identity takes an Identity or a decoded token payload (iss, sub, email, email_verified, hd), or - to read one from stdin. It answers a what-if, so it trusts the file it is handed rather than verifying a signature.

Terminal window
npx mcp-authz check policy.json --capabilities caps.json

--capabilities is the map naming every capability the server registers. Read it off the server with recordCapabilities rather than maintaining it by hand.

npx mcp-authz check policy.json --capabilities caps.json

check runs the same reconciliation your server runs at boot, so a capability no role can reach fails the pull request rather than the deploy.

It exits 1 on that and on an invalid policy, and 0 on an unused permission, which stays a warning because granting a role ahead of the tool that will use it is how a staged rollout works.

Record the capabilities an MCP server exposes into a permission-map module:

Terminal window
# In-process factory (connector module exporting a server builder).
npx mcp-authz record ./connector.ts --out permissions.ts
# URL-only upstream (service credential).
npx mcp-authz record \
--upstream https://vendor.example.com/mcp \
--token "$UPSTREAM_TOKEN" \
--out permissions.ts

The module carries PERMISSIONS, DEFINITIONS (each capability’s definition as served, and the server’s instructions as 'server:instructions' when it gives any) and, when the server has resources, RESOURCE_URIS.

--upstream connects as an MCP 2026-07-28 client, so it works against a server that speaks only that. A connector module is recorded in process, in whichever version the server negotiates.

--check permissions.ts compares the live catalogue and definitions to a committed file and exits 1 on drift — the usual CI guard before deploy or before standing up a proxy. For each changed capability it prints the fields that changed, with was: and now: lines, and a ⚠ line when the new text looks like it is addressed to the model. Changed instructions show as ~ server instructions. A priced capability that DEFINITIONS has no record of fails too (? name … priced, but DEFINITIONS has no record of it), so a map with no DEFINITIONS fails.

Terminal window
npx mcp-authz tools --out some.jsonc [--client-out .mcp.json] -- npx -y some-mcp
npx mcp-authz tools --check some.jsonc
npx mcp-authz tools --refresh some.jsonc
npx mcp-authz wrap some.jsonc

Save a stdio server’s tools as a config, check it against the server, and run the server with only the tools it lists. wrap <file> and tools --check refuse to start without the record tools writes beside the config. See Trim a server’s tools.

policy.explain(identity) answers the same question inside a process, and nothing on the request path calls it. See Policies.