Loading...
    • Build
    • Admin
    • Models & pricing
    • Client SDKs
    • API Reference
    Search...
    ⌘K
    First steps
    Intro to ClaudeQuickstart
    Building with Claude
    Features overviewUsing the Messages APIHandling stop reasons
    Model capabilities
    Extended thinkingAdaptive thinkingEffortFast mode (beta: research preview)Structured outputsCitationsStreaming MessagesBatch processingSearch resultsStreaming refusalsMultilingual supportEmbeddings
    Tools
    OverviewHow tool use worksWeb search toolWeb fetch toolCode execution toolAdvisor toolMemory toolBash toolComputer use toolText editor tool
    Tool infrastructure
    Tool referenceTool searchProgrammatic tool callingFine-grained tool streaming
    Context management
    Context windowsCompactionContext editingPrompt cachingToken counting
    Working with files
    Files APIPDF supportImages and vision
    Skills
    OverviewQuickstartBest practicesSkills for enterpriseSkills in the API
    MCP
    Remote MCP serversMCP connector
    Prompt engineering
    OverviewPrompting best practicesConsole prompting tools
    Test and evaluate
    Define success and build evaluationsUsing the Evaluation Tool in ConsoleReducing latency
    Strengthen guardrails
    Reduce hallucinationsIncrease output consistencyMitigate jailbreaksReduce prompt leak
    Resources
    Glossary
    Release notes
    Claude Platform
    Console
    Log in
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...

    Solutions

    • AI agents
    • Code modernization
    • Coding
    • Customer support
    • Education
    • Financial services
    • Government
    • Life sciences

    Partners

    • Amazon Bedrock
    • Google Cloud's Vertex AI

    Learn

    • Blog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Company

    • Anthropic
    • Careers
    • Economic Futures
    • Research
    • News
    • Responsible Scaling Policy
    • Security and compliance
    • Transparency

    Learn

    • Blog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Help and security

    • Availability
    • Status
    • Support
    • Discord

    Terms and policies

    • Privacy policy
    • Responsible disclosure policy
    • Terms of service: Commercial
    • Terms of service: Consumer
    • Usage policy
    Documentation

    Parallel tool use

    Enable and format parallel tool calls, with message-history guidance and troubleshooting.

    Was this page helpful?

    • Worked example
    • Maximizing parallel tool use
    • Troubleshooting
    • Next steps

    This page covers parallel tool calls: when Claude calls multiple tools in one turn, how to format the message history so parallelism keeps working, and how to disable it. For the single-call flow, see Handle tool calls.

    By default, Claude may use multiple tools to answer a user query. You can disable this behavior by:

    • Setting disable_parallel_tool_use=true when tool_choice type is auto, which ensures that Claude uses at most one tool
    • Setting disable_parallel_tool_use=true when tool_choice type is any or tool, which ensures that Claude uses exactly one tool

    Worked example

    Simpler with Tool Runner: The example below shows manual parallel tool handling. For most use cases, Tool Runner automatically handles parallel tool execution with much less code.

    Here's a complete, runnable script to test and verify parallel tool calls are working correctly:

    # Define tools
    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"],
            },
        },
        {
            "name": "get_time",
            "description": "Get the current time in a given timezone",
            "input_schema": {
                "type": "object",
                "properties": {
                    "timezone": {
                        "type": "string",
                        "description": "The timezone, e.g. America/New_York",
                    }
                },
                "required": ["timezone"],
            },
        },
    ]
    
    # Test conversation with parallel tool calls
    messages = [
        {
            "role": "user",
            "content": "What's the weather in SF and NYC, and what time is it there?",
        }
    ]
    
    # Make initial request
    print("Requesting parallel tool calls...")
    response = client.messages.create(
        model="claude-opus-4-6", max_tokens=1024, messages=messages, tools=tools
    )
    
    # Check for parallel tool calls
    tool_uses = [block for block in response.content if block.type == "tool_use"]
    print(f"\n✓ Claude made {len(tool_uses)} tool calls")
    
    if len(tool_uses) > 1:
        print("✓ Parallel tool calls detected!")
        for tool in tool_uses:
            print(f"  - {tool.name}: {tool.input}")
    else:
        print("✗ No parallel tool calls detected")
    
    # Simulate tool execution and format results correctly
    tool_results = []
    for tool_use in tool_uses:
        if tool_use.name == "get_weather":
            if "San Francisco" in str(tool_use.input):
                result = "San Francisco: 68°F, partly cloudy"
            else:
                result = "New York: 45°F, clear skies"
        else:  # get_time
            if "Los_Angeles" in str(tool_use.input):
                result = "2:30 PM PST"
            else:
                result = "5:30 PM EST"
    
        tool_results.append(
            {"type": "tool_result", "tool_use_id": tool_use.id, "content": result}
        )
    
    # Continue conversation with tool results
    messages.extend(
        [
            {"role": "assistant", "content": response.content},
            {"role": "user", "content": tool_results},  # All results in one message!
        ]
    )
    
    # Get final response
    print("\nGetting final response...")
    final_response = client.messages.create(
        model="claude-opus-4-6", max_tokens=1024, messages=messages, tools=tools
    )
    
    print(f"\nClaude's response:\n{final_response.content[0].text}")
    
    # Verify formatting
    print("\n--- Verification ---")
    print(f"✓ Tool results sent in single user message: {len(tool_results)} results")
    print("✓ No text before tool results in content array")
    print("✓ Conversation formatted correctly for future parallel tool use")

    This script demonstrates:

    • How to properly format parallel tool calls and results
    • How to verify that parallel calls are being made
    • The correct message structure that encourages future parallel tool use
    • Common mistakes to avoid (like text before tool results)

    Run this script to test your implementation and ensure Claude is making parallel tool calls effectively.

    Maximizing parallel tool use

    While Claude 4 models have excellent parallel tool use capabilities by default, you can increase the likelihood of parallel tool execution across all models with targeted prompting:

    Troubleshooting

    If Claude isn't making parallel tool calls when expected, check these common issues:

    1. Incorrect tool result formatting

    The most common issue is formatting tool results incorrectly in the conversation history. This "teaches" Claude to avoid parallel calls.

    Specifically for parallel tool use:

    • ❌ Wrong: Sending separate user messages for each tool result
    • ✅ Correct: All tool results must be in a single user message
    // ❌ This reduces parallel tool use
    [
      {"role": "assistant", "content": [tool_use_1, tool_use_2]},
      {"role": "user", "content": [tool_result_1]},
      {"role": "user", "content": [tool_result_2]}  // Separate message
    ]
    
    // ✅ This maintains parallel tool use
    [
      {"role": "assistant", "content": [tool_use_1, tool_use_2]},
      {"role": "user", "content": [tool_result_1, tool_result_2]}  // Single message
    ]

    See Handle tool calls for other formatting rules.

    2. Weak prompting

    Default prompting may not be sufficient. Use the stronger system prompt from the Maximizing parallel tool use section above.

    3. Measuring parallel tool usage

    To verify parallel tool calls are working:

    # Calculate average tools per tool-calling message
    tool_call_messages = [
        msg for msg in messages if any(block.type == "tool_use" for block in msg.content)
    ]
    total_tool_calls = sum(
        len([b for b in msg.content if b.type == "tool_use"]) for msg in tool_call_messages
    )
    avg_tools_per_message = (
        total_tool_calls / len(tool_call_messages) if tool_call_messages else 0.0
    )
    print(f"Average tools per message: {avg_tools_per_message}")
    # Should be > 1.0 if parallel calls are working

    Next steps

    • For the single-tool-call flow and tool_result formatting rules, see Handle tool calls.
    • For the SDK abstraction that handles parallel execution automatically, see Tool Runner.
    • For the full tool-use workflow, see Define tools.