Skip to main content

Python SDK for Keel — agent-governance compliance middleware

Project description

keel (Python SDK)

PyPI Python versions License

Python SDK for Keel — agent-governance compliance middleware for regulated finance. Wrap your agent's tool calls so every action is evaluated against policy before it runs.

Async-first (httpx + asyncio), fully typed (Pydantic v2, mypy --strict).

Installation

pip install keel-ai          # core SDK (KeelClient + guard)
pip install keel-ai[mcp]     # adds MCP handler (create_mcp_tool_handler)

KeelClient

import asyncio
from keel import KeelClient, KeelClientOptions, Policy, EvaluationContext, Action

policy = Policy(
    id="treasury-cap",
    name="Treasury per-transaction cap",
    version=1,
    default_action="allow",
    rules=[
        {
            "id": "block-over-50k",
            "action": "block",
            "reason": "Over per-transaction limit.",
            "condition": {
                "type": "spend_limit_per_transaction",
                "currency": "USD",
                "max_amount": 50_000,
            },
        }
    ],
)

async def main() -> None:
    client = KeelClient(KeelClientOptions(base_url="https://api.keel.dev"))
    result = await client.evaluate(
        policy,
        EvaluationContext(
            agent_id="treasury-agent",
            correlation_id="corr-1",
            timestamp="2026-06-01T12:00:00Z",
            action=Action(type="transaction", amount=10_000, currency="USD"),
        ),
    )
    print(result.decision)  # "allow"

asyncio.run(main())

guard()

Wrap async tool handlers so each call is enforced against the policy. A block raises KeelGuardBlockedError (the handler never runs); an escalate raises KeelGuardEscalatedError; an allow runs the original handler.

from keel import KeelClient, KeelClientOptions, guard, GuardOptions, Action
from keel import KeelGuardBlockedError

client = KeelClient(KeelClientOptions(base_url="https://api.keel.dev"))

async def wire_transfer(args: dict) -> str:
    return f"wired {args['amount']} to {args['counterparty']}"

guarded = guard(
    GuardOptions(
        client=client,
        policy=policy,
        agent_id="treasury-agent",
        tool_to_action=lambda name, args: Action(
            type="transaction",
            amount=args.get("amount"),
            currency=args.get("currency"),
        ),
    ),
    {"wire_transfer": wire_transfer},
)

async def run() -> None:
    try:
        out = await guarded["wire_transfer"]({"amount": 60_000, "currency": "USD"})
        print(out)
    except KeelGuardBlockedError as err:
        print(f"blocked: {err.reason} (policy {err.policy_id}, rule {err.rule_id})")

Using with MCP

If you expose your tools over the Model Context Protocol, create_mcp_tool_handler wraps an MCP tools/call handler so every invocation is enforced by guard() and guard outcomes become MCP-shaped CallToolResults with isError=True (block / escalate / governance-unreachable / unknown tool) — so the model can self-correct instead of the action slipping through.

This requires the optional mcp extra:

pip install keel[mcp]
from keel import KeelClient, KeelClientOptions, Action
from keel.mcp import McpGuardOptions, McpToolHandlerOptions, create_mcp_tool_handler
from mcp.types import CallToolRequest, CallToolResult, TextContent

client = KeelClient(KeelClientOptions(base_url="https://api.keel.dev"))

async def wire_transfer(args: dict) -> CallToolResult:
    return CallToolResult(
        content=[TextContent(type="text", text=f"wired {args['amount']}")],
    )

handle = create_mcp_tool_handler(
    McpToolHandlerOptions(
        guard=McpGuardOptions(
            client=client,
            policy=policy,
            agent_id="treasury-agent",
            tool_to_action=lambda name, args: Action(
                type="transaction", amount=args.get("amount"), currency=args.get("currency")
            ),
        ),
        tools={"wire_transfer": wire_transfer},
    )
)

# Dispatch an MCP tools/call request through Keel:
result = await handle(
    CallToolRequest(
        method="tools/call",
        params={"name": "wire_transfer", "arguments": {"amount": 60_000, "currency": "USD"}},
    )
)
# result.isError is True when the policy blocked/escalated the call.

Fail-open

Set failure_mode="open" on a low-risk Policy (serialized as failureMode) so that, if the Keel API is unreachable (KeelNetworkError / KeelEvaluateTimeoutError), the guard runs the tool unguarded and logs a guard_fail_open line to stderr instead of failing closed. Default is closed.

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

keel_ai-0.1.0.tar.gz (95.0 kB view details)

Uploaded Source

Built Distribution

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

keel_ai-0.1.0-py3-none-any.whl (15.5 kB view details)

Uploaded Python 3

File details

Details for the file keel_ai-0.1.0.tar.gz.

File metadata

  • Download URL: keel_ai-0.1.0.tar.gz
  • Upload date:
  • Size: 95.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for keel_ai-0.1.0.tar.gz
Algorithm Hash digest
SHA256 fdaf1b2644ca598e578cd4a01229021c187b5450b21993633dd6f22699fcb4d4
MD5 3e61a777651f7750cce61839d41443d0
BLAKE2b-256 75c9dca06033ebd0f6554bd1d252d72b6340ecc4ff00639dec3b46bc6683d51b

See more details on using hashes here.

File details

Details for the file keel_ai-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: keel_ai-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for keel_ai-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cc497c814c705b3586aee66ff157600e0df5c535c47691897bfc144fd8272064
MD5 e6ceb02b834f17ecb083bf230c8dec71
BLAKE2b-256 ffed0f456b1428bf6da85b5fcdb8ae104bceb82753a2fe5a0d038c9c5dc541c5

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