From Tool Calls to Real Execution: Inside Claude Code’s 43‑Tool Scheduling System

The article dissects Claude Code’s tool runtime, detailing how a unified TypeScript interface, a feature‑gated registry, a seven‑stage dispatch pipeline, and a concurrency scheduler transform model‑generated tool_use blocks into safe, parallel or serial system operations, including dynamic MCP extensions.

Code Mala Tang
Code Mala Tang
Code Mala Tang
From Tool Calls to Real Execution: Inside Claude Code’s 43‑Tool Scheduling System

Claude Code bridges the gap between stateless large language models and real system actions by introducing a comprehensive tool runtime system that converts model‑generated tool_use blocks into executable operations.

Architecture Overview

The system consists of four layers: the Tool Interface , the Registry , the Dispatch Pipeline , and the Concurrency Scheduler . Each layer has a clear responsibility, and a tool passes through all four before reaching the operating system.

Tool Interface

All tools implement the same generic interface defined in Tool.ts. The interface accepts three type parameters – Input (a Zod schema), Output, and P (progress data). A typical definition looks like:

interface Tool<Input, Output, P> {
  name: string;
  description: string;
  inputSchema: z.ZodSchema<Input>;
  call(input: Input, context: ExecutionContext): Promise<ToolResult<Output>>;
  isConcurrencySafe(input: Input): boolean;
  isReadOnly(input: Input): boolean;
  checkPermissions(input: Input, context: PermissionContext): Promise<PermissionResult>;
  mapToolResultToToolResultBlockParam(result: ToolResult<Output>): ToolResultBlockParam;
}

Tools are created via the buildTool() factory, which supplies conservative default values (fail‑closed). If a tool omits concurrency safety, it is executed serially; missing permission checks fall back to the default permission flow.

Tool Registry

All tools are registered in tools.ts through getAllBaseTools(), which returns a flat array. Sixteen tools are always available (file read/write/patch, bash, web_fetch, delegate_task, memory, etc.), while roughly twenty‑seven are conditionally enabled via feature flags, environment variables, or platform checks.

MCP (Model Context Protocol) Tools

External processes can expose tools via the MCP server. MCP tools are dynamically registered at runtime and wrapped to conform to the same Tool interface, allowing them to participate in the same dispatch pipeline and permission system.

Tool Pool Assembly

The final tool set is built in three steps: getAllBaseTools() – returns the built‑in list, applying feature gates. getTools(permissionContext) – filters the list with deny rules and isEnabled(). assembleToolPool(permissionContext, mcpTools) – merges built‑in and MCP tools, sorting alphabetically so that built‑in tools win name collisions.

const merged = [...builtInTools, ...mcpTools].sort((a, b) => a.name.localeCompare(b.name));

This stable ordering improves prompt‑cache hit rates because the tool array is part of the API request.

API Serialization

Before sending tools to the Claude API, toolToAPISchema() converts each tool’s Zod schema into the JSON Schema format required by Anthropic.

Dispatch Pipeline – Seven Stages

When Claude returns a response containing tool_use blocks, the pipeline processes each block sequentially through the following stages:

Stage 1 – Extraction

const toolUseBlocks = message.content.filter(block => block.type === 'tool_use');

Each block includes name, input, and a unique id that must be echoed back.

Stage 2 – Input Validation

The Zod schema validates the raw input via safeParse(). If validation fails, the model receives a formatted error and execution stops. Some tools also run a second validateInput() for semantic checks (e.g., absolute file paths).

Stage 3 – Pre‑Hook

User‑configured hooks run before permission checks. They can allow, deny, modify input, block execution, or provide extra context, but they never bypass deny rules defined in settings.json.

Stage 4 – Permission Check

The most complex stage evaluates multiple layers in order:

Deny rules – immediate stop.

Ask rules – prompt the user unless a Bash sandbox auto‑allows.

Tool‑specific checkPermissions() (e.g., BashTool parses sub‑commands).

Hard‑coded safety checks for sensitive paths (e.g., .git/).

Permission mode from user settings.

Allow rules – final pass if no deny/ask triggered.

Sources of rules include policySettings, localSettings, projectSettings, userSettings, flagSettings, CLI arguments, command‑line flags, and session data, allowing organization‑wide policies to override personal preferences.

Stage 5 – Execution

const result = await tool.call(
  validatedInput,
  executionContext,
  permissionCallback,
  parentAssistantMessage,
  progressCallback
);

The call receives five parameters: validated input, execution context (working directory, abort controller, app state), a permission callback for runtime permission requests, the parent assistant message, and a progress callback. The original model input is preserved for logging, while hooks may see a modified version.

Stage 6 – Post‑Hook

After execution, post‑hooks can modify the tool’s output, add context, or abort the conversation. A special PostToolUseFailure hook runs only on errors, giving external systems a chance to log or suggest remediation.

Stage 7 – Result Mapping

Each tool implements mapToolResultToToolResultBlockParam() to produce a ToolResultBlockParam that references the original tool_use_id. Large results are persisted to sessionDir/tool-results/{toolUseId}.txt and a preview with a file reference is sent to the API, preventing context overflow.

Concurrency Scheduler

When a single model message generates multiple tool calls, the scheduler batches them based on the isConcurrencySafe(input) flag. Safe batches run in parallel (up to ten concurrent tools, configurable via CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY); unsafe batches run serially. Context modifiers are applied only between batches.

For example, five independent read calls form one concurrent batch, while a subsequent write call starts a new serial batch.

Streaming Executor

The StreamingToolExecutor can start executing a tool as soon as its tool_use block is streamed, without waiting for the full model response. It follows the same concurrency rules but adds a Bash error‑cascading rule: if a Bash command fails, all sibling tools in the same batch are aborted, because subsequent operations may depend on a now‑invalid environment.

Practical Example

A model decides to read /src/index.ts and emits:

{
  "type": "tool_use",
  "id": "toolu_01XYZ",
  "name": "read",
  "input": { "file_path": "/src/index.ts" }
}

The pipeline then extracts the block, finds FileReadTool, validates the input against its Zod schema, runs any pre‑hooks (none in this case), passes permission checks (generally allowed for reads), executes the tool (which may run cat -n), maps the result back to a tool_result referencing toolu_01XYZ, and finally appends the result to the conversation.

Key Takeaways

Model as Scheduler: The runtime trusts the model’s plan (parallelize independent reads, serialize writes) and merely enforces it.

Fail‑Closed Design: Unknown tools, invalid inputs, missing concurrency flags, or absent permissions all result in safe failure rather than permissive execution.

Hook Extensibility: Pre‑, post‑, and failure hooks provide controlled extension points that can tighten security but never relax it.

Uniform Interface: All 43+ tools share a 30‑method contract, simplifying routing and permission handling.

Overall, Claude Code’s tool system transforms structured tool_use intents into verified, permission‑checked, and efficiently scheduled real‑world actions.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TypeScriptMCPconcurrencyPermission SystemClaude CodeTool SchedulingLLM Tool Execution
Code Mala Tang
Written by

Code Mala Tang

Read source code together, write articles together, and enjoy spicy hot pot together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.