Python SDK
The Scopebound Python SDK provides runtime tool-call enforcement for AI agents. Wrap your agent's tools with Scopebound and every tool call is evaluated against the role's authorization scope before it executes.
- PyPI:
scopebound - Repository: scopebound-ai/scopebound-python
- Status: 0.3.0 — production-ready
- License: Apache 2.0
- Python: 3.10+
Install
For LangChain framework integration:
What this SDK does
Unlike the TypeScript SDK (which evaluates whole workflows before execution), the Python SDK enforces at the individual tool call level. Every time your agent calls a tool, the SDK:
- Verifies the tool is in the role's
allowed_toolslist - Checks parameter constraints (rate limits, value ranges, environment scope)
- Resolves and validates credential bindings
- Enforces human-in-the-loop approval gates if required
- Returns the call result or raises a typed exception explaining why it was blocked
This makes it well-suited for runtime enforcement in long-running agent processes, while the TypeScript SDK and n8n node are better suited for pre-execution validation of full workflow definitions.
Quickstart
import os
from scopebound import ScopeboundSDK
sdk = ScopeboundSDK(
base_url=os.environ["SCOPEBOUND_BASE_URL"],
api_key=os.environ["SCOPEBOUND_API_KEY"],
)
# Enforce a single tool call
result = sdk.enforce(
role_id="vision-invoice-processor",
tool_name="post_to_erp",
call_args={"invoice_id": "INV-12345", "amount": 1500.00, "env": "production"},
)
# If allowed: result contains the evaluation details and proceeds
# If denied: ScopeboundDenyError is raised with the violation details
The enforce() call returns when the tool is allowed; it raises a typed exception when denied. Your code calls the actual tool only after enforce() returns successfully.
LangChain integration
The @enforce decorator wraps a LangChain BaseTool class so every call is automatically gated by Scopebound:
from scopebound import ScopeboundSDK, enforce
from langchain_core.tools import BaseTool
sdk = ScopeboundSDK(
base_url=os.environ["SCOPEBOUND_BASE_URL"],
api_key=os.environ["SCOPEBOUND_API_KEY"],
)
@enforce(sdk, role="invoice-processor")
class PostToErpTool(BaseTool):
name = "post_to_erp"
description = "Post an invoice to the ERP system"
def _run(self, invoice_id: str, amount: float) -> str:
# This method only executes if Scopebound's enforcement permits the call.
return submit_to_erp(invoice_id, amount)
Calls to the tool from your agent are evaluated against the invoice-processor role's scope before the underlying _run method is invoked.
Provisioning and session lifecycle
For multi-tool agent sessions, provision a session up front and reuse it across enforcement calls:
session = sdk.provision(
role_id="vision-invoice-processor",
requested_ttl=3600, # 1 hour
task_type="invoice_audit",
framework="langchain",
)
# Use the session token for subsequent calls
# Session is automatically revoked when its TTL expires, or manually:
sdk.revoke(reason="task_completed")
Managing roles
The SDK includes the full management API for creating and updating agent roles:
# Create a role
role = sdk.create_role(
name="invoice-processor",
allowed_tools=["read_invoices", "post_to_erp", "request_approval"],
description="Reads invoices and posts to ERP after approval",
default_ttl_seconds=3600,
max_delegation_depth=0,
rate_limit_per_minute=60,
allowed_envs=["staging", "production"],
approval_required=["post_to_erp"],
)
# Update a role
sdk.update_role(
role_id=role["id"],
allowed_tools=role["allowed_tools"] + ["emit_audit_event"],
)
# List or fetch
sdk.list_roles()
sdk.get_role(role_id=role["id"])
Approval workflow (human-in-the-loop)
When a role requires approval for a tool, calls block on a pending approval:
try:
sdk.enforce(
role_id="invoice-processor",
tool_name="post_to_erp",
call_args={"invoice_id": "INV-12345", "amount": 50000.00},
)
except ScopeboundPendingError as e:
# An approval has been created; surface to the human reviewer
approval = sdk.get_approval(e.approval_id)
# ... display in UI, send to Slack, etc.
# Reviewer approves it via the UI, an API call, or:
sdk.approve(approval_id=e.approval_id, approved_by="[email protected]")
# Now the original call can proceed (re-call enforce)
MCP enforcement
For Model Context Protocol servers, use mcp_enforce to validate tool calls against MCP-specific schemas:
sdk.mcp_enforce(
role_id="vision-invoice-processor",
tool_name="read_file",
arguments={"path": "/invoices/2026-Q1/"},
mcp_server="filesystem",
mcp_tool_schema={...},
mcp_session_id="session_abc",
)
See the MCP framework guide for details on MCP-specific enforcement.
Error handling
The SDK raises typed exceptions for each failure mode:
from scopebound import (
ScopeboundSDK,
ScopeboundDenyError, # Tool call denied by policy
ScopeboundPendingError, # Awaiting human approval
ScopeboundTimeoutError, # Evaluation exceeded timeout
ScopeboundUnavailableError, # Enforcement plane unreachable
)
try:
sdk.enforce(role_id="invoice-processor", tool_name="post_to_erp", call_args={...})
except ScopeboundDenyError as e:
# Tool is not allowed for this role, or parameter constraints failed
logger.warning(f"Blocked tool call: {e.code} — {e.message}")
except ScopeboundPendingError as e:
# Approval workflow triggered — surface to human reviewer
notify_approver(e.approval_id)
except ScopeboundTimeoutError:
# Enforcement plane took too long
# By default this blocks the call (fail-closed). Configure fail_open=True
# in ScopeboundSDK() to allow calls when enforcement is slow.
pass
except ScopeboundUnavailableError:
# Enforcement plane is down or unreachable
# Same fail-open/fail-closed configuration applies.
pass
Fail-open vs fail-closed
By default, the SDK is fail-closed: if the enforcement plane is unreachable or evaluation times out, the tool call is blocked. This is the safe default for production agents.
For non-production environments where enforcement-plane uptime would block development, set fail_open=True:
sdk = ScopeboundSDK(
base_url="...",
api_key="...",
fail_open=True, # Allow tool calls when enforcement plane is unreachable
)
Audit log export
Export evaluation records for compliance retention:
audit_bytes = sdk.export_audit_log(
format="json", # or "csv"
window_hours=168, # last 7 days
)
with open("audit-2026-Q2.json", "wb") as f:
f.write(audit_bytes)
Framework integrations
The Python SDK ships with first-class framework integrations:
- LangChain —
@enforcedecorator forBaseToolclasses - AutoGen
- CrewAI
- OpenAI Assistants
- Semantic Kernel
- Claude Agent SDK
- MCP
Next steps
- Quickstart — your first enforced tool call in 5 minutes
- LangChain integration guide — the most popular Python framework path
- TypeScript SDK — Node.js alternative for workflow-level evaluation
- n8n Community Node — no-code option for n8n users