Core Concepts

February 17, 2026 · View on GitHub

This guide explains the fundamental building blocks of CHUK Tool Processor.

What CHUK Tool Processor Is (and Isn't)

CHUK Tool Processor is a tool execution runtime for AI systems. It deliberately does not:

  • Plan workflows or decide which tools to call
  • Manage conversation history or memory
  • Implement agent loops or reasoning chains

It does:

  • Execute tool calls reliably, with timeouts, retries, caching, and rate limits
  • Parse tool calls from any LLM format (Anthropic XML, OpenAI tool_calls, JSON)
  • Run tools locally, in isolated subprocesses, or remotely via MCP
  • Provide observability (tracing, metrics) for tool execution

This separation is intentional. Higher-level planners (your agent, LangChain, LlamaIndex) decide which tools to call. CHUK Tool Processor makes sure those calls actually succeed.


Table of Contents


1. Tool Registry

The registry is where you register tools for execution. Tools can be:

  • Simple classes with an async execute() method
  • ValidatedTool subclasses with Pydantic validation
  • StreamingTool for real-time incremental results
  • Functions registered via register_fn_tool()

Note: The registry is global by default, but you can create isolated registries with create_registry() for multi-tenant apps. See PRODUCTION_PATTERNS.md.

Basic Tool Registration

from chuk_tool_processor import register_tool

@register_tool(name="calculator")
class Calculator:
    async def execute(self, a: float, b: float, operation: str) -> dict:
        ops = {"add": a + b, "multiply": a * b, "subtract": a - b}
        return {"result": ops.get(operation, 0)}

Validated Tool with Pydantic

from chuk_tool_processor import register_tool
from chuk_tool_processor.models.validated_tool import ValidatedTool
from pydantic import BaseModel, Field

@register_tool(name="weather")
class WeatherTool(ValidatedTool):
    class Arguments(BaseModel):
        location: str = Field(..., description="City name")
        units: str = Field("celsius", description="Temperature units")

    class Result(BaseModel):
        temperature: float
        conditions: str

    async def _execute(self, location: str, units: str) -> Result:
        # Your weather API logic here
        return self.Result(temperature=22.5, conditions="Sunny")

Short Decorator Syntax

from chuk_tool_processor import tool

@tool(name="search")  # Shorter alternative to @register_tool
class SearchTool:
    async def execute(self, query: str) -> dict:
        return {"results": [f"Found: {query}"]}

2. Execution Strategies

Strategies determine how tools run:

StrategyUse CaseTrade-offs
InProcessStrategyFast, trusted toolsSpeed ✅, Isolation ❌
IsolatedStrategyUntrusted or risky codeIsolation ✅, Speed ❌

Parallel Execution

Both strategies execute tools concurrently by default. Results return in completion order (faster tools return first), not submission order. Use ToolResult.tool to match results to original calls.

Using InProcessStrategy (Default)

from chuk_tool_processor import ToolProcessor

async with ToolProcessor() as processor:
    # Tools run in the same process (fast)
    results = await processor.process(tool_calls)

Using IsolatedStrategy

from chuk_tool_processor import ToolProcessor, IsolatedStrategy, get_default_registry

async def main():
    registry = await get_default_registry()
    processor = ToolProcessor(
        strategy=IsolatedStrategy(
            registry=registry,
            max_workers=4,
            default_timeout=30.0
        )
    )
    async with processor:
        # Tools run in separate subprocesses (safe)
        results = await processor.process(tool_calls)

Note: IsolatedStrategy is an alias of SubprocessStrategy for backwards compatibility. Use IsolatedStrategy for clarity—it better communicates the security boundary intent.

When to Use Each Strategy

ScenarioRecommended Strategy
Trusted internal toolsInProcessStrategy
External/user-provided codeIsolatedStrategy
LLM-generated code executionIsolatedStrategy
Performance-critical pathInProcessStrategy
Tools that might crashIsolatedStrategy

3. Execution Wrappers (Middleware)

Wrappers add production features as composable layers:

processor = ToolProcessor(
    enable_caching=True,         # Cache expensive calls
    cache_ttl=600,               # 10 minutes
    enable_rate_limiting=True,   # Prevent abuse
    global_rate_limit=100,       # 100 req/min globally
    enable_retries=True,         # Auto-retry failures
    max_retries=3                # Up to 3 attempts
)

Execution Order

The processor stacks wrappers automatically:

Request → Cache → Rate Limit → Retry → Strategy → Tool

Response ← Cache ← Rate Limit ← Retry ← Strategy ← Tool

Available Wrappers

WrapperPurposeKey Options
CacheAvoid redundant callscache_ttl, enable_caching
Rate LimitPrevent abuseglobal_rate_limit, tool_rate_limits
RetryHandle transient failuresmax_retries, retry_delay
Circuit BreakerPrevent cascading failuresenable_circuit_breaker

See CONFIGURATION.md for all options.


4. Input Parsers (Plugins)

Parsers extract tool calls from various LLM output formats. All formats work automatically—no configuration needed.

XML Tags (Anthropic-style)

<tool name="search" args='{"query": "Python"}'/>

OpenAI tool_calls (JSON)

{
  "tool_calls": [
    {
      "type": "function",
      "function": {
        "name": "search",
        "arguments": "{\"query\": \"Python\"}"
      }
    }
  ]
}

Direct JSON (array of calls)

[
  { "tool": "search", "arguments": { "query": "Python" } }
]

Input Format Compatibility

FormatExampleUse Case
XML Tool Tag<tool name="search" args='{"q":"Python"}'/>Anthropic Claude, XML-based LLMs
OpenAI tool_callsJSON object (above)OpenAI GPT-4 function calling
Direct JSON[{"tool": "search", "arguments": {"q": "Python"}}]Generic API integrations
Single dict{"tool": "search", "arguments": {"q": "Python"}}Programmatic calls

5. MCP Integration (External Tools)

Connect to remote tool servers using the Model Context Protocol. CHUK Tool Processor supports three transport mechanisms for different use cases.

Transport Comparison

TransportUse CaseReal Examples
HTTP StreamableCloud APIs, SaaS servicesNotion (mcp.notion.com)
STDIOLocal tools, databasesSQLite (mcp-server-sqlite), Echo (chuk-mcp-echo)
SSELegacy cloud servicesAtlassian (mcp.atlassian.com)

Modern HTTP streaming transport for cloud-based MCP servers:

from chuk_tool_processor.mcp import setup_mcp_http_streamable

servers = [
    {
        "name": "notion",
        "url": "https://mcp.notion.com/mcp",
        "headers": {"Authorization": f"Bearer {access_token}"}
    }
]

processor, manager = await setup_mcp_http_streamable(
    servers=servers,
    namespace="notion",
    initialization_timeout=120.0,
    enable_caching=True,
    enable_retries=True
)

# Use Notion tools through MCP
results = await processor.process(
    '<tool name="notion.search_pages" args=\'{"query": "meeting notes"}\'/>'
)

STDIO (Best for Local Tools)

For running local MCP servers as subprocesses:

from chuk_tool_processor.mcp import setup_mcp_stdio

processor, manager = await setup_mcp_stdio(
    config_file="mcp_config.json",
    servers=["sqlite"],
    namespace="db",
    initialization_timeout=120.0
)

results = await processor.process(
    '<tool name="db.query" args=\'{"sql": "SELECT * FROM users LIMIT 10"}\'/>'
)

SSE (Legacy Support)

For backward compatibility with older MCP servers:

from chuk_tool_processor.mcp import setup_mcp_sse

servers = [
    {
        "name": "atlassian",
        "url": "https://mcp.atlassian.com/v1/sse",
        "headers": {"Authorization": f"Bearer {access_token}"}
    }
]

processor, manager = await setup_mcp_sse(
    servers=servers,
    namespace="atlassian",
    initialization_timeout=120.0
)

Architecture with MCP

    LLM Output

  Tool Processor

 ┌──────────────┬────────────────────┐
 │ Local Tools  │ Remote Tools (MCP) │
 └──────────────┴────────────────────┘

Relationship with chuk-mcp:

  • chuk-mcp is a low-level MCP protocol client (handles transports, protocol negotiation)
  • chuk-tool-processor wraps chuk-mcp to integrate external tools into your execution pipeline
  • You can use local tools, remote MCP tools, or both in the same processor

For detailed MCP examples, see MCP_INTEGRATION.md.