
Claude and the Claude Agent SDK are trademarks of Anthropic, used here for identification and integration guidance only. No endorsement, partnership, or affiliation is implied.
- What the SDK ships — the agent loop (
query/ClaudeSDKClient), tool permissions (allowed_tools,can_use_tool), subagents, hooks, sessions, and MCP clients overstdio,http, andsse— including auth headers on remote servers. - What it doesn’t ship — a way for those agents to act as a real account: sign up for a SaaS tool, hold a funded card, or spend within a budget you control, per end-user.
How the pairing works
- The SDK turns any MCP server into a set of tools: add a server to
mcp_servers, allow its tools, and each MCP tool becomes a function the model can call — no manual schema wiring. - Naive ships a hosted MCP server and mints per-user sessions — short-lived, revocable SSE endpoints whose tool list is the fused native + third-party toolset, already filtered by that user’s Account Kit.
- Each session is one URL + one bearer scoped to one user. Register it under
mcp_servers, allowmcp__naive__*, and every tool call runs as that user — gated server-side.
Tested against:
claude-agent-sdk 0.2.x (Python: query, ClaudeAgentOptions,
can_use_tool, McpSSEServerConfig) — equivalently @anthropic-ai/claude-agent-sdk
0.3.x (TypeScript) — backed by the Claude Code CLI 2.x, and Naive API v2 (hosted
MCP server over SSE + per-user sessions), on Python ≥ 3.10 / Node ≥ 18.The Claude Agent SDK spawns the Claude Code CLI under the hood, so Node.js and the CLI must
be installed even for the Python SDK. Naive’s session URL contains /mcp/sse/…, so register
it with "type": "sse". The SDK and CLI now recommend streamable-HTTP for new servers and mark
SSE as deprecated, but SSE is still fully supported — use it to match Naive’s endpoint. The
scoped bearer rides in the connection headers, never in the URL. There is no Python Naive
SDK yet, so the control plane (Account Kit, user, session) is shown over the REST API; you can
equally provision from the dashboard, the CLI, or the Node
SDK. Pin your versions and set the model to one you have access to.Prerequisites
- A Naive API key (
nv_sk_...) — get one from the dashboard. - An
ANTHROPIC_API_KEYfor the Claude model that runs the agent. - Node.js ≥ 18 and the Claude Code CLI (the SDK’s runtime):
npm install -g @anthropic-ai/claude-code. - Python ≥ 3.10.
Minimal viable integration
The shortest path to a Claude Agent SDK agent that can actually transact: define a policy and provision a user (control plane, once), then at runtime mint a per-user MCP session and hand it toquery().
Define the policy, then provision a user
An Account Kit is the spend/capability policy. Here a tenant
user gets a card (capped at $500, approval required), the vault, and an allowlist of apps.
Everything the agent does is bounded by this kit — server-side. These are one-time
control-plane calls:
Mint a per-user MCP session
At runtime, mint a short-lived session for the user. It returns the
scoped SSE endpoint and a bearer that lives in the headers — never in the URL — and expires
(default 15 min, max 24h):
Build the agent — and let it transact
Register the session’s scoped SSE endpoint under The model discovers GitHub (
mcp_servers, allow its tools with a
wildcard, and call query(). The SDK discovers Naive’s tools, exposes them to the model, and
runs the whole tool-calling loop for you:mcp__naive__naive_connections_connect), returns a connect link
for Alice to authorize, and attempts to issue the card
(mcp__naive__naive_cards_create) — a real card on Alice’s account, capped by her kit. The
whole agent loop is the SDK’s; the real-world actions are Naive’s.MCP tools require explicit permission — without
allowed_tools, the model sees Naive’s tools
but can’t call them. The session’s tool list is already filtered by Alice’s kit, so the agent
never sees a tool the policy forbids. To narrow further, list exact tool names instead of a
wildcard (e.g. allowed_tools=["mcp__naive__naive_connections_connect", "mcp__naive__naive_cards_create"]),
or mint the session against a tighter kit.Extension: human-in-the-loop spend (two gates)
Because the kit setcards.requiresApproval: true, the agent cannot silently spend. Pair
the SDK’s in-run permission callback with Naive’s server-side gate for defense in depth:
- In the run — a
can_use_toolcallback lets you inspect every tool call before it fires and hold the sensitive ones for review. - On the server — even if a call gets through, Naive freezes it and returns a pending
approval (HTTP
202) instead of a live card. This holds no matter what runtime calls it.
can_use_tool. It runs before the tool executes and returns
either PermissionResultAllow or PermissionResultDeny:
can_use_tool requires the SDK’s streaming mode, so pass the prompt as an async iterable
of message dicts rather than a plain string:
pending → executed / failed / denied) and the deny endpoint.
The
can_use_tool callback shapes the run from inside your app; the real enforcement is
Naive’s server-side approval gate above, which can’t be bypassed from the prompt, the
allowed_tools list, or the agent config.Approvals are only enforced for agent (API-key / MCP) calls on real tenant users. A human
acting in your dashboard, and agent calls on the operator’s own default user, bypass the
gate — so end-user agents stay governed while your own automation isn’t slowed down.
Alternative: one agent definition, every tenant
A Naive session is scoped to one user, so to serve every tenant from the same agent definition, mint a fresh session per request and build the options from it. The model, system prompt, and allowed tools stay the same — only which user’s session backs the toolset changes, and every call is Account-Kit-gated server-side:DELETE /v1/users/{user_id}/sessions/{id}.
TypeScript? The SDK is the same shape in Node: register the session under
mcpServers
({ type: "sse", url, headers }), allow ["mcp__naive__*"], and call query(...) from
@anthropic-ai/claude-agent-sdk. On TypeScript you can also provision the control plane with
the @usenaive-sdk/server SDK (naive.accountKits.create, naive.users.create,
client.session(...)) instead of raw REST.What stays enforced
No matter how the agent is wired, the policy is enforced where it matters — on Naive’s servers, not in your prompt or your agent config:- Identity — every action runs as a specific tenant user, fully isolated from your other users.
- Capability bounds — the Account Kit decides which
primitives and which apps the agent can touch (
allowlist/blocklist/ per-tool). - Scoped spend — virtual cards are capped per card and per user; the model can’t raise its own limit.
- Human-in-the-loop — sensitive actions (cards, domains, KYC, formation, connecting an app) freeze as approvals until a human says yes.
- Scoped, expiring access — the agent holds a per-user session bearer, not your API key;
it expires (default 15 min) and you can
DELETE /v1/users/:user_id/sessions/:idto revoke it early.
Next steps
- MCP server — the hosted SSE server and its full tool list
- Sessions — per-user MCP sessions, TTL, and revocation
- Account Kits — author spend/capability policy
- Approvals — the human-in-the-loop lifecycle
- Pydantic AI · LlamaIndex · Agno — the same MCP-session pairing for other Python stacks