Tool use with Claude
Claude is capable of interacting with tools and functions, allowing you to extend Claude's capabilities to perform a wider variety of tasks.
Structured Outputs provides guaranteed schema validation for tool inputs. Add strict: true to your tool definitions to ensure Claude's tool calls always match your schema exactly—no more type mismatches or missing fields.
Perfect for production agents where invalid tool parameters would cause failures. Learn when to use strict tool use →
Here's an example of how to provide tools to Claude using the Messages API:
curl https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
}
},
"required": ["location"]
}
}
],
"messages": [
{
"role": "user",
"content": "What is the weather like in San Francisco?"
}
]
}'
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
}
],
messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
)
print(response)
import { Anthropic } from '@anthropic-ai/sdk';
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY
});
async function main() {
const response = await anthropic.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 1024,
tools: [{
name: "get_weather",
description: "Get the current weather in a given location",
input_schema: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA"
}
},
required: ["location"]
}
}],
messages: [{
role: "user",
content: "Tell me the weather in San Francisco."
}]
});
console.log(response);
}
main().catch(console.error);
import java.util.List;
import java.util.Map;
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
import com.anthropic.models.messages.Tool;
import com.anthropic.models.messages.Tool.InputSchema;
public class GetWeatherExample {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
InputSchema schema = InputSchema.builder()
.properties(JsonValue.from(Map.of(
"location",
Map.of(
"type", "string",
"description", "The city and state, e.g. San Francisco, CA"))))
.putAdditionalProperty("required", JsonValue.from(List.of("location")))
.build();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_0)
.maxTokens(1024)
.addTool(Tool.builder()
.name("get_weather")
.description("Get the current weather in a given location")
.inputSchema(schema)
.build())
.addUserMessage("What's the weather like in San Francisco?")
.build();
Message message = client.messages().create(params);
System.out.println(message);
}
}
How tool use works
Claude supports two types of tools:
Client tools: Tools that execute on your systems, which include:
- User-defined custom tools that you create and implement
- Anthropic-defined tools like computer use and text editor that require client implementation
Server tools: Tools that execute on Anthropic's servers, like the web search and web fetch tools. These tools must be specified in the API request but don't require implementation on your part.
Client tools
Integrate client tools with Claude in these steps:
Server tools
Server tools follow a different workflow:
Using MCP tools with Claude
If you're building an application that uses the Model Context Protocol (MCP), you can use tools from MCP servers directly with Claude's Messages API. MCP tool definitions use a schema format that's similar to Claude's tool format. You just need to rename inputSchema to input_schema.
Converting MCP tools to Claude format
When you build an MCP client and call list_tools() on an MCP server, you'll receive tool definitions with an inputSchema field. To use these tools with Claude, convert them to Claude's format:
async def get_claude_tools(mcp_session: ClientSession): """Convert MCP tools to Claude's tool format.""" mcp_tools = await mcp_session.list_tools()
claude_tools = []
for tool in mcp_tools.tools:
claude_tools.append({
"name": tool.name,
"description": tool.description or "",
"input_schema": tool.inputSchema # Rename inputSchema to input_schema
})
return claude_tools
```typescript TypeScript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
async function getClaudeTools(mcpClient: Client) {
// Convert MCP tools to Claude's tool format
const mcpTools = await mcpClient.listTools();
return mcpTools.tools.map((tool) => ({
name: tool.name,
description: tool.description ?? "",
input_schema: tool.inputSchema, // Rename inputSchema to input_schema
}));
}
Then pass these converted tools to Claude:
client = anthropic.Anthropic() claude_tools = await get_claude_tools(mcp_session)
response = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, tools=claude_tools, messages=[{"role": "user", "content": "What tools do you have available?"}] )
```typescript TypeScript
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic();
const claudeTools = await getClaudeTools(mcpClient);
const response = await anthropic.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 1024,
tools: claudeTools,
messages: [{ role: "user", content: "What tools do you have available?" }],
});
When Claude responds with a tool_use block, execute the tool on your MCP server using call_tool() and return the result to Claude in a tool_result block.
For a complete guide to building MCP clients, see Build an MCP client.
Tool use examples
Here are a few code examples demonstrating various tool use patterns and techniques. For brevity's sake, the tools are simple tools, and the tool descriptions are shorter than would be ideal to ensure best performance.
```python Python
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The unit of temperature, either \"celsius\" or \"fahrenheit\""
}
},
"required": ["location"]
}
}
],
messages=[{"role": "user", "content": "What is the weather like in San Francisco?"}]
)
print(response)
```
```java Java
import java.util.List;
import java.util.Map;
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
import com.anthropic.models.messages.Tool;
import com.anthropic.models.messages.Tool.InputSchema;
public class WeatherToolExample {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
InputSchema schema = InputSchema.builder()
.properties(JsonValue.from(Map.of(
"location", Map.of(
"type", "string",
"description", "The city and state, e.g. San Francisco, CA"
),
"unit", Map.of(
"type", "string",
"enum", List.of("celsius", "fahrenheit"),
"description", "The unit of temperature, either \"celsius\" or \"fahrenheit\""
)
)))
.putAdditionalProperty("required", JsonValue.from(List.of("location")))
.build();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_0)
.maxTokens(1024)
.addTool(Tool.builder()
.name("get_weather")
.description("Get the current weather in a given location")
.inputSchema(schema)
.build())
.addUserMessage("What is the weather like in San Francisco?")
.build();
Message message = client.messages().create(params);
System.out.println(message);
}
}
```
Claude will return a response similar to:
{
"id": "msg_01Aq9w938a90dw8q",
"model": "claude-sonnet-4-5",
"stop_reason": "tool_use",
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll check the current weather in San Francisco for you."
},
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": {"location": "San Francisco, CA", "unit": "celsius"}
}
]
}
You would then need to execute the get_weather function with the provided input, and return the result in a new user message:
```python Python
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The unit of temperature, either 'celsius' or 'fahrenheit'"
}
},
"required": ["location"]
}
}
],
messages=[
{
"role": "user",
"content": "What's the weather like in San Francisco?"
},
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll check the current weather in San Francisco for you."
},
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": {"location": "San Francisco, CA", "unit": "celsius"}
}
]
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9", # from the API response
"content": "65 degrees" # from running your tool
}
]
}
]
)
print(response)
```
import java.util.List;
import java.util.Map;
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.*;
import com.anthropic.models.messages.Tool.InputSchema;
public class ToolConversationExample {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
InputSchema schema = InputSchema.builder()
.properties(JsonValue.from(Map.of(
"location", Map.of(
"type", "string",
"description", "The city and state, e.g. San Francisco, CA"
),
"unit", Map.of(
"type", "string",
"enum", List.of("celsius", "fahrenheit"),
"description", "The unit of temperature, either \"celsius\" or \"fahrenheit\""
)
)))
.putAdditionalProperty("required", JsonValue.from(List.of("location")))
.build();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_0)
.maxTokens(1024)
.addTool(Tool.builder()
.name("get_weather")
.description("Get the current weather in a given location")
.inputSchema(schema)
.build())
.addUserMessage("What is the weather like in San Francisco?")
.addAssistantMessageOfBlockParams(
List.of(
ContentBlockParam.ofText(
TextBlockParam.builder()
.text("I'll check the current weather in San Francisco for you.")
.build()
),
ContentBlockParam.ofToolUse(
ToolUseBlockParam.builder()
.id("toolu_01A09q90qw90lq917835lq9")
.name("get_weather")
.input(JsonValue.from(Map.of(
"location", "San Francisco, CA",
"unit", "celsius"
)))
.build()
)
)
)
.addUserMessageOfBlockParams(List.of(
ContentBlockParam.ofToolResult(
ToolResultBlockParam.builder()
.toolUseId("toolu_01A09q90qw90lq917835lq9")
.content("15 degrees")
.build()
)
))
.build();
Message message = client.messages().create(params);
System.out.println(message);
}
}
{
"id": "msg_01Aq9w938a90dw8q",
"model": "claude-sonnet-4-5",
"stop_reason": "stop_sequence",
"role": "assistant",
"content": [
{
"type": "text",
"text": "The current weather in San Francisco is 15 degrees Celsius (59 degrees Fahrenheit). It's a cool day in the city by the bay!"
}
]
}
Claude can call multiple tools in parallel within a single response, which is useful for tasks that require multiple independent operations. When using parallel tools, all tool_use blocks are included in a single assistant message, and all corresponding tool_result blocks must be provided in the subsequent user message.
For comprehensive examples, test scripts, and best practices for implementing parallel tool calls, see the parallel tool use section in our implementation guide.
You can provide Claude with multiple tools to choose from in a single request. Here's an example with both a get_weather and a get_time tool, along with a user query that asks for both.
```python Python
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The unit of temperature, either 'celsius' or 'fahrenheit'"
}
},
"required": ["location"]
}
},
{
"name": "get_time",
"description": "Get the current time in a given time zone",
"input_schema": {
"type": "object",
"properties": {
"timezone": {
"type": "string",
"description": "The IANA time zone name, e.g. America/Los_Angeles"
}
},
"required": ["timezone"]
}
}
],
messages=[
{
"role": "user",
"content": "What is the weather like right now in New York? Also what time is it there?"
}
]
)
print(response)
```
```java Java
import java.util.List;
import java.util.Map;
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
import com.anthropic.models.messages.Tool;
import com.anthropic.models.messages.Tool.InputSchema;
public class MultipleToolsExample {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
// Weather tool schema
InputSchema weatherSchema = InputSchema.builder()
.properties(JsonValue.from(Map.of(
"location", Map.of(
"type", "string",
"description", "The city and state, e.g. San Francisco, CA"
),
"unit", Map.of(
"type", "string",
"enum", List.of("celsius", "fahrenheit"),
"description", "The unit of temperature, either \"celsius\" or \"fahrenheit\""
)
)))
.putAdditionalProperty("required", JsonValue.from(List.of("location")))
.build();
// Time tool schema
InputSchema timeSchema = InputSchema.builder()
.properties(JsonValue.from(Map.of(
"timezone", Map.of(
"type", "string",
"description", "The IANA time zone name, e.g. America/Los_Angeles"
)
)))
.putAdditionalProperty("required", JsonValue.from(List.of("timezone")))
.build();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_0)
.maxTokens(1024)
.addTool(Tool.builder()
.name("get_weather")
.description("Get the current weather in a given location")
.inputSchema(weatherSchema)
.build())
.addTool(Tool.builder()
.name("get_time")
.description("Get the current time in a given time zone")
.inputSchema(timeSchema)
.build())
.addUserMessage("What is the weather like right now in New York? Also what time is it there?")
.build();
Message message = client.messages().create(params);
System.out.println(message);
}
}
```
In this case, Claude may either:
- Use the tools sequentially (one at a time) — calling
get_weatherfirst, thenget_timeafter receiving the weather result - Use parallel tool calls — outputting multiple
tool_useblocks in a single response when the operations are independent
When Claude makes parallel tool calls, you must return all tool results in a single user message, with each result in its own tool_result block.
If the user's prompt doesn't include enough information to fill all the required parameters for a tool, Claude Opus is much more likely to recognize that a parameter is missing and ask for it. Claude Sonnet may ask, especially when prompted to think before outputting a tool request. But it may also do its best to infer a reasonable value.
For example, using the get_weather tool above, if you ask Claude "What's the weather?" without specifying a location, Claude, particularly Claude Sonnet, may make a guess about tools inputs:
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": {"location": "New York, NY", "unit": "fahrenheit"}
}
This behavior is not guaranteed, especially for more ambiguous prompts and for less intelligent models. If Claude Opus doesn't have enough context to fill in the required parameters, it is far more likely respond with a clarifying question instead of making a tool call.
Some tasks may require calling multiple tools in sequence, using the output of one tool as the input to another. In such a case, Claude will call one tool at a time. If prompted to call the tools all at once, Claude is likely to guess parameters for tools further downstream if they are dependent on tool results for tools further upstream.
Here's an example of using a get_location tool to get the user's location, then passing that location to the get_weather tool:
```python Python
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[
{
"name": "get_location",
"description": "Get the current user location based on their IP address. This tool has no parameters or arguments.",
"input_schema": {
"type": "object",
"properties": {}
}
},
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The unit of temperature, either 'celsius' or 'fahrenheit'"
}
},
"required": ["location"]
}
}
],
messages=[{
"role": "user",
"content": "What's the weather like where I am?"
}]
)
```
```java Java
import java.util.List;
import java.util.Map;
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
import com.anthropic.models.messages.Tool;
import com.anthropic.models.messages.Tool.InputSchema;
public class EmptySchemaToolExample {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
// Empty schema for location tool
InputSchema locationSchema = InputSchema.builder()
.properties(JsonValue.from(Map.of()))
.build();
// Weather tool schema
InputSchema weatherSchema = InputSchema.builder()
.properties(JsonValue.from(Map.of(
"location", Map.of(
"type", "string",
"description", "The city and state, e.g. San Francisco, CA"
),
"unit", Map.of(
"type", "string",
"enum", List.of("celsius", "fahrenheit"),
"description", "The unit of temperature, either \"celsius\" or \"fahrenheit\""
)
)))
.putAdditionalProperty("required", JsonValue.from(List.of("location")))
.build();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_0)
.maxTokens(1024)
.addTool(Tool.builder()
.name("get_location")
.description("Get the current user location based on their IP address. This tool has no parameters or arguments.")
.inputSchema(locationSchema)
.build())
.addTool(Tool.builder()
.name("get_weather")
.description("Get the current weather in a given location")
.inputSchema(weat
…(truncated)