Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Build LLM-powered apps with the Anthropic Claude API or SDK across Python, TypeScript, Java, Go, Ruby, C#, and PHP.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
python/claude-api/tool-use.md
1# Tool Use — Python23For conceptual overview (tool definitions, tool choice, tips), see [shared/tool-use-concepts.md](../../shared/tool-use-concepts.md).45## Tool Runner (Recommended)67**Beta:** The tool runner is in beta in the Python SDK.89Use the `@beta_tool` decorator to define tools as typed functions, then pass them to `client.beta.messages.tool_runner()`:1011```python12import anthropic13from anthropic import beta_tool1415client = anthropic.Anthropic()1617@beta_tool18def get_weather(location: str, unit: str = "celsius") -> str:19"""Get current weather for a location.2021Args:22location: City and state, e.g., San Francisco, CA.23unit: Temperature unit, either "celsius" or "fahrenheit".24"""25# Your implementation here26return f"72°F and sunny in {location}"2728# The tool runner handles the agentic loop automatically29runner = client.beta.messages.tool_runner(30model="claude-opus-4-7",31max_tokens=16000,32tools=[get_weather],33messages=[{"role": "user", "content": "What's the weather in Paris?"}],34)3536# Each iteration yields a BetaMessage; iteration stops when Claude is done37for message in runner:38print(message)39```4041For async usage, use `@beta_async_tool` with `async def` functions.4243**Key benefits of the tool runner:**4445- No manual loop — the SDK handles calling tools and feeding results back46- Type-safe tool inputs via decorators47- Tool schemas are generated automatically from function signatures48- Iteration stops automatically when Claude has no more tool calls4950---5152## MCP Tool Conversion Helpers5354**Beta.** Convert [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) tools, prompts, and resources to Anthropic API types for use with the tool runner. Requires `pip install anthropic[mcp]` (Python 3.10+).5556> **Note:** The Claude API also supports an `mcp_servers` parameter that lets Claude connect directly to remote MCP servers. Use these helpers instead when you need local MCP servers, prompts, resources, or more control over the MCP connection.5758### MCP Tools with Tool Runner5960```python61from anthropic import AsyncAnthropic62from anthropic.lib.tools.mcp import async_mcp_tool63from mcp import ClientSession64from mcp.client.stdio import stdio_client, StdioServerParameters6566client = AsyncAnthropic()6768async with stdio_client(StdioServerParameters(command="mcp-server")) as (read, write):69async with ClientSession(read, write) as mcp_client:70await mcp_client.initialize()7172tools_result = await mcp_client.list_tools()73# tool_runner is sync — returns the runner, not a coroutine74runner = client.beta.messages.tool_runner(75model="claude-opus-4-7",76max_tokens=16000,77messages=[{"role": "user", "content": "Use the available tools"}],78tools=[async_mcp_tool(t, mcp_client) for t in tools_result.tools],79)80async for message in runner:81print(message)82```8384For sync usage, use `mcp_tool` instead of `async_mcp_tool`.8586### MCP Prompts8788```python89from anthropic.lib.tools.mcp import mcp_message9091prompt = await mcp_client.get_prompt(name="my-prompt")92response = await client.beta.messages.create(93model="claude-opus-4-7",94max_tokens=16000,95messages=[mcp_message(m) for m in prompt.messages],96)97```9899### MCP Resources as Content100101```python102from anthropic.lib.tools.mcp import mcp_resource_to_content103104resource = await mcp_client.read_resource(uri="file:///path/to/doc.txt")105response = await client.beta.messages.create(106model="claude-opus-4-7",107max_tokens=16000,108messages=[{109"role": "user",110"content": [111mcp_resource_to_content(resource),112{"type": "text", "text": "Summarize this document"},113],114}],115)116```117118### Upload MCP Resources as Files119120```python121from anthropic.lib.tools.mcp import mcp_resource_to_file122123resource = await mcp_client.read_resource(uri="file:///path/to/data.json")124uploaded = await client.beta.files.upload(file=mcp_resource_to_file(resource))125```126127Conversion functions raise `UnsupportedMCPValueError` if an MCP value cannot be converted (e.g., unsupported content types like audio, unsupported MIME types).128129---130131## Manual Agentic Loop132133Use this when you need fine-grained control over the loop (e.g., custom logging, conditional tool execution, human-in-the-loop approval):134135```python136import anthropic137138client = anthropic.Anthropic()139tools = [...] # Your tool definitions140messages = [{"role": "user", "content": user_input}]141142# Agentic loop: keep going until Claude stops calling tools143while True:144response = client.messages.create(145model="claude-opus-4-7",146max_tokens=16000,147tools=tools,148messages=messages149)150151# If Claude is done (no more tool calls), break152if response.stop_reason == "end_turn":153break154155# Server-side tool hit iteration limit; re-send to continue156if response.stop_reason == "pause_turn":157messages = [158{"role": "user", "content": user_input},159{"role": "assistant", "content": response.content},160]161continue162163# Extract tool use blocks from the response164tool_use_blocks = [b for b in response.content if b.type == "tool_use"]165166# Append assistant's response (including tool_use blocks)167messages.append({"role": "assistant", "content": response.content})168169# Execute each tool and collect results170tool_results = []171for tool in tool_use_blocks:172result = execute_tool(tool.name, tool.input) # Your implementation173tool_results.append({174"type": "tool_result",175"tool_use_id": tool.id, # Must match the tool_use block's id176"content": result177})178179# Append tool results as a user message180messages.append({"role": "user", "content": tool_results})181182# Final response text183final_text = next(b.text for b in response.content if b.type == "text")184```185186---187188## Handling Tool Results189190```python191response = client.messages.create(192model="claude-opus-4-7",193max_tokens=16000,194tools=tools,195messages=[{"role": "user", "content": "What's the weather in Paris?"}]196)197198for block in response.content:199if block.type == "tool_use":200tool_name = block.name201tool_input = block.input202tool_use_id = block.id203204result = execute_tool(tool_name, tool_input)205206followup = client.messages.create(207model="claude-opus-4-7",208max_tokens=16000,209tools=tools,210messages=[211{"role": "user", "content": "What's the weather in Paris?"},212{"role": "assistant", "content": response.content},213{214"role": "user",215"content": [{216"type": "tool_result",217"tool_use_id": tool_use_id,218"content": result219}]220}221]222)223```224225---226227## Multiple Tool Calls228229```python230tool_results = []231232for block in response.content:233if block.type == "tool_use":234result = execute_tool(block.name, block.input)235tool_results.append({236"type": "tool_result",237"tool_use_id": block.id,238"content": result239})240241# Send all results back at once242if tool_results:243followup = client.messages.create(244model="claude-opus-4-7",245max_tokens=16000,246tools=tools,247messages=[248*previous_messages,249{"role": "assistant", "content": response.content},250{"role": "user", "content": tool_results}251]252)253```254255---256257## Error Handling in Tool Results258259```python260tool_result = {261"type": "tool_result",262"tool_use_id": tool_use_id,263"content": "Error: Location 'xyz' not found. Please provide a valid city name.",264"is_error": True265}266```267268---269270## Tool Choice271272```python273response = client.messages.create(274model="claude-opus-4-7",275max_tokens=16000,276tools=tools,277tool_choice={"type": "tool", "name": "get_weather"}, # Force specific tool278messages=[{"role": "user", "content": "What's the weather in Paris?"}]279)280```281282---283284## Code Execution285286### Basic Usage287288```python289import anthropic290291client = anthropic.Anthropic()292293response = client.messages.create(294model="claude-opus-4-7",295max_tokens=16000,296messages=[{297"role": "user",298"content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"299}],300tools=[{301"type": "code_execution_20260120",302"name": "code_execution"303}]304)305306for block in response.content:307if block.type == "text":308print(block.text)309elif block.type == "bash_code_execution_tool_result":310print(f"stdout: {block.content.stdout}")311```312313### Upload Files for Analysis314315```python316# 1. Upload a file317uploaded = client.beta.files.upload(file=open("sales_data.csv", "rb"))318319# 2. Pass to code execution via container_upload block320# Code execution is GA; Files API is still beta (pass via extra_headers)321response = client.messages.create(322model="claude-opus-4-7",323max_tokens=16000,324extra_headers={"anthropic-beta": "files-api-2025-04-14"},325messages=[{326"role": "user",327"content": [328{"type": "text", "text": "Analyze this sales data. Show trends and create a visualization."},329{"type": "container_upload", "file_id": uploaded.id}330]331}],332tools=[{"type": "code_execution_20260120", "name": "code_execution"}]333)334```335336### Retrieve Generated Files337338```python339import os340341OUTPUT_DIR = "./claude_outputs"342os.makedirs(OUTPUT_DIR, exist_ok=True)343344for block in response.content:345if block.type == "bash_code_execution_tool_result":346result = block.content347if result.type == "bash_code_execution_result" and result.content:348for file_ref in result.content:349if file_ref.type == "bash_code_execution_output":350metadata = client.beta.files.retrieve_metadata(file_ref.file_id)351file_content = client.beta.files.download(file_ref.file_id)352# Use basename to prevent path traversal; validate result353safe_name = os.path.basename(metadata.filename)354if not safe_name or safe_name in (".", ".."):355print(f"Skipping invalid filename: {metadata.filename}")356continue357output_path = os.path.join(OUTPUT_DIR, safe_name)358file_content.write_to_file(output_path)359print(f"Saved: {output_path}")360```361362### Container Reuse363364```python365# First request: set up environment366response1 = client.messages.create(367model="claude-opus-4-7",368max_tokens=16000,369messages=[{"role": "user", "content": "Install tabulate and create data.json with sample data"}],370tools=[{"type": "code_execution_20260120", "name": "code_execution"}]371)372373# Get container ID from response374container_id = response1.container.id375376# Second request: reuse the same container377response2 = client.messages.create(378container=container_id,379model="claude-opus-4-7",380max_tokens=16000,381messages=[{"role": "user", "content": "Read data.json and display as a formatted table"}],382tools=[{"type": "code_execution_20260120", "name": "code_execution"}]383)384```385386### Response Structure387388```python389for block in response.content:390if block.type == "text":391print(block.text) # Claude's explanation392elif block.type == "server_tool_use":393print(f"Running: {block.name} - {block.input}") # What Claude is doing394elif block.type == "bash_code_execution_tool_result":395result = block.content396if result.type == "bash_code_execution_result":397if result.return_code == 0:398print(f"Output: {result.stdout}")399else:400print(f"Error: {result.stderr}")401else:402print(f"Tool error: {result.error_code}")403elif block.type == "text_editor_code_execution_tool_result":404print(f"File operation: {block.content}")405```406407---408409## Memory Tool410411### Basic Usage412413```python414import anthropic415416client = anthropic.Anthropic()417418response = client.messages.create(419model="claude-opus-4-7",420max_tokens=16000,421messages=[{"role": "user", "content": "Remember that my preferred language is Python."}],422tools=[{"type": "memory_20250818", "name": "memory"}],423)424```425426### SDK Memory Helper427428Subclass `BetaAbstractMemoryTool`:429430```python431from anthropic.lib.tools import BetaAbstractMemoryTool432433class MyMemoryTool(BetaAbstractMemoryTool):434def view(self, command): ...435def create(self, command): ...436def str_replace(self, command): ...437def insert(self, command): ...438def delete(self, command): ...439def rename(self, command): ...440441memory = MyMemoryTool()442443# Use with tool runner444runner = client.beta.messages.tool_runner(445model="claude-opus-4-7",446max_tokens=16000,447tools=[memory],448messages=[{"role": "user", "content": "Remember my preferences"}],449)450451for message in runner:452print(message)453```454455For full implementation examples, use WebFetch:456457- `https://github.com/anthropics/anthropic-sdk-python/blob/main/examples/memory/basic.py`458459---460461## Structured Outputs462463### JSON Outputs (Pydantic — Recommended)464465```python466from pydantic import BaseModel467from typing import List468import anthropic469470class ContactInfo(BaseModel):471name: str472email: str473plan: str474interests: List[str]475demo_requested: bool476477client = anthropic.Anthropic()478479response = client.messages.parse(480model="claude-opus-4-7",481max_tokens=16000,482messages=[{483"role": "user",484"content": "Extract: Jane Doe ([email protected]) wants Enterprise, interested in API and SDKs, wants a demo."485}],486output_format=ContactInfo,487)488489# response.parsed_output is a validated ContactInfo instance490contact = response.parsed_output491print(contact.name) # "Jane Doe"492print(contact.interests) # ["API", "SDKs"]493```494495### Raw Schema496497```python498response = client.messages.create(499model="claude-opus-4-7",500max_tokens=16000,501messages=[{502"role": "user",503"content": "Extract info: John Smith ([email protected]) wants the Enterprise plan."504}],505output_config={506"format": {507"type": "json_schema",508"schema": {509"type": "object",510"properties": {511"name": {"type": "string"},512"email": {"type": "string"},513"plan": {"type": "string"},514"demo_requested": {"type": "boolean"}515},516"required": ["name", "email", "plan", "demo_requested"],517"additionalProperties": False518}519}520}521)522523import json524# output_config.format guarantees the first block is text with valid JSON525text = next(b.text for b in response.content if b.type == "text")526data = json.loads(text)527```528529### Strict Tool Use530531```python532response = client.messages.create(533model="claude-opus-4-7",534max_tokens=16000,535messages=[{"role": "user", "content": "Book a flight to Tokyo for 2 passengers on March 15"}],536tools=[{537"name": "book_flight",538"description": "Book a flight to a destination",539"strict": True,540"input_schema": {541"type": "object",542"properties": {543"destination": {"type": "string"},544"date": {"type": "string", "format": "date"},545"passengers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6, 7, 8]}546},547"required": ["destination", "date", "passengers"],548"additionalProperties": False549}550}]551)552```553554### Using Both Together555556```python557response = client.messages.create(558model="claude-opus-4-7",559max_tokens=16000,560messages=[{"role": "user", "content": "Plan a trip to Paris next month"}],561output_config={562"format": {563"type": "json_schema",564"schema": {565"type": "object",566"properties": {567"summary": {"type": "string"},568"next_steps": {"type": "array", "items": {"type": "string"}}569},570"required": ["summary", "next_steps"],571"additionalProperties": False572}573}574},575tools=[{576"name": "search_flights",577"description": "Search for available flights",578"strict": True,579"input_schema": {580"type": "object",581"properties": {582"destination": {"type": "string"},583"date": {"type": "string", "format": "date"}584},585"required": ["destination", "date"],586"additionalProperties": False587}588}]589)590```591