The security, access-control, and governance layer for MCP servers.
Project description
pontifex-mcp
Enterprise-grade capabilities for MCP servers, built on the official MCP Python SDK.
pontifex-mcp lets you build MCP servers that connect AI agents to
real systems without giving up control over who can call what. You write the tools; it handles
authentication, per-caller scopes, rate limits, and a full audit trail.
Key features
- Secure by default — OAuth 2.1 JWTs and
sk_…API keys; every tool call is authenticated. Any OIDC provider (Auth0, Entra, Clerk, Keycloak). - Least-privilege scopes —
domain:resource:action, checked before every call. Callers can't widen their own access. - Auditable — every call recorded: who, what, when, data source, cache hit, latency.
- Standards-based — RFC 9728 discovery +
WWW-Authenticate; MCP clients bootstrap auth on their own. - Resilient — per-caller rate limiting, adapter failover, circuit breaking.
- Observable — Logfire / OpenTelemetry tracing and metrics wired in.
- Built on the MCP SDK — keep its tools, protocol, and transports; add the controls a production server needs.
Security is deliberate: asymmetric-only JWT validation, generic auth errors, and no token claim can escalate a caller — all verifiable in the source.
Status:
0.x, building in public. The security model is solid; the public API (everything exported frompontifex_mcp) is still settling — expect occasional breaking changes before1.0.
Install
pip install pontifex-mcp # or: uv add pontifex-mcp
Requires Python 3.12+, Postgres, and Redis.
Build your own domain
A domain is: a settings class, one or more data adapters, and tools wrapped with tool_runtime.
Everything below comes from the top-level package.
from typing import Any
from mcp.server.fastmcp import Context, FastMCP
from pontifex_mcp import (
AuditWriter,
CoreSettings,
create_mcp_http_app,
tool_runtime,
)
class OrdersSettings(CoreSettings):
orders_api_base: str = "https://orders.internal.example.com"
def register_tools(mcp: FastMCP, audit: AuditWriter) -> None:
@mcp.tool(name="orders_get_status", description="Look up the status of an order.")
@tool_runtime(
domain="orders",
tool_name="orders_get_status",
resource="order", # scope checked: orders:order:read
action="read",
audit=audit,
)
async def get_order_status(order_id: str, ctx: Context | None = None) -> dict[str, Any]:
# ... fetch from your internal system (ideally through a DataAdapter) ...
return {"source": "orders-api", "cache_hit": False, "order_id": order_id, "status": "shipped"}
async def health() -> dict[str, Any]:
return {"status": "ok"}
settings = OrdersSettings()
app = create_mcp_http_app("orders", settings, register_tools, health)
# `uv run uvicorn your_module:app` → MCP endpoint at /mcp, health at /health/ready
Auth, scope checks, rate limiting, the audit row, and the structured error envelope are all applied by
tool_runtime and the server's middleware — your handler just returns data.
Configuration
Infrastructure settings read from bare, unprefixed env vars:
DATABASE_URL, REDIS_URL # required (the app fails fast if unset)
AUTH_JWKS_URL, AUTH_ISSUER, AUTH_AUDIENCE, AUTH_SCOPES_CLAIM # enable the OAuth/JWT path
PUBLIC_BASE_URL # canonical URL advertised in OAuth discovery
Domain-specific settings on your subclass read with your domain's env_prefix.
Who it's for
Reach for pontifex-mcp when you're exposing internal or proprietary systems — an orders API, a
customer database, an analytics warehouse — to AI agents (Claude Desktop, your own agents, anything
that speaks MCP), and unauthenticated tool access isn't an option.
If you're shipping a single public tool over non-sensitive data, the MCP SDK on its own is simpler. Come here when access control and an audit trail start to matter.
License
MIT © Chris Dare. Part of Argonauts.
Project details
Release history Release notifications | RSS feed
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 pontifex_mcp-0.1.0.tar.gz.
File metadata
- Download URL: pontifex_mcp-0.1.0.tar.gz
- Upload date:
- Size: 21.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4d7580db2d5f743ba158cd1ce95339debc17067fd19f31f5184b51e90b98b89
|
|
| MD5 |
9f8f02b09d384aad088e659bb0d0561a
|
|
| BLAKE2b-256 |
b1bb70046558bb4c7afd56759da740d8adfda63174d17fd4fdd3927cbf86651b
|
Provenance
The following attestation bundles were made for pontifex_mcp-0.1.0.tar.gz:
Publisher:
publish-pypi.yml on chris-dare/pontifex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pontifex_mcp-0.1.0.tar.gz -
Subject digest:
c4d7580db2d5f743ba158cd1ce95339debc17067fd19f31f5184b51e90b98b89 - Sigstore transparency entry: 1753614234
- Sigstore integration time:
-
Permalink:
chris-dare/pontifex@133aafbbd1db7e938450e151a1acee3af0c9dad5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/chris-dare
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@133aafbbd1db7e938450e151a1acee3af0c9dad5 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pontifex_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pontifex_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 31.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16b64d39a207f67ab112b9110db95cc1acd3d2edd6cb7df8d40b16a415daff95
|
|
| MD5 |
ff794e2838e510ed37c744f3585a52ab
|
|
| BLAKE2b-256 |
f9f0c30fc598bbb9fb82cd51d42a155a9952fca0e87ff65aad05b725e468c16f
|
Provenance
The following attestation bundles were made for pontifex_mcp-0.1.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on chris-dare/pontifex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pontifex_mcp-0.1.0-py3-none-any.whl -
Subject digest:
16b64d39a207f67ab112b9110db95cc1acd3d2edd6cb7df8d40b16a415daff95 - Sigstore transparency entry: 1753614414
- Sigstore integration time:
-
Permalink:
chris-dare/pontifex@133aafbbd1db7e938450e151a1acee3af0c9dad5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/chris-dare
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@133aafbbd1db7e938450e151a1acee3af0c9dad5 -
Trigger Event:
release
-
Statement type: