The Claude Agent SDK registers paid work through in-process MCP tool() definitions. Paybond wraps those handlers so Harbor verifies spend before execution and auto-submits evidence after success. Built-in Claude tools (Read, Bash, etc.) pass through unguarded.
Beta: The Claude Agent SDK is evolving. Treat this adapter as beta until Anthropic stabilizes the SDK.
Adapter reference: /docs/kit/claude-agents.
spend verify before handlers
In-process MCP tool() handlers authorize operation and amount before paid work runs.
Auto-evidence
Wrapped handlers finalize spend and submit signed evidence after tool success.
Policy budgets
Versioned YAML caps per-call and intent spend — built-in Claude tools pass through unguarded.
TypeScript and Python
Same claude-agents adapter on npm and pip (paybond-kit[claude-agents]).
Why Paybond (not just SDK guardrails)?
Claude Agent SDK approvals and host checks do not enforce a spend limit, a per-operation permission check (capability token), or a signed completion receipt tied to a spend agreement (intent).
Model / input guardrails
- SDK alone
- Yes — SDK or host checks and approvals
- With Paybond
- Yes — plus Harbor authorize at the tool boundary
Spend boundary
- SDK alone
- No per-tool Harbor budget or capability token
- With Paybond
- Per-call and intent budgets enforced before invoke
Signed evidence
- SDK alone
- SDK traces / logs only
- With Paybond
- Signed completion digests bound to the intent
Intent binding
- SDK alone
- No Harbor intent or settlement receipt
- With Paybond
- Capability token + intentId from authenticated bind
Paid tool deny / HITL
- SDK alone
- Host or SDK approvals only
- With Paybond
- spend verify, deny, or HITL hold before side effects
| Capability | SDK alone | With Paybond |
|---|---|---|
| Model / input guardrails | Yes — SDK or host checks and approvals | Yes — plus Harbor authorize at the tool boundary |
| Spend boundary | No per-tool Harbor budget or capability token | Per-call and intent budgets enforced before invoke |
| Signed evidence | SDK traces / logs only | Signed completion digests bound to the intent |
| Intent binding | No Harbor intent or settlement receipt | Capability token + intentId from authenticated bind |
| Paid tool deny / HITL | Host or SDK approvals only | spend verify, deny, or HITL hold before side effects |
How it works
Adapter flow
tool() handler
Claude Agent SDK calls an in-process MCP custom tool
Paybond wrap
Harbor authorize before your handler runs
- Verify spend and operation
- Deny or HITL hold
- Issue / check capability
Handler runs
Your tool body performs the paid work
Evidence
Wrapped handler finalizes spend + auto-evidence
Paybond wraps Claude Agent SDK tool() handlers: Harbor authorize before the handler runs, then auto-evidence after success.
3-minute quickstart
Smoke the claude-agents adapter sandbox contract — no Anthropic credentials required for this check:
terminal
paybond login
paybond agent demo claude-agents smoke \
--operation paid-tool \
--requested-spend-cents 100 \
--evidence-preset cost_and_completion \
--format tableWhen the smoke succeeds you should see:
- ✓ Spend approved
- ✓ Tool completed
- ✓ Evidence verified (
cost_and_completion)
What success looks like
What success looks like
Authorized tool call · illustrative
- Operation
- paid-tool
- Status
- Approved
- Requested
- $1.00
- Evidence
- Verified
- Preset
- cost_and_completion
Scaffold
terminal
paybond init agent-middleware --framework claude-agents --out paybond-claude-agents.ts
paybond policy init --preset travel --out paybond.policy.yamlValidate before deploy:
terminal
paybond policy validate-tools --file paybond.policy.yaml --local-onlyWire middleware
Recommended wiring
paybond.agent with framework claude-agents returns claudeAgentsConfig so Harbor wraps tool() handlers before query().
paybond-session.ts
import { tool, query } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
import { Paybond } from "@paybond/kit";
const paybond = await Paybond.open({ apiKey: process.env.PAYBOND_API_KEY! });
const sdkTools = [
tool(
"travel.book_hotel",
"Book a hotel room",
{ city: z.string(), estimatedPriceCents: z.number() },
async (args) => ({
content: [{ type: "text", text: JSON.stringify(await bookHotel(args)) }],
structuredContent: await bookHotel(args),
}),
),
];
const { claudeAgentsConfig } = await paybond.agent({
policy: "travel",
framework: "claude-agents",
tools: sdkTools,
});
const { mcpServer, allowedTools } = claudeAgentsConfig!;
await query({
prompt: "Book a hotel in Lisbon under budget.",
options: {
mcpServers: { paybond: mcpServer },
allowedTools,
},
});Install extras: pip install "paybond-kit[claude-agents]".
Production: omit sandbox defaults, use deferred bind, then instrumented.bind({ intentId, capabilityToken }) per session. Tenant and intent IDs come from the Paybond session binding — never from unauthenticated tool args.
Production checklist
Production checklist
- Scaffold middleware with paybond init agent-middleware --framework claude-agents
- Init a policy preset (e.g. travel) and validate tools
- Wire paybond.agent({ framework: "claude-agents", tools })
- Bind intentId and capabilityToken per session in production
- Smoke with paybond agent demo claude-agents smoke before ship
Works with
Works with
- Anthropic
- OpenAI
- Vercel
- MCP
Ready to test?
Related guides
- Agent middleware — run binding and tenant isolation
- MCP agent spend controls — stdio MCP hosts
- Agent-agnostic spend controls — Claude tool-use without the Agent SDK
Developer reference: /docs/kit/claude-agents.