Skip to content

Releases: chris-dare/pontifex

v0.5.1

Choose a tag to compare

@chris-dare chris-dare released this 23 Jun 21:01
dbf42a8

Fixes a migration failure on databases provisioned before ec55a7a renamed the core schema from core to pontifex_mcp_core. Those databases never had a migration to perform the rename, so core_0005 (introduced in 0.5.0) would fail with schema "pontifex_mcp_core" does not exist on upgrade.

Fix

Adds migration core_0004b that conditionally renames the schema on existing installs and is a no-op on fresh ones.

Upgrading from 0.5.0

Run pontifex-mcp db upgradecore_0004b and core_0005 will apply in sequence.

Upgrading from < 0.5.0

Follow the 0.5.0 upgrade notes, then run pontifex-mcp db upgrade.

Full Changelog: v0.5.0...v0.5.1

v0.5.0

Choose a tag to compare

@chris-dare chris-dare released this 21 Jun 22:57
4cc7ced

Pontifex 0.5.0 is the namespace release.

Adds agent skill for pontifex-map
Terminology cleanup: Renames domain to namespace. That changes the words we use in docs, configs, and internal names, but it does not change your scope values, API keys, CLI commands, or auth flow.

Features

  • Bundle the pontifex-mcp skill in the wheel so the coding-agent guidance ships with the package (#103).
  • Add the Upgrading guide and the coding-agent guide (#103).

Refactors

  • Rename the core concept from domain to namespace across the public docs and codebase (#102).
  • Move the worked example from domains/ to examples/ (#102).

Upgrading

  • Run pontifex-mcp db upgrade.
  • Rename domain: to namespace: in connector YAML.
  • If you import the internal registry model, switch DomainRegistryModel to NamespaceRegistryModel.

What stays the same

  • Existing scope values such as payments:balance:read and gse:*:*.
  • ApiKeyAuth and JwtAuth.
  • The pontifex-mcp CLI commands and flags.

v0.4.2

Choose a tag to compare

@chris-dare chris-dare released this 21 Jun 14:37
147095f

Zero-infra quickstart + key management CLI

ApiKeyAuth no longer requires Postgres or Redis to get started. Pass a SQLite URL and the schema is created on first request — no migration step, no containers:

auth = ApiKeyAuth(database_url="sqlite+aiosqlite:///./keys.db")

Redis is optional in all configurations. When REDIS_URL is absent, rate limiting is disabled and logged; everything else works normally.

New: pontifex-mcp CLI

Migrations and key provisioning are now first-class CLI operations — no custom scripts needed.

pontifex-mcp db upgrade — runs the packaged Alembic migrations against Postgres. Safe to call on every deploy; concurrent runs are serialized via a Postgres advisory lock so a multi-replica rollout never races.

$ pontifex-mcp db upgrade
INFO  [alembic.runtime.migration] Running upgrade  -> 001, core schema
INFO  [alembic.runtime.migration] Running upgrade 001 -> 002, audit log indexes

pontifex-mcp keys create/list/revoke — full key lifecycle. The plaintext token is shown once at creation and never stored; only the SHA-256 hash is written to the database. Revocation invalidates the Redis cache immediately.

$ pontifex-mcp keys create --owner usr_01 --label "prod" --scopes payments:invoices:read
sk_live_...   ← copy now, shown once

Breaking change

The Postgres schema was renamed from core to pontifex_mcp_core (#92). Existing Postgres deployments need a one-time migration:

ALTER SCHEMA core RENAME TO pontifex_mcp_core;

Then run pontifex-mcp db upgrade to apply the remaining migrations.

Fixes

  • ApiKeyAuth with DATABASE_URL set no longer activates API-key auth on a JwtAuth server (#93)
  • keys revoke now invalidates the Redis cache immediately — revocation is not TTL-delayed (#97)
  • Scope validation requires 3-part domain:resource:action format; 2-part scopes are rejected at creation (#97)
  • keys create on Postgres without db upgrade gives a clean "schema not set up" error instead of raw SQL (#97)
  • Model server_default values aligned with migrations so raw INSERTs behave identically on SQLite and Postgres (#98)

Full Changelog: v0.4.1...v0.4.2

v0.4.1

Choose a tag to compare

@chris-dare chris-dare released this 20 Jun 11:34
7695f1f

Replaces the deprecated authlib.jose JWT backend with PyJWT and patches a pydantic-settings vulnerability.

What changed

  • JWT validation migrated to PyJWTauthlib.jose is deprecated upstream and would break at authlib 2.0. The new implementation uses PyJWKSet + jwt.decode with explicit kid-based key lookup. All security properties are preserved: asymmetric-only algorithm allowlist, alg: none rejection, full exp/iss/aud/sub enforcement, generic error messages. Key rotation resilience is also restored for providers that reuse a kid across rotations.
  • pydantic-settings bumped to 2.14.2 — fixes GHSA-4xgf-cpjx-pc3j (symlink traversal in NestedSecretsSettingsSource).
  • authlib removed from the published dependency list; pyjwt>=2.8.0 added. cryptography>=42.0 (already declared) provides RSA/EC key support.

Full Changelog: v0.4.0...v0.4.1

v0.4.0 — the PontifexMCP facade

Choose a tag to compare

@chris-dare chris-dare released this 19 Jun 22:00
a1626d0

PontifexMCP — a governed MCP server in a few lines

PontifexMCP is a drop-in subclass of the MCP SDK's FastMCP: swap the import and your tools keep working. The difference is what you can turn on. The floor needs no database, no Redis, and no auth — an anonymous caller, audit to stdout, stdio or localhost HTTP. You graduate to the full governance stack one keyword at a time.

from pontifex_mcp import PontifexMCP, ApiKeyAuth

mcp = PontifexMCP("payments", auth=ApiKeyAuth(), audit="audit.db")

@mcp.tool(scope="refunds:execute")
async def issue_refund(charge_id: str, amount: int, idempotency_key: str) -> dict:
    ...

mcp.run(http=True)

What's new

  • Zero-infra floor → opt-in ceiling. auth=ApiKeyAuth() / JwtAuth() turn on Bearer auth and scope enforcement; @tool(scope="resource:action") is advisory until then. No auth → HTTP binds 127.0.0.1; exposing it publicly is an explicit auth="none".
  • Pluggable audit sinks. audit= is stdout by default, a path/URL for durable rows, or a list to tee. Audit needs no infrastructure to stay visible.
  • SQLite alongside Postgres. Point any datastore at a sqlite:///file path for local dev or a postgresql+asyncpg://… URL for production; the dialect is detected from the connection string. Postgres keeps its schema-per-domain isolation.
  • mcp.cache and mcp.add_openapi(...). A Redis cache exposed to your tools, and one-line generation of governed tools from an OpenAPI spec — each authenticated, scope-checked, and audited like a hand-written one.

Compatibility

Backward-compatible. create_mcp_http_app, run_mcp_stdio, and tool_runtime are unchanged — now the lower-level path beneath the facade.

Full Changelog: v0.3.0...v0.4.0

v0.3.0

Choose a tag to compare

@chris-dare chris-dare released this 13 Jun 18:35
3551380

Highlights

Per-user downstream auth via OAuth token exchange (RFC 8693)

Connectors can now authenticate to a downstream API as the calling user rather than with a single shared service credential. Pontifex exchanges the caller's token at your IdP for one scoped to the downstream's audience — the inbound token is never forwarded (no passthrough). Works with any RFC 8693 provider (Keycloak, Auth0, Microsoft Entra, Okta). Enable with type: token_exchange in a connector's config, or TokenExchange(...) in code. API-key callers (no user token to exchange) are cleanly rejected. (#44)

Shared encrypted token cache

Exchanged tokens can be cached in Redis across workers (PONTIFEX_TOKEN_CACHE=redis), encrypted at rest with a Fernet key held in the environment — a Redis dump yields only ciphertext. The default remains in-process memory. External-KMS key management is tracked in #52. (#47)

Enhancements

  • Audit log records per-user delegations via a new delegated_audience column — auditors can see which downstream a user's credential was delegated to (never the token). (#45)
  • Metrics for the token-exchange path (exchange latency, outcomes, cache hit/miss/coalesced) when Logfire is configured. (#48)

Fixes

  • Isolate the IdP circuit breaker from the downstream connector breaker, so an IdP outage no longer trips the downstream breaker or locks out callers whose delegated token is still cached. (#46)

Docs

  • New token-exchange and token-cache guidance on the Connectors page, including the two-persona (service credential vs. user identity) framing.

Full Changelog: v0.2.0...v0.3.0

v0.2.0 — OpenAPI connectors

Choose a tag to compare

@chris-dare chris-dare released this 13 Jun 09:11
86a483a

Auto-generate governed tools from an OpenAPI spec — onboarding a system goes from code to config.

Highlights

  • OpenAPI connectorsregister_openapi_tools(...) reads an OpenAPI 3.x spec (URL, file, or dict; JSON or YAML) and registers one MCP tool per allowlisted operation. Each tool is wrapped in the same tool_runtime as a hand-written one — same scope check, audit row, and error envelope. Auto-generated does not mean ungoverned.
  • Config-only onboarding — point PONTIFEX_CONNECTORS_CONFIG at a connectors YAML file and the server registers the tools at startup. No domain code required.
  • Derived scopes — each generated tool enforces a domain:resource:action scope derived from the operation (resource from the path, action from the verb), slotting straight into the existing scope model.
  • Opt-in by design — operations are exposed via an explicit include allowlist; mutating verbs require allow_mutations. Typos and unapproved writes fail at startup, never silently.
  • Backend authBearerFromEnv / HeaderFromEnv authenticate the generated adapter to the downstream API; secrets are read from the environment (presence checked at boot).
  • Resilient — downstream calls run through a generated DataAdapter under DataSourceManager, so circuit breaking applies; connector health appears in /health/ready.

New docs: the Connectors guide. Full detail in #38 / #40.

Compatibility

Additive and backward compatible with 0.1.0. New dependency: pyyaml.

v0.1.0

Choose a tag to compare

@chris-dare chris-dare released this 08 Jun 01:38
133aafb

First release of pontifex-mcp — enterprise-grade capabilities for MCP servers, built on the official MCP Python SDK.

Highlights

  • Auth, two ways — OAuth 2.1 JWTs (any OIDC provider) and sk_… API keys, resolving to one CallerIdentity.
  • Least-privilege scopesdomain:resource:action, enforced before every tool call.
  • Audit trail — every call recorded (who, what, when, source, cache hit, latency).
  • Standards-based discovery — RFC 9728 protected-resource metadata + WWW-Authenticate.
  • Resilient — per-caller rate limiting, adapter failover, circuit breaking.
  • Observable — Logfire / OpenTelemetry wired in.