Repository navigation
donkey-kit 0.2.0: Phase 2, Differentiate, go beyond. This release adds the capabilities a stock OpenAI client with a base_url can't offer, because they depend on the platform behind the gateway. You get governed MCP tool access, publication to Exchange from your code and CI, on-behalf-of user identity, and human-in-the-loop approvals, including the gateway's own CIBA step-up. You also get an A2A server built on the official a2a-sdk, declarative refusal handlers, typed custom policies, and the OpenAI Agents SDK as the second deep adapter.
pip install --upgrade "donkey-kit==0.2.0"
pip install --upgrade "donkey-kit[all]==0.2.0" # now includes mcp and a2aBreaking changes
From 0.1.3. No name was removed from donkey_kit, and no extra was dropped. These changes can still affect existing code. Each has its own section, with the fix, in MIGRATION.md.
- New refusal types. A CIBA pending
401is nowGatewayApprovalPending, whichexcept AuthError:no longer catches, and a CIBA denial403isGatewayApprovalDenied(#1320). Google Model Armor and CrowdStrike AIDR blocks areContentSafetyBlockedinstead ofPolicyViolation(policy="unknown"), and theirdonkey.policy.typereadscontent_safety(#1178, #1176). classifyis aClassifierobject. Calling it works as before, butinspect.isfunction(classify)isFalse. To type a custom policy, useclassify.register()instead of wrapping it (#1152).- Calls that raised
NotImplementedErrornow run.donkey publishanddonkey verifyare visible and do the work: they exit 0, 1 or 2, and no longer exit 3 (#218, #1352).discover(),donkey.registry.search(),resolve_mcp()/resolve_agent(),explain(),Publication.verify(), theToolSetbindings andderive_descriptor(mode="auto…")make control-plane calls. Anexcept NotImplementedError:fallback around them is no longer reached. A gateway credential is held back from abase_urlset in the project files that isn't a regional Anypoint host (ADR 0019, #1479). donkey.tools.discover()defaults togoverned=True. Passgoverned=Nonefor the unfiltered list (ADR 0017, #1424).GovernanceCriteriais imported fromdonkey_kitagain.from donkey_kit.experimental import GovernanceCriteriastill works, but it emits aDeprecationWarning(#1425).- Install changes.
[cli]needstyper>=0.26.0andrich>=13.8.0, and no longer installsclick(#1196).[all]addsmcpanda2a, and[adk]installslitellm[mcp](see Extras changes). AgentKilledis terminal for theDonkeythat saw it. Build a newDonkeyto carry on (#220).refusal_translatorleaves the__all__of the Agent Framework and Strands adapters. A direct import still works (#1422).- A configured URL with a user name or password is refused with
ConfigErrorbefore anything is sent. Before, httpx sent those credentials to the host asAuthorization: Basic(#1478). AgentFrameworkAdapter(...).policy_middleware()withoutagent_frameworkinstalled raises the install-hintImportErrorinstead ofNotImplementedError(#1503).
From a 0.2.0 pre-release (0.2.0.devN, 0.2.0rc1). These surfaces first shipped in the 0.2.0 pre-releases, and they changed before the final with no deprecation cycle. The full list is in MIGRATION.md. The changes most likely to need a code edit:
- Identity:
donkey.as_user(id_token=...)isdonkey.as_user(token=...), andtoken_exchange_pathis gone.as_user()refuses anllm_proxy_urlfrom the working-directory config files. Set it in the environment or in code, or setDONKEY_TRUST_PROJECT_CONFIG=1. - Tools:
ToolSet.openai()isToolSet.openai_agents(). A per-tool binding raisesAuthErrorunder a differentas_user()user, so bind inside the block that runs the agent. A gateway with a plainhttp://public URL is refused unlessDONKEY_ALLOW_HTTP=1is set. - Approvals:
donkey.approvalsis per client, and the module-level instance is gone (ADR 0018). An unknown approval id raisesApprovalNotFound, which is still aKeyError.ApprovalRejectedandGatewayApprovalDeniedshare the newApprovalErrorbase. A resumed approval runs as its requester. The adapter helpers returnApprovalobjects, with the framework object on.native. A Strands approval covers exactly one call.require_approval()on a whole-server binding raisesConfigError. - CLI and Action:
donkey dev --versionis--agent-version. The--jsondocuments carry their own format key (publish_format,verify_format,expose_format). A failedpublish --jsonprints its outcome and exits 1.donkey verifyexits 2 with no gateway credential. Pass the Action'sclient-secretfromsecrets.*; itsskippedoutput is gone. - Errors: the ADK, LangGraph and Agent Framework helpers raise the install-hint
ImportErrorinstead of a bareModuleNotFoundError.
Highlights
- Governed MCP tool access:
donkey.tools.discover()finds governed MCP servers in Exchange.ToolSetbinds them to LangGraph, the OpenAI Agents SDK, ADK, Strands, MS Agent Framework, Anthropic, CrewAI and LlamaIndex through the governed gateway (#221, #1308, #1310). A server that isn't governed is refused withUngovernedMcpServer(#1199), and the gateway's tool-access denial is typed asToolNotInProfile(#1362).donkey.tools.warm()pre-fills the discovery cache (#1333), and discovery emits a span with cache hit and miss counters (#1351). - Publication to Exchange:
donkey scanderives a deterministic model of your agents, tools and MCP servers (#1192).donkey publishregisters MCP servers and agents in Exchange with a full asset page, including a "Changes since" section (#1259, #1270, #1277, #1291, #1358).donkey verifychecks what you published against the live tools and agent card (#1355, #1361). The scan-and-publish GitHub Action runs this from CI (#1263). - On-behalf-of identity:
donkey.as_user(token=...)forwards the user's token to the gateway's OBO policy on model calls and MCP bindings. It never falls back to the service identity (#1290, #1293, #1353, #1369, #1472). - Human in the loop:
@donkey.tool(approval="required")andToolSet.require_approval()pause gated tools with each framework's own mechanism: LangGraphinterrupt(), OpenAI Agentsneeds_approval, ADK tool confirmation and Strands interrupts (#1154, #1155, #1201, #1233, #1239, #1241). The gateway's CIBA step-up arrives as typed, waitableGatewayApprovalPending/GatewayApprovalDenied(#1329, #1376). - A2A:
donkey.serve()wraps the officiala2a-sdk, with a governed inbound (#1212, #1225).donkey devruns a simulated A2A ingress, anddonkey expose/donkey preflightput the gateway instance in front of your agent (#1287, #1330). - Refusals: declarative refusal handlers (
donkey.on(...)) react but never un-refuse (#1146). A classification registry turns custom gateway policies into typed exceptions (#1152). The kill switch stops runs cleanly (#1151), and Google Model Armor and CrowdStrike AIDR blocks are typed asContentSafetyBlocked(#1180, #1461). - A second deep adapter: the OpenAI Agents SDK joins LangGraph as a conformance-gated adapter (#1164).
- Around them: an inbound correlation ID is carried across MCP and A2A hops (#1258), and
donkey.run()keeps a run ledger (#1379). You can set the business group per request (#1190) and send a provider key for Dynamic-key routes (#1253). The budget has a stated concurrency contract (#1189) and reads the upstream provider's rate-limit window (#1246). - Hardening from the 0.2.0 code review:
- Credentials are stripped on cross-origin MCP redirects (#1459).
donkey dev,serve()and scanned endpoints are hardened for non-loopback use (#1458).- An out-of-range budget reset header no longer crashes
send()(#1456). - The 0.2.0 API stability tiers are settled, with a snapshot of the stable surface (#1460).
Extras changes (§8.4)
mcpis back (mcp>=1.24) forToolSetbinding. It was dropped in 0.1.2 and last shipped asmcp>=1.2.a2ais back (a2a-sdk[http-server]>=1.2.0,uvicorn>=0.30) fordonkey.serve(). It was dropped in 0.1.2 and last shipped asa2a-sdk>=0.1.allnow installsllm, langgraph, otel, cli, local, a2a, mcp, so it addsmcpanda2a(#1436).adk:litellm>=1.84becomeslitellm[mcp]>=1.84. From litellm 1.106,model()with tools needsmcp(#1289).cli:typer>=0.15.4becomestyper>=0.26.0, andrich>=13.0becomesrich>=13.8.0(#1200).- The base dependencies, the Python floor (3.10), the
donkeyconsole script and the pytest plugin entry point are unchanged. Extras stay floors only, with no upper pins.
Verification-status changes (§0.3)
- MCP discovery and binding. Discovery and
ToolSetbinding through the governed gateway move from blocked to VERIFIED (LIVE), 2026-10-28 (§9, #221). They run over framework binding classes that are VERIFIED (local round-trip) (#636–#652). The tool-access denial shape is VERIFIED (LIVE) (#1359). - MCP and A2A resolution. Endpoint resolution and the governed-state reads behind
explain()are VERIFIED (LIVE) (§6, #1297, #1298, #1354). - Publication. Exchange search, and the publication of scanned MCP servers and agents, move from blocked to VERIFIED (LIVE) (§7, #53, #218, #1260).
donkey verify. The read-back of a published version's MCP tools and agent card, whichdonkey verifycompares against, is VERIFIED (LIVE), 2026-10-29 (§7, #991, #1354).as_user()header. The user-token header is VERIFIED (LIVE), 2026-10-29:Authorization: Bearer <token>, on model calls and MCP bindings (§13, #255).- CIBA step-up. The pending (
401), denied (403) and initiation-failure (502) shapes are VERIFIED (LIVE), 2026-10-28 and 2026-10-29, on model and MCPtools/calltraffic (§4, #1320, #1380). - Content safety. The Google Model Armor rejection is VERIFIED (LIVE), 2026-10-19 (§4, #1178).
- CrowdStrike AIDR. The AIDR rejection is VERIFIED (POLICY SOURCE), a new evidence class (ADR 0016). Its shape is read from
crowdstrike-aidr-guardrails-policy1.0.0, not captured live, because no proxy runs it.classify()types it asContentSafetyBlocked(provider="crowdstrike-aidr"). The live capture is still open (#1184), and a capture replaces the derived shape if they differ (§4, #1176, #1429). - Still blocked, behind a
NotImplementedError("blocked on verification: …"):- the lockfile (
donkey.tools.lock(),discover(locked=True)); - the governed-state search filters (
search(governed=, environment=, domain=)); Publication.preview()/export();- the hidden
donkey status.
- the lockfile (
- No row moved from verified to blocked.
Acceptance
donkey-kit==0.2.0 from TestPyPI: passed. This was a live run of all seven groups (./run.sh --version 0.2.0 --index testpypi) on Python 3.12, against the artifact this Release publishes.
- Proxies: all 24 declared proxies were configured, and none was skipped for missing credentials.
- Results: 559 passed, 33 skipped, 0 failed.
| Session | Passed | Skipped |
|---|---|---|
[all] + langchain-mcp-adapters (data plane, governance, public surface, blocked, telemetry, frameworks) |
415 | 27 |
[all,adk] |
21 | 1 |
[all,strands] |
22 | 1 |
[all,agent_framework] |
12 | 1 |
[all,openai-agents] |
27 | 1 |
[all,anthropic] |
11 | 0 |
[all,crewai] + crewai-tools[mcp] |
12 | 1 |
[all,llamaindex] + llama-index-tools-mcp |
9 | 0 |
| packaging | 30 | 1 |
- Coverage map: consistent. 108 features are mapped, and 321 of 330 collected tests are claimed by a feature.
- Offline published gate (groups 3, 4 and 5): passed in the TestPyPI publish run for 0.2.0.
- Release candidate:
0.2.0rc1also passed the live run (546 passed, 33 skipped, 0 failed).
Full changelog: v0.1.3...v0.2.0 (promotion PR #1522)