Skip to main content
Glama
SDGLBL
by SDGLBL

batch

Execute multiple independent tool operations in a single request to reduce context usage and latency. Runs tools in parallel when possible, respecting each tool's permissions and validation rules.

Instructions

Batch execution tool that runs multiple tool invocations in a single request.

Tools are executed in parallel when possible, and otherwise serially. Takes a list of tool invocations (tool_name and input pairs). Returns the collected results from all invocations. Use this tool when you need to run multiple independent tool operations at once -- it is awesome for speeding up your workflow, reducing both context usage and latency. Each tool will respect its own permissions and validation rules. The tool's outputs are NOT shown to the user; to answer the user's query, you MUST send a message with the results after the tool call completes, otherwise the user will not see the results.

<batch_example> When dispatching multiple agents to find necessary information. batch( description="Update import statements across modules", invocations=[ {tool_name: "dispatch_agent", input: {prompt: "Search for all instances of 'logger' configuration in /app/config directory"}}, {tool_name: "dispatch_agent", input: {prompt: "Find all test files that reference 'UserService' in /app/tests"}}, ] )

Common scenarios for effective batching:

  1. Reading multiple related files in one operation

  2. Performing a series of simple mechanical changes

  3. Running multiple diagnostic commands

  4. Dispatch multiple agents to complete the task

To make a batch call, provide the following:

  1. description: A short (3-5 word) description of the batch operation

  2. invocations: List of invocation [{"tool_name": "...", "input": "..."}], tool_name: The name of the tool to invoke,newText: The input to pass to the tool

Available tools in batch call: Tool: dispatch_agent,read,directory_tree,grep,grep_ast,run_command,notebook_read Not available: think,write,edit,multi_edit,notebook_edit

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
descriptionYesA short (3-5 word) description of the batch operation
invocationsYesThe list of tool invocations to execute (required -- you MUST provide at least one tool invocation)

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • BatchTool class containing the name 'batch', description, __init__ with tools dict, main call handler for parallel tool execution, _format_results helper, and register method.
    class BatchTool(BaseTool):
        """Tool for executing multiple tools in a single request.
    
        Executes a list of tool invocations in parallel when possible, or
        otherwise serially. Returns the collected results from all invocations.
        """
    
        @property
        @override
        def name(self) -> str:
            """Get the tool name.
    
            Returns:
                Tool name
            """
            return "batch"
    
        @property
        @override
        def description(self) -> str:
            """Get the tool description.
    
            Returns:
                Tool description
            """
            return """Batch execution tool that runs multiple tool invocations in a single request.
    
    Tools are executed in parallel when possible, and otherwise serially.
    Takes a list of tool invocations (tool_name and input pairs).
    Returns the collected results from all invocations.
    Use this tool when you need to run multiple independent tool operations at once -- it is awesome for speeding up your workflow, reducing both context usage and latency.
    Each tool will respect its own permissions and validation rules.
    The tool's outputs are NOT shown to the user; to answer the user's query, you MUST send a message with the results after the tool call completes, otherwise the user will not see the results.
    
    <batch_example>
    When dispatching multiple agents to find necessary information.
    batch(
      description="Update import statements across modules",
      invocations=[
        {tool_name: "dispatch_agent", input: {prompt: "Search for all instances of 'logger' configuration in /app/config directory"}},
        {tool_name: "dispatch_agent", input: {prompt: "Find all test files that reference 'UserService' in /app/tests"}},
      ]
    )
    
    Common scenarios for effective batching:
    1. Reading multiple related files in one operation
    2. Performing a series of simple mechanical changes
    3. Running multiple diagnostic commands
    4. Dispatch multiple agents to complete the task
    
    To make a batch call, provide the following:
    1. description: A short (3-5 word) description of the batch operation
    2. invocations: List of invocation [{"tool_name": "...", "input": "..."}], tool_name: The name of the tool to invoke,newText: The input to pass to the tool
    
    
    Available tools in batch call:
    Tool: dispatch_agent,read,directory_tree,grep,grep_ast,run_command,notebook_read
    Not available: think,write,edit,multi_edit,notebook_edit
    """
    
        def __init__(self, tools: dict[str, BaseTool]) -> None:
            """Initialize the batch tool.
    
            Args:
                tools: Dictionary mapping tool names to tool instances
            """
            self.tools = tools
    
        @override
        async def call(
            self,
            ctx: MCPContext,
            **params: Unpack[BatchToolParams],
        ) -> str:
            """Execute the tool with the given parameters.
    
            Args:
                ctx: MCP context
                **params: Tool parameters
    
            Returns:
                Tool result
            """
            tool_ctx = create_tool_context(ctx)
            tool_ctx.set_tool_info(self.name)
    
            # Extract parameters
            description = params.get("description")
            invocations: list[dict[str, Any]] = params.get("invocations", list())
    
            # Validate required parameters
            if not description:
                await tool_ctx.error(
                    "Parameter 'description' is required but was None or empty"
                )
                return "Error: Parameter 'description' is required but was None or empty"
    
            if not invocations:
                await tool_ctx.error(
                    "Parameter 'invocations' is required but was None or empty"
                )
                return "Error: Parameter 'invocations' is required but was None or empty"
    
            if not isinstance(invocations, list) or len(invocations) == 0:
                await tool_ctx.error("Parameter 'invocations' must be a non-empty list")
                return "Error: Parameter 'invocations' must be a non-empty list"
    
            await tool_ctx.info(
                f"Executing batch operation: {description} ({len(invocations)} invocations)"
            )
    
            # Execute all tool invocations in parallel
            tasks: list[asyncio.Future[dict[str, Any]]] = []
            invocation_map: dict[
                asyncio.Future[dict[str, Any]], dict[str, Any]
            ] = {}  # Map task Future to invocation
    
            for i, invocation in enumerate(invocations):
                # Extract tool name and input from invocation
                tool_name: str = invocation.get("tool_name", "")
                tool_input: dict[str, Any] = invocation.get("input", {})
    
                # Validate tool invocation
                if not tool_name:
                    error_message = f"Tool name is required in invocation {i}"
                    await tool_ctx.error(error_message)
                    # Add direct result for this invocation
                    tasks.append(asyncio.Future())
                    tasks[-1].set_result(
                        {"invocation": invocation, "result": f"Error: {error_message}"}
                    )
                    invocation_map[tasks[-1]] = invocation
                    continue
    
                # Check if the tool exists
                if tool_name not in self.tools:
                    error_message = f"Tool '{tool_name}' not found"
                    await tool_ctx.error(error_message)
                    # Add direct result for this invocation
                    tasks.append(asyncio.Future())
                    tasks[-1].set_result(
                        {"invocation": invocation, "result": f"Error: {error_message}"}
                    )
                    invocation_map[tasks[-1]] = invocation
                    continue
    
                # Create a task for this tool invocation
                try:
                    tool = self.tools[tool_name]
                    await tool_ctx.info(f"Creating task for tool: {tool_name}")
    
                    # Create coroutine for this tool execution
                    async def execute_tool(
                        tool_obj: BaseTool, tool_name: str, tool_input: dict[str, Any]
                    ):
                        try:
                            await tool_ctx.info(f"Executing tool: {tool_name}")
                            result = await tool_obj.call(ctx, **tool_input)
                            await tool_ctx.info(f"Tool '{tool_name}' execution completed")
                            return {
                                "invocation": {"tool_name": tool_name, "input": tool_input},
                                "result": result,
                            }
                        except Exception as e:
                            error_message = f"Error executing tool '{tool_name}': {str(e)}"
                            await tool_ctx.error(error_message)
                            return {
                                "invocation": {"tool_name": tool_name, "input": tool_input},
                                "result": f"Error: {error_message}",
                            }
    
                    # Schedule the task
                    task = asyncio.create_task(execute_tool(tool, tool_name, tool_input))
                    tasks.append(task)
                    invocation_map[task] = invocation
                except Exception as e:
                    error_message = f"Error scheduling tool '{tool_name}': {str(e)}"
                    await tool_ctx.error(error_message)
                    # Add direct result for this invocation
                    tasks.append(asyncio.Future())
                    tasks[-1].set_result(
                        {"invocation": invocation, "result": f"Error: {error_message}"}
                    )
                    invocation_map[tasks[-1]] = invocation
    
            # Wait for all tasks to complete
            await tool_ctx.info(f"Waiting for {len(tasks)} tool executions to complete")
            results: list[dict[str, Any]] = []
    
            # As tasks complete, collect their results
            for task in asyncio.as_completed(tasks):
                try:
                    result = await task
                    results.append(result)
                except Exception as e:
                    invocation = invocation_map[task]
                    tool_name: str = invocation.get("tool_name", "unknown")
                    error_message = f"Unexpected error in tool '{tool_name}': {str(e)}"
                    await tool_ctx.error(error_message)
                    results.append(
                        {"invocation": invocation, "result": f"Error: {error_message}"}
                    )
    
            # Format the results
            formatted_results = self._format_results(results)
            await tool_ctx.info(
                f"Batch operation '{description}' completed with {len(results)} results"
            )
    
            return formatted_results
  • Pydantic-style schema definitions using TypedDict and Annotated Field for batch tool parameters: InvocationItem, Description, Invocations, BatchToolParams.
    class InvocationItem(TypedDict):
        """A single tool invocation item.
    
        Attributes:
            tool_name: The name of the tool to invoke
            input: The input to pass to the tool
        """
    
        tool_name: Annotated[
            str,
            Field(
                description="The name of the tool to invoke",
                min_length=1,
            ),
        ]
        input: Annotated[
            dict[str, Any],
            Field(
                description="The input to pass to the tool",
            ),
        ]
    
    
    Description = Annotated[
        str,
        Field(
            description="A short (3-5 word) description of the batch operation",
            min_length=1,
        ),
    ]
    
    Invocations = Annotated[
        list[InvocationItem],
        Field(
            description="The list of tool invocations to execute (required -- you MUST provide at least one tool invocation)",
            min_length=1,
        ),
    ]
    
    
    class BatchToolParams(TypedDict):
        """Parameters for the BatchTool.
    
        Attributes:
            description: A short (3-5 word) description of the batch operation
            invocations: The list of tool invocations to execute (required -- you MUST provide at least one tool invocation)
        """
    
        description: Description
        invocations: Invocations
    
    
    @final
  • Creates BatchTool instance passing all available tools, then registers it using ToolRegistry.register_tool.
    def register_batch_tool(mcp_server: FastMCP, tools: dict[str, BaseTool]) -> None:
        """Register batch tool with the MCP server.
    
        Args:
            mcp_server: The FastMCP server instance
            tools: Dictionary mapping tool names to tool instances
        """
        batch_tool = BatchTool(tools)
        ToolRegistry.register_tool(mcp_server, batch_tool)
  • Invocation of register_batch_tool after collecting all other tools into all_tools dict, as part of register_all_tools.
    # Register batch tool
    register_batch_tool(mcp_server, all_tools)
  • Helper method to format batch results into structured markdown output with numbered results and code blocks for multi-line outputs.
    def _format_results(self, results: list[dict[str, dict[str, Any]]]) -> str:
        """Format the results from multiple tool invocations.
    
        Args:
            results: List of tool invocation results
    
        Returns:
            Formatted results string
        """
        formatted_parts: list[str] = []
        for i, result in enumerate(results):
            invocation: dict[str, Any] = result["invocation"]
            tool_name: str = invocation.get("tool_name", "unknown")
    
            # Add the result header
            formatted_parts.append(f"### Result {i + 1}: {tool_name}")
            # Add the result content - use multi-line code blocks for code outputs
            if "\n" in result["result"]:
                formatted_parts.append(f"```\n{result['result']}\n```")
            else:
                formatted_parts.append(result["result"])
            # Add a separator
            formatted_parts.append("")
    
        return "\n".join(formatted_parts)
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden and does an excellent job disclosing behavioral traits. It explains execution order (parallel when possible, otherwise serial), permission handling (each tool respects its own permissions), output behavior (outputs NOT shown to user, requiring separate message), and provides practical constraints like latency reduction benefits. The only minor gap is lack of explicit error handling details.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with core information but becomes verbose with extensive examples, scenario lists, and tool availability sections. While all content is relevant, it could be more tightly structured. The example section is particularly lengthy and includes formatting that might not be necessary in a pure description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (batch execution with multiple invocations), no annotations, but with a comprehensive input schema and output schema present, the description provides excellent contextual completeness. It covers purpose, usage guidelines, behavioral characteristics, examples, available tools, and important constraints about user visibility of results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds minimal value beyond the schema: it repeats the 'description' parameter guidance and provides an example format for 'invocations', but doesn't significantly enhance understanding of parameter semantics beyond what's already documented in the comprehensive schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Batch execution tool that runs multiple tool invocations in a single request.' It specifies the verb ('runs'), resource ('multiple tool invocations'), and distinguishes it from siblings by explaining it's for parallel/serial execution of other tools rather than direct operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use this tool: 'Use this tool when you need to run multiple independent tool operations at once.' It also includes specific examples of common scenarios and explicitly lists which sibling tools are available vs. not available for batch calls, providing clear alternatives and exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/SDGLBL/mcp-claude-code'

If you have feedback or need assistance with the MCP directory API, please join our Discord server