• codingvillain
  • POSTS
© 2023 Cheolwan-ParkPowered by nextjs & notion API
Loading comments...

Claude Agent Toolkit

A simple Python package designed to enhance the usability and convenience of claude-code-sdk. Running the claude code based agent on docker with programmable custom tools.

  • #AI Agent
  • #Claude Code
  • #Python
  • #AI

September 11, 2025 · Cheolwan Park

Development Background

The claude-code-sdk , which leverages Claude Code's code generation and execution capabilities, is a powerful tool. However, during actual project implementation, we encountered two significant inconveniences.

The first was the complexity of tool integration. Even for adding a single function, the process of directly configuring and deploying an MCP (Model Context Protocol) server, then injecting it through configuration, proved quite cumbersome.

The second was the consistency issue of the execution environment. The claude-code-sdk fundamentally executes code in local environment subprocesses. This means execution results can vary based on local environment configurations such as user-scope installed MCP servers or CLAUDE.md files in parent directories. When development and actual execution environments differ, unexpected results could occur.

To address these challenges, we created the Claude Agent Toolkit. Our goal was to resolve these two issues and provide an intuitive and stable development experience similar to Google's ADK (Agent Development Kit).

Core Features

Decorator-Based Tool Creation

There is no longer a need to build complex MCP servers directly. Simply add the @tool decorator to regular Python functions to convert them into tools that Claude can use.

from claude_agent_toolkit import BaseTool, tool

class CalculatorTool(BaseTool):
    def __init__(self):
        super().__init__()
        self.history = []
        self.last_result = None

    @tool(description="Adds two numbers together")
    async def add(self, a: float, b: float) -> dict:
        result = a + b
        self.last_result = result
        self.history.append(f"{a} + {b} = {result}")

        return {
            "operation": f"{a} + {b}",
            "result": result,
            "message": f"The result of adding {a} and {b} is {result}"
        }

Defined tools can be used immediately by simply passing them to an Agent object.

from claude_agent_toolkit import Agent

calculator_tool = CalculatorTool()

agent = Agent(
    system_prompt="I am a friendly assistant that helps with mathematical calculations.",
    tools=[calculator_tool]
)

result = await agent.run("What is 10 plus 5?")

Docker-Based Isolated Execution

To provide an isolated execution environment unaffected by the local environment, Docker containers are used as the default executor. This ensures identical execution results regardless of the environment.

For cases where Docker usage is difficult, subprocess execution is also supported.

from claude_agent_toolkit import Agent, ExecutorType

# Default: Uses Docker executor
agent = Agent(tools=[calculator_tool])

# Switch to subprocess executor
agent = Agent(tools=[calculator_tool], executor=ExecutorType.SUBPROCESS)

Built-in Tools

Built-in tools are provided for frequently used functionalities. FileSystemTool supports secure file system access with pattern-based permission control, while DataTransferTool enables structured data transfer based on Pydantic models. Since tools run on the host, they can be used for communication between host processes and agents running in Docker containers.

from claude_agent_toolkit.tools import FileSystemTool, DataTransferTool
from pydantic import BaseModel

# File system access tool
permissions = [
    ("*.txt", "read"),           # Read permission for all text files
    ("data/**", "write"),        # Write permission for data directory
    ("logs/*.log", "read"),      # Read permission for log files
]
fs_tool = FileSystemTool(permissions=permissions, root_dir="/workspace")

# Structured data transfer tool
class UserProfile(BaseModel):
    name: str
    age: int
    email: str

user_tool = DataTransferTool.create(UserProfile, "UserProfileTool")

Key Advantages

Simple Tool Integration

Class declaration and the @tool decorator alone convert regular methods into tools that Claude Code-based agents can use. They are immediately available without complex MCP server configuration or deployment processes.

Secure Isolated Execution

Execution occurs within Docker containers, allowing only connected tools. This ensures consistent results without being affected by local environment configurations.

Update: When Should You Use This?

Recent updates to claude-code-sdk have simplified tool addition significantly. This has substantially reduced the necessity for Claude Agent Toolkit compared to when it was first created.

For simple agents and tooling needs with subprocess execution, we recommend using claude-code-sdk. It is also more suitable for rapid prototyping or when local environment configurations need to be utilized.

Conversely, Claude Agent Toolkit is recommended when isolated execution within Docker containers is required or when CPU-intensive tools are needed. While claude-code-sdk runs tools in the same process, which can cause blocking during CPU-intensive operations, Claude Agent Toolkit supports parallel execution in separate process pools through the parallel=True option. It is also useful when consistent execution environments are needed in production environments.

Getting Started

Installation is straightforward using pip.

pip install claude-agent-toolkit

After setting up the Claude Code OAuth token and running Docker Desktop, you can begin using the toolkit.

export CLAUDE_CODE_OAUTH_TOKEN='your-token-here'

Let us begin with a simple example.

import asyncio
from claude_agent_toolkit import Agent, BaseTool, tool

class HelloTool(BaseTool):
    @tool(description="Say hello")
    async def say_hello(self, name: str) -> dict:
        return f"Hello! {name}!!"

async def main():
    agent = Agent(
        tools=[HelloTool()],
        system_prompt="You are a helpful assistant."
    )

    result = await agent.run("Hello there!")
    print(result)

asyncio.run(main())

More detailed examples and documentation are available on GitHub.

GitHub - cheolwanpark/claude-agent-toolkit: Python framework for building agents using claude-code-sdk with programmable tools

Python framework for building agents using claude-code-sdk with programmable tools - cheolwanpark/claude-agent-toolkit

https://github.com/cheolwanpark/claude-agent-toolkit