Wrap the tools that actually have consequences, and Kynara decides — allow, deny, or require human approval — before any side effect runs. No re-architecture required.
# Python
pip install kynara-sdk
# TypeScript
npm install @kynara/sdk
Sign up at kynaraai.com, register an agent, and create an API key (scope decisions.check). You'll use the API key and the agent ID below.
from kynara_sdk import Kynara, permission_required
from kynara_sdk.context import set_current_kynara
set_current_kynara(Kynara(
api_key=os.environ["KYNARA_API_KEY"],
agent_id="crm-assistant",
user_id=current_user_id, # the human the agent acts on behalf of
fail_closed=True, # deny if the control plane is unreachable
))
@permission_required("crm.contacts.read",
resource_arg="contact_id",
resource_type="crm.contact")
def read_contact(contact_id: str):
return crm.get(contact_id)
If policy denies the call, PermissionDenied is raised before crm.get runs, and the attempt is recorded in the audit log. If policy returns require_approval, ApprovalRequired is raised so your agent can pause for a human.
In the Kynara console, create a policy (or load a template). For example, only allow refunds during business hours, or require approval for emails to external recipients:
{ "op": "ends_with",
"args": ["ctx.resource.attrs.recipient", "@yourcompany.com"] }
Browse ready-made policies in the docs — Slack channel allowlists, Gmail recipient rules, business-hours, geo, and more.
Every check — allow, deny, or require_approval — lands in your tamper-evident audit log with the full context. That's it: your agent is governed.
If your agent uses Model Context Protocol servers, point them at the Kynara MCP Gateway instead — every tool call is authorized per agent, and agents only see the tools they're allowed to use. No agent-side changes; swap one URL. See the MCP Gateway docs.
Free plan: 3 seats, 10k decisions/month.