Centurian Python SDK — thin MCP wrapper for AI agents. Auto-registers, instruments tool calls, attributes cost. Implements ADR-017 SDK perf primitives: local rule cache + per-action OPA decision cache + durable sqlite-backed event queue + async batched MCP calls. Owner: Connect agent (T12 W3-W5).
Project description
centurian-sdk (Python)
Thin MCP wrapper for AI agents. See docs/prd/v4.1/Centurian_Solo_Developer_Experience.md.
Status
Version 0.1.0b8 ships real network calls to the Centurian control plane. The previous 0.1.0b7 shipped a stub MCP transport (security audit C1) — anyone on <= 0.1.0b7 should upgrade.
Install
pip install centurian-sdk
# optional: enable httpx transport (otherwise stdlib urllib is used)
pip install 'centurian-sdk[http]'
For local-monorepo development:
pip install -e ./packages/sdk-python
Quickstart
from centurian import Agent
agent = Agent(
name="my-agent",
purpose="Answer questions about my docs",
# token is the provisioning token from your /signup flow
# (also auto-read from CENTURIAN_TOKEN env)
)
@agent.tool
def search_docs(query: str) -> str:
return run_my_search(query)
agent.run()
agent.run() does this over the network:
- POST
/api/mcp/tools/callwithtools/callJSON-RPC and toolcenturian.register_agent. - GET
/api/mcp/resources/org_global_rules_manifest?org_id=...to seed the local rule cache. - Start the durable sqlite-backed event queue. Tool invocations enqueue trajectory + tool-call events; the queue flushes via
centurian.report_*_bulkJSON-RPC calls.
Auth
| Call | Auth |
|---|---|
register_agent |
Authorization: Bearer <provisioning_token> (passed via token constructor arg or CENTURIAN_TOKEN env var) |
All spine-ingest tools (report_*, submit_*) |
signing_credential field inside the tool arguments — extracted from the agent identity returned by register_agent |
Action evaluation
agent.evaluate_action(verb, attributes) consults the local rule cache and returns an ActionDecision:
| Effect | decision.allowed |
When |
|---|---|---|
allow |
True |
Rule explicitly allows or no rule matches and manifest is fresh |
deny |
False |
Rule explicitly denies |
escalate |
False |
Synchronous human-in-the-loop gate required |
miss |
False |
Rule manifest stale or absent — treat as deny (Shadow #21 fix). Re-prime via agent.run() or mcp.prime_rule_cache(). |
Use agent.assert_action_allowed(...) to raise ActionRefusedError instead of branching.
Configuration
Reads CENTURIAN_TOKEN, CENTURIAN_MCP_URL, CENTURIAN_ORG_ID, CENTURIAN_OWNER_USER_ID, CENTURIAN_QUEUE_PATH from env.
Errors
McpRpcError(code, message, data)— JSON-RPC error envelope from the server (4xx).McpTransportError(message, status=None)— network failure after retries exhausted (5xx, DNS, TLS).ActionRefusedError(decision)— local rule cache refused the action.
Multi-rail payment support
A62 reserves rail-agnostic schema across the SDK surface. The exported
CostSource Literal accepts legacy uppercase values plus 13 A62-reserved
lowercase values (model_provider_*, mcp_call, stablecoin_x402, etc.);
P0 wires the first 4 (model_provider_openai, model_provider_anthropic,
model_provider_bedrock, mcp_call). The remainder, plus the new
PaymentRail / PaymentProtocol / Facilitator Literals, the
StablecoinAttributes TypedDict, and is_valid_wallet_identifier,
are schema reservation only in v0.1.0.
Live x402 facilitator integration (Coinbase CDP, Cloudflare, Stripe)
ships in v0.2.0+ per A63 / task_plan_v4.1.2.md. Until then, payloads
carrying payment_rail or stablecoin sub-attributes parse without error
but no consumer (cost router, attribute extraction, global rules) acts
on them.
Known beta limitations (v0.1.0b8)
These are documented gaps tracked for the 0.1.0 GA release. Production usage on --pre should be aware:
W3-C1c — register_agent provisioning-token binding is surface-only
The HTTP endpoint at /api/mcp/tools/call requires an Authorization: Bearer <provisioning_token> header for register_agent, but only validates that the token is ≥16 characters. The handler trusts the org_id and owner_user_id claims supplied in the call arguments; it does NOT verify that the bearer token is bound to those claims server-side. Implication: anyone with any 16+ char string can register an agent under any org/owner they claim. The registered agent's signing credential IS bound at the row level, so subsequent calls authenticate normally — but the registration itself is a trust gap.
Mitigation in beta: treat your provisioning tokens as confidential; only obtain them through the documented /signup flow; rotate via centurian.rotate_credential if compromised. GA fix planned: introspectable provisioning_tokens table that binds each token to a specific (org_id, owner_user_id, expires_at) and rejects mismatches.
#13 — validateSigningCredential runs scrypt on every event ingest
Each report_trajectory_step, report_tool_call, etc. validates the signing_credential via scrypt (~30ms per call). High-throughput callers should batch via the bulk variants (report_trajectory_steps_bulk, report_tool_calls_bulk) which amortize the auth cost across up to 1,000 events per round trip. The SDK's BatchClient does this automatically; manual MCP callers should follow the pattern. GA fix planned: auth-cache layer keying validated credentials by (prefix, secret_hash) for 60s LRU.
#17 — No nonce/JTI replay defense on signing credentials
Captured cnt_live_* credentials are valid for their full TTL (default 90 days) until rotated. There is no nonce/JTI/timestamp on signed requests. Mitigation in beta: rotate credentials proactively if you suspect interception; restrict your SDK runtime environment so credentials cannot be exfiltrated. GA fix planned: SDK signs requests with timestamp + nonce; server rejects nonces seen within rotation window or timestamps with >5min skew.
A59 plain-English policy authoring — feature-flagged off
Customer-facing plain-English-to-Rego policy compilation is disabled in v0.1.0b8 and ships in v0.2.0 with the ADR-018 neuro-symbolic guardrail. The lower-level compile_plain_english_to_rego remains callable for internal use (e.g. audit-engine evidence predicates), but customer-facing authoring (submit_for_review, approve_review) is gated until the IR + symbolic verifier ship.
v0.2.0 fix: LLM emits an Intermediate Representation using only ontology primitives → deterministic compiler → symbolic verifier proves IR ↔ Rego logical equivalence → Dana reviews all three layers before applying. See task_plan_v4.1.2.md and docs/prd/v4.1/Centurian_PRD_v4.1.2_Amendments.md (ADR-018 §5.1).
Multi-rail payment coverage — schema only
Schema reservation only in v0.1.0: payment_rail attribute and stablecoin sub-attributes (payment_protocol, payment_amount_usdc, payment_token, payment_network, recipient_did, facilitator, transaction_hash) are recognized in attribute extraction. Live x402 facilitator integration (Coinbase CDP, Cloudflare, Stripe) ships v0.2.0 per A63. See task_plan_v4.1.2.md.
Re-attestation cadence (GA #14)
Every agent is issued an Attestation row at register_agent time with a 30-day TTL. The signing credential itself has a separate 90-day TTL, so a credential can remain technically valid while the underlying attestation has lapsed. Per docs/architecture/federated_model.md, agents must re-attest every 30 days.
The Centurian backend now runs a re-attestation worker (src/workers/reattestation.ts) that emits an agent.attestation.expired spine event when an attestation's expires_at passes without a fresh attestation in place. The recommended cadence is once per hour (the worker is idempotent across runs and per-agent — multiple expired rows produce a single warning, and a fresh attestation heals the warning state).
Caller responsibility: observe agent.attestation.expired on your own activity feed and call centurian.attest_owner (which writes a fresh Attestation row, resetting the 30-day clock) before day 30. SDK auto-re-attestation on the next agent.run() is deferred to a future SDK release; for v0.1.0b8 the re-attestation must be triggered explicitly by the operator or a wrapper script. Track the follow-up on the issue tracker.
Other deferred items
- KMS-managed signing keys for tier-3 audit reports — not yet shipped; tier-3 audit emit throws in production until the host registers a real signer resolver.
- Per-org rate limiting at the MCP HTTP route — not yet implemented; free-tier $5/mo + 10K-step caps at the cost layer mitigate.
License
Proprietary. © Centurian.
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 centurian_sdk-0.2.0b1.tar.gz.
File metadata
- Download URL: centurian_sdk-0.2.0b1.tar.gz
- Upload date:
- Size: 39.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d863106cdcd63444396ae889ce4917ea64b1091a94a48d82b319444208d19a49
|
|
| MD5 |
7d01386564c4710d9041f3bab377bdb2
|
|
| BLAKE2b-256 |
9eec76dd4bbf4b45df97c641df01738ea5a6db4fee8bd0228cfeb6cbb9a9fc97
|
Provenance
The following attestation bundles were made for centurian_sdk-0.2.0b1.tar.gz:
Publisher:
release.yml on omniviewai/Centurian
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
centurian_sdk-0.2.0b1.tar.gz -
Subject digest:
d863106cdcd63444396ae889ce4917ea64b1091a94a48d82b319444208d19a49 - Sigstore transparency entry: 1412542227
- Sigstore integration time:
-
Permalink:
omniviewai/Centurian@b8c977753045f0deb8a17c0c1d47ddafaf190854 -
Branch / Tag:
refs/tags/v0.2.0-beta.1 - Owner: https://github.com/omniviewai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b8c977753045f0deb8a17c0c1d47ddafaf190854 -
Trigger Event:
push
-
Statement type:
File details
Details for the file centurian_sdk-0.2.0b1-py3-none-any.whl.
File metadata
- Download URL: centurian_sdk-0.2.0b1-py3-none-any.whl
- Upload date:
- Size: 29.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16699dcddca9207e48f22661bf6160803d6aa500b81b0559710fc19029eee9c9
|
|
| MD5 |
f7c8d36c962b5247dd29cb2f267cdbdf
|
|
| BLAKE2b-256 |
9b752c5e2eb7bbc396156f54b266aa98af8217200a32cd5b0d388301e9dddaa2
|
Provenance
The following attestation bundles were made for centurian_sdk-0.2.0b1-py3-none-any.whl:
Publisher:
release.yml on omniviewai/Centurian
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
centurian_sdk-0.2.0b1-py3-none-any.whl -
Subject digest:
16699dcddca9207e48f22661bf6160803d6aa500b81b0559710fc19029eee9c9 - Sigstore transparency entry: 1412542440
- Sigstore integration time:
-
Permalink:
omniviewai/Centurian@b8c977753045f0deb8a17c0c1d47ddafaf190854 -
Branch / Tag:
refs/tags/v0.2.0-beta.1 - Owner: https://github.com/omniviewai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b8c977753045f0deb8a17c0c1d47ddafaf190854 -
Trigger Event:
push
-
Statement type: