Tutorials · Claude Agent SDK · examples / typescript / agent.tsExample code

Example code · typescript

agent.ts

TypeScript demo: a read-only query, then a custom tool defined with Zod.

Raw fileDownload all examples (zip)See its output →

Used in Part 2 · Custom tools: your own functions

// TypeScript demo: a read-only query, then a custom tool defined with Zod.
import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";

const PROJECT = new URL("../project", import.meta.url).pathname;

// --- Part 1: plain query over the sample project -------------------------------
console.log("=== Part 1: read-only query ===");
for await (const message of query({
  prompt: "Which file in this project contains a hardcoded secret? Reply with the path and line only.",
  options: { cwd: PROJECT, allowedTools: ["Read", "Glob", "Grep"], maxTurns: 6 },
})) {
  if (message.type === "system" && message.subtype === "init") {
    console.log(`init: model=${message.model} cli=${message.claude_code_version} session=${message.session_id}`);
  } else if (message.type === "assistant") {
    for (const block of message.message.content) {
      if (block.type === "tool_use") console.log(`tool_use: ${block.name}`);
    }
  } else if (message.type === "result") {
    console.log(`result: ${message.subtype} cost=$${message.total_cost_usd.toFixed(4)} turns=${message.num_turns}`);
    if (message.subtype === "success") console.log(`answer: ${message.result}`);
  }
}

// --- Part 2: a custom tool with a Zod schema -------------------------------------
console.log("\n=== Part 2: custom tool ===");
const convert = tool(
  "convert_temperature",
  "Convert a temperature between Celsius and Fahrenheit",
  {
    value: z.number().describe("The temperature value"),
    from: z.enum(["C", "F"]).describe("Unit of the input value"),
  },
  async ({ value, from }) => {
    const result = from === "C" ? (value * 9) / 5 + 32 : ((value - 32) * 5) / 9;
    const to = from === "C" ? "F" : "C";
    return { content: [{ type: "text", text: `${value}°${from} = ${result.toFixed(1)}°${to}` }] };
  },
  { annotations: { readOnlyHint: true } },
);

const server = createSdkMcpServer({ name: "temps", version: "1.0.0", tools: [convert] });

for await (const message of query({
  prompt: "What is 100°F in Celsius and 37°C in Fahrenheit? Use the tool for both.",
  options: {
    cwd: PROJECT,
    mcpServers: { temps: server },
    allowedTools: ["mcp__temps__convert_temperature"],
    tools: [], // no built-in tools
    maxTurns: 6,
  },
})) {
  if (message.type === "assistant") {
    for (const block of message.message.content) {
      if (block.type === "tool_use") console.log(`tool_use: ${block.name}(${JSON.stringify(block.input)})`);
    }
  } else if (message.type === "user" && Array.isArray(message.message.content)) {
    for (const block of message.message.content) {
      if (block.type === "tool_result") console.log(`tool_result: ${JSON.stringify(block.content)}`);
    }
  } else if (message.type === "result" && message.subtype === "success") {
    console.log(`answer: ${message.result}`);
  }
}

66 lines · Back to the folder