Skip to main content
P2 Beginner

Tool Use & Permissions

Build a tool-using agent with real SDK code. Learn allowedTools, canUseTool, and permission control.

SDK APIs allowedTools canUseTool tool_call tool_result

Exercise 1: First Tool-Using Agent

Create an agent that uses file tools. Copy this code and run it.

Starter Code exercise-1.ts
import { query } from "@anthropic-ai/claude-agent-sdk";

// Your first tool-using agent
const response = query({
  prompt: "List all TypeScript files in the current directory and count them",
  options: {
    allowedTools: ["Read", "Glob", "Bash"],
    // disallowedTools: ["Write", "Edit"]  // alternative approach
  }
});

for await (const msg of response) {
  if (msg.type === "tool_call") {
    console.log(`[Tool] ${msg.tool_name}(${JSON.stringify(msg.tool_input).slice(0, 80)})`);
  }
  if (msg.type === "tool_result") {
    console.log(`[Result] ${msg.content.slice(0, 100)}`);
  }
  if (msg.type === "result") {
    console.log(`\n[Answer] ${msg.content}`);
  }
}

Your task: Run this code. Observe which tools are called and in what order. Then modify allowedTools to only allow ["Glob"] — what changes?

Exercise 2: Permission Gate

Add a canUseTool callback that logs every tool request and blocks dangerous commands.

Exercise Code exercise-2.ts
import { query } from "@anthropic-ai/claude-agent-sdk";

const response = query({
  prompt: "Clean up temp files and organize the project",
  options: {
    allowedTools: ["Read", "Write", "Bash", "Glob"],

    canUseTool: async (toolName, input) => {
      // TODO 1: Log every tool request with timestamp
      console.log(`[${new Date().toISOString()}] ${toolName}`, input);

      // TODO 2: Always allow read-only tools
      if (/* your condition */) {
        return { behavior: "allow" };
      }

      // TODO 3: Block rm, sudo, dd commands
      if (/* your condition */) {
        return { behavior: "deny", message: "Blocked: dangerous command" };
      }

      // TODO 4: Ask for human confirmation on everything else
      return { behavior: "ask", message: `Allow ${toolName}?` };
    }
  }
});

for await (const msg of response) {
  console.log(msg.type, msg.content?.slice?.(0, 100) ?? "");
}

Your task: Fill in the TODO conditions. Test with prompts like "delete all .tmp files" and verify the deny behavior.

Exercise 3: Tool Call Logger

Build a complete tool usage analytics system.

Challenge exercise-3.ts
// Build a tool analytics system:
// 1. Track how many times each tool is called
// 2. Measure execution time for each tool call
// 3. Record success/failure rates
// 4. Output a summary at the end:
//    Tool      | Calls | Avg Time | Success Rate
//    Read      | 5     | 120ms    | 100%
//    Bash      | 3     | 890ms    | 67%
//    Glob      | 2     | 45ms     | 100%
//
// Hint: Use message.type to track tool_call and tool_result pairs
// Hint: Generate unique IDs for each call to match calls with results
← Back to Exercises