Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build Claude agents using TypeScript with the @anthropic-ai/claude-agent-sdk. Use this skill when implementing conversational agents, building tools for agents, setting up streaming responses, or debugging agent implementations. Covers the tool wrapping pattern, SDK initialization, agent architecture, and best practices.
.claude/skills/majiayu000-claude-agent-ts-sdk/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 78% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 134% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 87% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 95% | 0% |
Build production-ready Claude agents using TypeScript and the @anthropic-ai/claude-agent-sdk. This skill provides battle-tested patterns for creating modular, composable agent tools.
typescriptimport { query, createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk'; import { z } from 'zod'; // 1. Define tools const greetTool = tool( 'greet', 'Greet a user by name', z.object({ name: z.string().describe('User name'), }).shape, async ({ name }) => ({ content: [{ type: 'text', text: `Hello, ${name}!` }], }) ); // 2. Create MCP server const server = createSdkMcpServer({ name: 'my-agent', version: '1.0.0', tools: [greetTool], }); // 3. Query with streaming const messages = query({ prompt: 'Greet Alice', options: { systemPrompt: 'You are a helpful agent.', permissionMode: 'bypassPermissions', mcpServers: { 'my-agent': server }, }, }); // 4. Process stream for await (const event of messages) { if (event.type === 'assistant') { for (const content of event.message.content) { if (content.type === 'text') { console.log(content.text); } } } }
Use when:
Tools are the building blocks of agent capabilities. Use the tool() function to create them:
typescriptimport { tool } from '@anthropic-ai/claude-agent-sdk'; import { z } from 'zod'; const myTool = tool( 'tool_name', // Name (lowercase, underscores) 'What it does', // Clear description z.object({ // Zod schema for validation param: z.string().describe('Parameter description'), }).shape, async (params) => { // Implementation return { content: [{ type: 'text', text: 'Result' }], }; } );
Key Points:
{ content: [{ type: 'text', text: string }] }Wrap tools in MCP servers for query execution:
typescriptimport { createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk'; const server = createSdkMcpServer({ name: 'server-name', version: '1.0.0', tools: [tool1, tool2], });
Important: Create servers at query time, not module level (enables dynamic tool selection).
Execute agent queries with real-time streaming:
typescriptimport { query } from '@anthropic-ai/claude-agent-sdk'; const messages = query({ prompt: 'User request here', options: { systemPrompt: 'Agent role and instructions', permissionMode: 'bypassPermissions', // For standalone servers mcpServers: { 'server-name': server, }, }, }); for await (const event of messages) { // Process events: 'assistant', 'user', 'error' }
For streaming patterns and event handling, see references/streaming.md
System prompts define agent behavior (100-170+ lines recommended):
typescriptconst SYSTEM_PROMPT = `You are a specialized agent that... ## Available Tools [Detailed tool descriptions] ## Workflow [Step-by-step instructions] ## Output Format [Expected response structure] `;
For system prompt best practices, see references/system-prompts.md
Choose the pattern that fits your use case:
Best for: Command-line tools, batch processing
typescriptexport async function runAgent(userPrompt: string) { const server = createSdkMcpServer({ name: 'cli-agent', version: '1.0.0', tools }); const messages = query({ prompt: userPrompt, options: { systemPrompt, permissionMode: 'bypassPermissions', mcpServers: { 'cli-agent': server } } }); for await (const event of messages) { if (event.type === 'assistant') { for (const content of event.message.content) { if (content.type === 'text') process.stdout.write(content.text); } } } }
Best for: Web applications, APIs, real-time UIs
typescriptapp.post('/agent/stream', async (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); const server = createSdkMcpServer({ name: 'web-agent', version: '1.0.0', tools }); const messages = query({ prompt: req.body.prompt, options: { systemPrompt, mcpServers: { 'web-agent': server } } }); for await (const event of messages) { res.write(`data: ${JSON.stringify(event)}\n\n`); } res.end(); });
Best for: Extensible systems, plugin architectures
typescriptexport class AgentEngine { async stream(prompt: string) { const tools = this.plugin.getTools(); const server = createSdkMcpServer({ name: this.plugin.name, version: '1.0.0', tools }); const messages = query({ prompt, options: { systemPrompt: this.plugin.systemPrompt, permissionMode: 'bypassPermissions', mcpServers: { [this.plugin.name]: server } } }); for await (const event of messages) { await this.plugin.handleEvent(event); } } }
For complete architecture patterns including monorepo setup, see references/patterns.md
json{ "name": "my-agent", "type": "module", "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.1.14", "zod": "^3.23.8" }, "devDependencies": { "typescript": "^5.3.3", "tsx": "^4.7.0" } }
my-agent/
├── src/
│ ├── index.ts # Entry point
│ ├── agent.ts # Agent implementation
│ ├── tools/ # Tool definitions
│ └── prompts/ # System prompts
├── package.json
└── tsconfig.jsonFor complete project setup including TypeScript config, see references/project-setup.md
typescriptconst readFile = tool('read_file', 'Read file contents', z.object({ path: z.string() }).shape, async ({ path }) => ({ content: [{ type: 'text', text: await fs.readFile(path, 'utf-8') }] }) ); const writeFile = tool('write_file', 'Write to file', z.object({ path: z.string(), content: z.string() }).shape, async ({ path, content }) => { await fs.writeFile(path, content); return { content: [{ type: 'text', text: 'Done' }] }; } );
typescriptconst SYSTEM_PROMPT = `You are a file management agent. When user asks to edit a file: 1. read_file to see current contents 2. Propose changes 3. write_file to save changes`;
typescriptconst server = createSdkMcpServer({ name: 'files', version: '1.0.0', tools: [readFile, writeFile] }); const messages = query({ prompt: userRequest, options: { systemPrompt: SYSTEM_PROMPT, permissionMode: 'bypassPermissions', mcpServers: { 'files': server } } });
Create tool factories that close over session-specific data:
typescriptfunction createSessionTools(userId: string) { return [ tool('get_user_data', 'Get user data', {}, async () => { const data = await db.getUser(userId); // Closure over userId return { content: [{ type: 'text', text: JSON.stringify(data) }] }; }) ]; } // Per-session tools app.post('/agent', async (req, res) => { const tools = createSessionTools(req.session.userId); const server = createSdkMcpServer({ name: 'session', version: '1.0.0', tools }); // ... rest of agent setup });
permissionMode: 'bypassPermissions' for standalone servers"type": "module" consistentlyinteractive permission mode in standalone serversNo configuration required! The SDK automatically uses Claude Code's authentication. Your agent works seamlessly within Claude Code without any API key setup.
typescriptconst messages = query({ prompt, options: { systemPrompt, mcpServers, onToolCall: (name, params) => console.log(`[CALL] ${name}`, params), onToolResult: (name, result) => console.log(`[RESULT] ${name}`, result), }, });
typescript// Test before integrating const result = await myTool.execute({ param: 'test' }); console.log('Tool output:', result);
"Claude Code process exited with code 1"
permissionMode: 'bypassPermissions' for standalone serversTools not being called
Import errors
"type": "module" in package.json.js extensions in imports (Node16 resolution)This skill includes detailed reference documentation:
Other measured skills in the registry, with their headline benchmark lift.