mcp-authz (Python)
Authorization for servers built with the official MCP Python SDK v2. It uses
the SDK's MCPServer, TokenVerifier, AccessToken, AuthSettings, and
server-middleware interfaces rather than replacing the protocol stack.
pip install mcp-authz
from mcp.server.auth.settings import AuthSettings
from mcp_authz import AuthorizedMCPServer, JwtVerifier, current_principal, define_policy
policy = define_policy({
"roles": {
"reader": ["cases:read"],
"editor": ["cases:read", "cases:write"],
},
"rules": [
{"match": {"domain": "acme.com"}, "role": "reader"},
{"match": {"email": "alice@acme.com"}, "role": "editor"},
],
})
server = AuthorizedMCPServer(
"cases",
policy=policy,
token_verifier=JwtVerifier(
issuer="https://auth.acme.com",
jwks_uri="https://auth.acme.com/.well-known/jwks.json",
resource="https://mcp.acme.com/mcp",
),
auth=AuthSettings(
issuer_url="https://auth.acme.com",
resource_server_url="https://mcp.acme.com/mcp",
required_scopes=["mcp"],
),
)
@server.tool(permission="cases:read")
def get_case(case_id: str) -> dict[str, str]:
return {"id": case_id}
app = server.streamable_http_app(stateless_http=True)
The verifier checks signature, issuer, resource audience, expiry, stable
subject, and verified email. Stable identities are (issuer, sub), and email
or domain policy rules match only verified email identities. Policy is deny-by-default; matching deny rules
override grants. Unauthorized tools, prompts, and resources are filtered from
discovery and rejected if called directly.
Tools, prompts, and resources are first-class MCP capabilities:
@server.prompt(permission="reports:generate")
def release_report(version: str) -> str: ...
@server.resource("case://{case_id}", permission="cases:read")
def case(case_id: str) -> str: ...
Inside a handler, current_principal() exposes the authorization context for
tenant and row-level decisions. The package performs the declared capability
permission check; the application uses the resulting principal to constrain
its own domain query.
The official Python SDK currently exposes only global HTTP scope requirements.
AuthSettings.required_scopes therefore enforces the baseline scope, while
per-capability permissions control discovery and invocation. The shared routing
and scope helpers pin the intended step-up behavior, but this package does not
double-verify tokens or patch private SDK routes to manufacture transport-level
per-capability challenges.
The package runs the same language-neutral policy, scope, and routing fixtures
as mcp-authz, preventing the two implementations from drifting.
Development
uv sync --all-extras
uv run ruff check src tests
uv run mypy src tests
uv run pytest
uv build
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_authz-0.1.0.tar.gz.
File metadata
- Download URL: mcp_authz-0.1.0.tar.gz
- Upload date:
- Size: 85.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.5.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5628bd8e74f271584682e749d86fd703ab1fb4c366ea225459cabbbaff29f81
|
|
| MD5 |
9c4342beb2a03b1185ff436fb04bd39a
|
|
| BLAKE2b-256 |
6e834ac3fcb4119a74610b913496e2f1d3120b6db341bd02762e47ad9af52e76
|
File details
Details for the file mcp_authz-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcp_authz-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.5.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00eb148703a62bfe59f31b87269fa5673f6986a0e4b76de512169219638b6a8e
|
|
| MD5 |
9b2206315f7b588d22964b007bbea094
|
|
| BLAKE2b-256 |
0064201316ea2178395ff3bd25c06f413701588a19bcf920bb275b34b03b5427
|