Agents, Tools, and Managed Agents Cookbook
Purpose and Scope
This cookbook helps you decide how to build agentic workflows with the TypeScript SDK when the work spans local tools, Managed Agents, MCP-connected tools, and reusable skills. A local tool loop is best when your application owns the side effect, such as querying a private database or using credentials that should remain in your process. A Managed Agent is best when you want durable agent configuration, API-managed lifecycle operations, built-in sandbox tools, MCP server configuration, or skills that can be reused across sessions. Sources: src/lib/tools/BetaRunnableTool.ts, src/resources/beta/agents/agents.ts
The SDK source keeps those concerns separate. The local helper layer defines a runnable tool as a beta tool definition with parsing, execution, and optional cleanup behavior. The generated Managed Agents resource exposes create, retrieve, update, list, archive, and nested version listing methods under the beta agents namespace. The official Managed Agents documentation states that Managed Agents requests require the managed agents beta header; the generated resource methods append that beta value automatically while still accepting caller-supplied beta values through params. Sources: src/lib/tools/BetaRunnableTool.ts, src/resources/beta/agents/agents.ts, src/resources/beta/agents/versions.ts
Relevant Source Files
src/resources/beta/agents/index.ts- Barrel export for the Managed Agents beta resource, including agent, model, toolset, MCP, permission policy, custom tool, skill, and version-related types.src/resources/beta/agents.ts- Re-export shim that exposes the beta agents namespace from the generated resource tree.src/resources/beta/agents/agents.ts- GeneratedAgentsAPI resource with lifecycle methods for creating, retrieving, updating, listing, and archiving beta agent resources.src/resources/beta/agents/versions.ts- Generated nestedVersionsresource for listing prior versions of an agent through a cursor-backed page.src/lib/tools/BetaRunnableTool.ts- Shared contract for client-runnable tools, tool-use context, registry naming, tool error formatting, and runnable outcomes.src/lib/tools/BetaToolRunner.ts- Conversation-loop helper that iterates between Claude messages and local tools, supports streaming results, tracks state, and adds SDK helper headers.
Core Primitives
Start with a runnable tool when Claude should ask your application to perform work that only your runtime can safely perform. The tool contract combines an SDK beta tool shape with a parser, a runner, and an optional close hook. The parser converts raw model-provided input into the type your handler expects. The runner returns either a plain string or beta tool-result content blocks. The context object carries the originating tool use and an optional abort signal, which lets long-running handlers stop promptly when the surrounding request is cancelled. Sources: src/lib/tools/BetaRunnableTool.ts
The tool-use type intentionally spans two surfaces: direct beta Messages tool use and Managed Agents session event tool use. The shared fields let a handler read the identifier, name, and input without caring which surface produced the request. If a handler needs surface-specific data, narrow the shape first instead of assuming a Messages content block. That design is useful in cookbook code because one implementation can be reused first in a direct message loop and later in a Managed Agent event loop when the same operation becomes part of a larger agent workflow. Sources: src/lib/tools/BetaRunnableTool.ts
The tool runner is the local orchestration helper. It is an async iterable because an assistant response may request a tool, receive the result, and then continue for additional turns before producing the final message. The runner copies the starting messages, tracks whether the iterator has already been consumed, caches tool responses, counts API iterations, and exposes a completion promise for the last assistant message. It also collects helper metadata and adds a helper header so SDK requests identify that the higher-level runner surface is being used. Sources: src/lib/tools/BetaToolRunner.ts
Recipe: Run a Local Tool Loop
Use this pattern for application-owned tools. Define a public tool name, input schema, parser, and runner. The shared registry function resolves ordinary tools by name and MCP toolsets by MCP server name, so avoid creating a second naming convention in application code. Error behavior is also centralized. A thrown ToolError carries structured content back to the model, while other thrown values become a text error message. This keeps recovery inside the normal tool-result channel instead of turning one bad tool call into an unhandled application failure. Sources: src/lib/tools/BetaRunnableTool.ts
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();
const lookupOrder = {
name: 'lookup_order',
input_schema: {
type: 'object',
properties: { order_id: { type: 'string' } },
required: ['order_id'],
},
parse(input: unknown) {
return input as { order_id: string };
},
async run(args: { order_id: string }) {
return `Order ${args.order_id} is ready for pickup`;
},
};
const runner = client.beta.messages.toolRunner({
model: 'claude-sonnet-4-6',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Check order A123' }],
tools: [lookupOrder],
});
for await (const item of runner) {
console.log(item);
}Treat the runner as the owner of conversation state for the duration of the loop. Tool results must be appended before the next model call, so the runner mutates its internal request parameters between iterations while protecting the caller from accidental mutation of the original messages array. If streaming is enabled in the request parameters, yielded items are message streams rather than only completed messages. Downstream code should therefore decide whether it is consuming intermediate streams, waiting for the completion promise, or both, and should test cancellation through the abort signal passed into tool handlers. Sources: src/lib/tools/BetaToolRunner.ts, src/lib/tools/BetaRunnableTool.ts
Recipe: Create and Evolve a Managed Agent
Use a Managed Agent when the workflow benefits from a persistent API resource rather than a transient local conversation. The generated Agents class exposes create, retrieve, update, list, and archive operations. Create and update send request bodies, retrieve and list pass query parameters, and list returns a cursor-backed page promise that supports asynchronous iteration. Every method builds headers that append the managed agents beta value to any supplied beta list, so cookbook code can concentrate on model, toolset, MCP, skill, and lifecycle configuration without manually constructing that required beta header. Sources: src/resources/beta/agents/agents.ts
const agent = await client.beta.agents.create({
model: 'claude-sonnet-4-6',
name: 'Customer operations agent',
});
const latest = await client.beta.agents.retrieve(agent.id);
await client.beta.agents.update(agent.id, {
version: latest.version,
});
for await (const existing of client.beta.agents.list()) {
console.log(existing.id, existing.name);
}Version history is the operational companion to updates. The nested versions resource lists prior agent versions for one agent through the same cursor pagination shape used by agent listing. Use it after changing model settings, custom tool definitions, MCP configuration, skills, or permission policy choices so deployments can record what configuration was active at a point in time. Archive is the lifecycle endpoint for taking an agent out of active use while still receiving an agent-shaped response from the API. Sources: src/resources/beta/agents/versions.ts, src/resources/beta/agents/agents.ts
Recipe: Add Built-In Tools, MCP, and Skills
Managed Agent tools are configured differently from local runnable tools. The SDK index exports types for the managed agent toolset, per-tool configs, default configs, and permission policies, matching the product concept that an agent can use built-in tools autonomously inside its managed environment. Official docs describe bash, read, write, edit, glob, grep, web fetch, and web search as the built-in toolset names. Use this path when the agent should operate in its sandbox or managed environment instead of asking your application to execute every operation. Sources: src/resources/beta/agents/index.ts
MCP belongs to the server-provided tool category, not the local runnable tool category. The runnable-tool source explicitly says client-runnable tools exclude server-side tools such as MCP toolsets, while the shared tool-name helper still knows how to key MCP toolsets by server name. The agents index exports MCP server URL definitions, MCP toolsets, default configs, per-tool configs, and URL MCP server params. In practice, use local runnable tools for application-executed code, and use MCP configuration when an external server should expose a collection of tools to a Managed Agent. Sources: src/lib/tools/BetaRunnableTool.ts, src/resources/beta/agents/index.ts
Skills are reusable expertise attached to an agent rather than imperative functions. The official docs describe them as filesystem-based resources that load on demand for domain-specific workflows, and the SDK index mirrors the distinction between Anthropic skills, custom skills, and generic skill params. Use skills when you want a durable way to teach document handling, operational procedure, or domain best practices without forcing every conversation to include a long prompt. In a cookbook flow, create or choose the skill first, then reference it alongside model and tool configuration when creating or updating the agent. Sources: src/resources/beta/agents/index.ts
Compact Reference
| Surface | Public entry point or type | Cookbook use |
|---|---|---|
| Local runnable tool | BetaRunnableTool<Input> | Define parsing, execution, and optional cleanup for application-run tools. |
| Tool context | BetaToolRunContext | Read the originating tool use and cancellation signal. |
| Tool runner | BetaToolRunner<Stream> | Iterate through assistant messages or message streams while the SDK handles tool-response turns. |
| Agent create | client.beta.agents.create(params) | Create a persistent Managed Agent with model and configuration. |
| Agent lifecycle | retrieve, update, list, archive | Read, modify, paginate, and archive Managed Agent resources. |
| Agent versions | client.beta.agents.versions.list(agentID) | Inspect prior versions of one agent through an async cursor. |
| Built-in toolset | BetaManagedAgentsAgentToolset20260401* | Configure sandbox-style Managed Agent tools and tool settings. |
| MCP tools | BetaManagedAgentsMCPToolset* | Attach server-provided MCP tools instead of local application functions. |
| Skills | BetaManagedAgentsAnthropicSkill*, BetaManagedAgentsCustomSkill* | Attach reusable expertise to an agent configuration. |
Next Steps
Begin with a local runnable tool when the main risk is safe execution of secrets, side effects, or application state. Move to Managed Agents when the workflow needs durable configuration, built-in toolsets, MCP connectivity, skills, version tracking, or API-managed lifecycle operations. Before production, test parse failures, ordinary exceptions, ToolError responses, cancellation, and cleanup hooks. After each agent update, list versions and record the active version beside deployment metadata. For deeper implementation detail, read Tool Helpers, MCP Integration, Agent Skills, Managed Agent Setup, and Managed Agent Sessions next.