Skip to main content

Python SDK for the Modei REST API and self-issued passport workflows.

Project description

modei-python

PyPI version License: MIT

Python SDK for the Modei REST API. Manage agent passports, gates, and enforcement policies programmatically.

The MCP server (for Claude Desktop, Cursor, etc.) is the separate TypeScript package: modei-mcp on npm.


Installation

pip install modei-python

Usage

from modei import ModeiClient

client = ModeiClient(api_key="mod_live_xxx")

# List all gates
gates = client.list_gates()

# Create a gate
gate = client.create_gate(name="My API", gate_id="gate_my-api")

# Issue a passport
passport = client.issue_passport(
    "gate_my-api",
    agent_id="agent-001",
    permissions=["read", "write"],
    expires_in="7d",
)

# Check authorization
result = client.check_gate("gate_my-api", action="read", passport_id=passport["passport_id"])
print(result["allowed"])  # True

# Enforce with constraints
enforcement = client.enforce_action(
    passport_id=passport["passport_id"],
    action="write",
    cost_cents=500,
)
print(enforcement["decision"])  # "PERMIT"

client.close()

Async Usage

import asyncio
from modei import AsyncModeiClient

async def main():
    async with AsyncModeiClient(api_key="mod_live_xxx") as client:
        gates = await client.list_gates()
        for gate in gates:
            passports = await client.list_passports(gate["gate_id"])
            print(f"{gate['name']}: {len(passports)} passports")

asyncio.run(main())

Both clients support context managers for automatic cleanup:

with ModeiClient(api_key="mod_live_xxx") as client:
    gates = client.list_gates()

API Coverage

Gates

client.list_gates()
client.get_gate("gate_my-api")
client.create_gate(name="My API", gate_id="gate_my-api")
client.update_gate("gate_my-api", name="Updated Name")
client.delete_gate("gate_my-api")

Passports

client.list_passports("gate_my-api")
client.get_passport("gate_my-api", "pp_xxx")
client.issue_passport("gate_my-api", agent_id="agent-001", permissions=["read"])
client.revoke_passport("gate_my-api", "pp_xxx")
client.reissue_passport("pp_xxx", accept_catalog_version=2)

Attestations

client.list_attestations("gate_my-api", limit=50)
client.record_attestation("gate_my-api", passport_id="pp_xxx", permission="read", tool_name="search", result="allowed")

Permission Catalog

client.get_catalog("gate_my-api")
client.create_catalog("gate_my-api", permissions=[...])
client.publish_catalog("gate_my-api", change_summary="Added search permission")
client.list_catalog_versions("gate_my-api")
client.get_catalog_version("gate_my-api", version=1)
client.get_catalog_impact("gate_my-api")

Gate Check

client.check_gate("gate_my-api", action="read", passport_id="pp_xxx")
client.authorize_dry_run(gate_id="gate_my-api", passport={"..."}, requested_permission="read")

Constraints

client.get_constraints("pp_xxx")
client.set_constraints("pp_xxx", {"read": {"core:rate:max_per_minute": 100}})
client.list_constraint_types(category="cost")
client.list_constraint_templates(category="security")
client.apply_constraint_template("pp_xxx", "conservative-agent")
client.create_constraint_template(slug="my-template", name="My Template", constraints={...})

Enforcement (CEL)

client.enforce_action(passport_id="pp_xxx", action="write", cost_cents=500)
client.list_enforcement_attestations("pp_xxx", decision="BLOCK")
client.get_enforcement_attestation("enf_xxx")
client.verify_enforcement_attestation("enf_xxx")

Anonymous Access

client.get_anonymous_policy("gate_my-api")
client.set_anonymous_policy("gate_my-api", enabled=True, allowed_actions=["read"])
client.get_anonymous_log("gate_my-api")

Commerce

client.discover_services("flights:search", max_price_cents=100, sort="price_asc")
client.issue_consumption_attestation(passport_id="pp_xxx", gate_id="gate_my-api", action="flights:search", outcome="success")
client.generate_settlement(gate_id="gate_my-api", period_type="monthly", period_start="2025-01-01", period_end="2025-01-31")
client.list_settlements(gate_id="gate_my-api", status="pending")
client.get_settlement("stl_xxx")
client.update_settlement_status("stl_xxx", "invoiced")
client.get_sla_compliance("gate_my-api", period_start="2025-01-01", period_end="2025-01-31")

Cumulative State

client.get_cumulative_state("pp_xxx")
client.reset_cumulative_state("pp_xxx", window_type="daily")

API Keys

client.list_api_keys()
client.create_api_key(name="My Key", scopes=["gates:read", "passports:write"])
client.revoke_api_key("key_xxx")

Cryptographic Verification

Local verification utilities for Ed25519 signatures and RFC 8785 content hashing:

from modei import verify_attestation_signature, verify_content_hash, compute_content_hash

valid = verify_attestation_signature(
    attestation_json='{"gate_id":"gate_my-api",...}',
    signature_b64="base64-sig...",
    public_key_b64="base64-key...",
)

matches = verify_content_hash(catalog_snapshot, expected_hash)
hash_hex = compute_content_hash({"key": "value"})

Error Handling

from modei import (
    ModeiError,
    AuthenticationError,
    AuthorizationError,
    NotFoundError,
    RateLimitError,
    ValidationError,
    ConflictError,
)

try:
    client.get_gate("gate_nonexistent")
except NotFoundError as e:
    print(f"Not found: {e}")
    print(f"Status: {e.status_code}")  # 404
except RateLimitError as e:
    print(f"Rate limited, retry after: {e.retry_after}s")
except ModeiError as e:
    print(f"API error: {e} (HTTP {e.status_code})")
Exception HTTP Status
AuthenticationError 401
AuthorizationError 403
NotFoundError 404
ConflictError 409
ValidationError 400, 422
RateLimitError 429
ModeiError All other errors

Environment Variables

Variable Required Default Description
MODEI_API_KEY Yes Your Modei API key
MODEI_API_URL No https://modei.ai API base URL (override for local dev)

You can also pass these directly to the client:

client = ModeiClient(api_key="mod_live_xxx", base_url="http://localhost:3000")

Documentation

Full documentation at modei.ai/docs


License

MIT — Standard Logic Co.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

modei_python-1.1.0a1.tar.gz (67.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

modei_python-1.1.0a1-py3-none-any.whl (44.7 kB view details)

Uploaded Python 3

File details

Details for the file modei_python-1.1.0a1.tar.gz.

File metadata

  • Download URL: modei_python-1.1.0a1.tar.gz
  • Upload date:
  • Size: 67.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for modei_python-1.1.0a1.tar.gz
Algorithm Hash digest
SHA256 2066a8e65df3a8d04035ab1d3b544d283fa236cb53f6e6b07bec88519c7c3400
MD5 8a19fed04a0bd4c6679f40998c24bc6f
BLAKE2b-256 c3f348f84f933116afcb6ac52adf6e55cd93e00823dc164915a725eab9c101ac

See more details on using hashes here.

File details

Details for the file modei_python-1.1.0a1-py3-none-any.whl.

File metadata

  • Download URL: modei_python-1.1.0a1-py3-none-any.whl
  • Upload date:
  • Size: 44.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for modei_python-1.1.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 aad6add67fed4837a30056ac696a2ce013c9db24b9544d6ed95ec429a46793c9
MD5 26e9dc5c9fe993b179364ce71c63401a
BLAKE2b-256 3737833a49b227a496a4bf49381cb1f2098271fc8cc511e0da6a3b13ca01489b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page