TypeScript SDK
The @anthropic-ai/claude-agent-sdk package exposes a single async-generator query() function plus helpers for tools, MCP, and runtime control, all strongly typed.
Why it matters
Node/TypeScript is the default for web backends, Lambdas, and CI scripts, so this is the most common way to embed Claude Code. Full typings on Options, SDKMessage, and PermissionMode mean misconfigured tools or modes fail at compile time, not at runtime in production.
How it works
query() returns a Query — an AsyncGenerator<SDKMessage, void> that also carries control methods. You iterate messages; you call methods to steer mid-run.
function query({ prompt, options }: {
prompt: string | AsyncIterable<SDKUserMessage>;
options?: Options;
}): Query;Optionsessentials:systemPrompt,model,allowedTools/disallowedTools,permissionMode,maxTurns,mcpServers,hooks,canUseTool,cwd,resume,continue,settingSources,agents,abortController,maxBudgetUsd.Querycontrol methods (work in streaming-input mode):interrupt(),setPermissionMode(mode),setModel(model),streamInput(stream),close().permissionModeis one of:'default','acceptEdits','bypassPermissions','plan'. Maps to permission-modes.- Message stream is a union
SDKMessage; branch onmessage.type. The terminalSDKResultMessage(type: "result") carriestotal_cost_usd,num_turns,duration_ms, andusage. - Install:
npm install @anthropic-ai/claude-agent-sdk. A native Claude Code binary ships as an optional dependency, so no separate CLI install is needed.
Example
Read the result and cost from a one-shot run:
import { query } from "@anthropic-ai/claude-agent-sdk";
const q = query({
prompt: "Summarize README.md in 3 bullets",
options: { allowedTools: ["Read"], maxTurns: 3 }
});
for await (const m of q) {
if (m.type === "result")
console.log(m.subtype, `$${m.total_cost_usd}`, `${m.num_turns} turns`);
}Pitfalls
interrupt()only works with streaming input. Pass anAsyncIterable<SDKUserMessage>(not a plain string) or the control channel is inert — see programmatic-sessions-streaming.- Iterate to completion or you leak the subprocess. Breaking early without
q.close()(or anabortController) can orphan the Claude Code child process. allowedTools≠ enabling tools. It auto-approves allow-deny-rules; the tool must still be available. MCP tools need theirmcp__server__toolname.- No top-level
await?for awaitmust sit inside anasyncfunction or an ESM module configured for it.