ThinkChain establishes a direct connection between Claude's streaming API and local tools, piping results immediately into the model's reasoning loop. This creates a fluid "think-act-think-respond" cycle that avoids the need for heavy middleware.
The framework leverages Claude’s interleaved thinking and fine-grained tool streaming features. Users can observe the model’s reasoning process step by step as tools execute and their outputs shape the very next thought. The system supports concurrent tool execution, and every interaction is governed by strict type checks.
Local Python tools and MCP servers are managed within a single registry, providing Claude with a unified, extensible toolkit.
Quick Start
Option 1: uv run (zero configuration, recommended)
git clone https://github.com/martinbowling/ThinkChain.git
cd ThinkChain
echo "ANTHROPIC_API_KEY=your-key-here" > .env
uv run thinkchain.py # Enhanced UI with rich formatting
uv run thinkchain_cli.py # Minimal CLI
uv run run.py # Smart launcher (auto-detects the best UI)
Option 2: Traditional installation
git clone https://github.com/martinbowling/ThinkChain.git
cd ThinkChain
uv pip install -r requirements.txt
echo "ANTHROPIC_API_KEY=your-key-here" > .env
python run.py
How Tool Injection Works
When Claude triggers a tool:
This creates a closed loop: think → tool → think → respond.
Dynamic Tool Discovery
/tools directory./refresh command during development to update tools without restarting the session.Enhanced CLI
rich for terminal colors, borders, and progress bars.Streaming Architecture
Technical Architecture
Tool Injection System
The core mechanism is implemented as follows:
async def stream_once(messages, tools):
async with client.messages.stream(
model="claude-sonnet-4-20250514",
messages=messages,
tools=tools,
betas=["interleaved-thinking-2025-05-14", "fine-grained-tool-streaming-2025-05-14"],
thinking_budget=1024
) as stream:
async for event in stream:
if event.type == "tool_use":
result = await execute_tool(event.name, event.input)
yield {"type": "tool_result", "content": result}
The tool output becomes immediate context for Claude's subsequent reasoning step.
Tool Discovery Flow
Local tools (/tools/*.py) → Validate → Register
↓
MCP Servers (config.json) → Connect → Register → Unified List → Claude API
Every tool implements the BaseTool interface:
class BaseTool:
@property
def name(self) -> str: ...
@property
def description(self) -> str: ...
@property
def input_schema(self) -> Dict[str, Any]: ...
def execute(self, **kwargs) -> str: ...
Streaming Event Flow
User Input → Claude API → Thinking Stream → Tool Detection → Tool Execution
↑ ↓
Response ← Thinking Integration ← Tool Result Injection ← Tool Output
Available Tools
Local Tools (/tools)
Network & Data
weathertool: Fetches live weather data via wttr.in.duckduckgotool: Performs real-time web and restaurant searches.webscrapertool: Extracts the primary content from any URL.Files & Development
filecreatortool: Generates files with specific content and structures.fileedittool: Handles full or partial content replacement and search-and-replace tasks.filecontentreadertool: Reads multiple files simultaneously.createfolderstool: Creates nested directory structures.diffeditortool: Executes precise text replacements within files.Dev & Package Management
uvpackagemanager: Provides a full interface for the uv package manager.lintingtool: Runs the Ruff linter on Python source files.toolcreator: Generates new tools dynamically using natural language prompts.MCP Server Support
Configure these within mcp_config.json:
Slash Commands
The following commands are available during active sessions:
/refresh or /reload: Re-scan and reload tools./tools: Browse the full tool catalog by category./status: View current system status./clear: Clear the console while maintaining the status bar./config: View the current configuration./config model <model_name>: Switch between Sonnet and Opus models./config thinking <1024-16000>: Modify the thinking token budget./help: Display the help menu./exit or /quit: Terminate the session.Configuration
Environment
Create a .env file:
ANTHROPIC_API_KEY=your-key-here
MCP Servers
Edit mcp_config.json:
{
"mcpServers": {
"sqlite": {
"command": "uvx",
"args": ["mcp-server-sqlite", "--db-path", "./database.db"],
"enabled": true
},
"puppeteer": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-puppeteer"],
"enabled": false
}
}
}
Model Configuration
The framework supports two Claude models:
claude-sonnet-4-20250514 (default): Fast and efficient.claude-opus-4-20250514: Most capable, though slower.Adjustable parameters:
Runtime Config
/config model claude-opus-4-20250514
/config thinking 8192
Creating a New Local Tool
To add a tool, create a Python file in /tools/, such as /tools/mytool.py:
from tools.base import BaseTool
class MyTool(BaseTool):
name = "mytool"
description = """
Detailed description of what the tool does.
Use this tool when the user asks for:
- Specific use case 1
- Specific use case 2
- "keywords that trigger this tool"
"""
input_schema = {
"type": "object",
"properties": {
"input_param": {
"type": "string",
"description": "Description of this parameter"
},
"optional_param": {
"type": "integer",
"description": "Optional parameter with default",
"default": 10
}
},
"required": ["input_param"]
}
def execute(self, **kwargs) -> str:
input_param = kwargs.get("input_param")
optional_param = kwargs.get("optional_param", 10)
result = f"Processed: {input_param} with {optional_param}"
return result
Key Requirements
mytool.py requires class MyTool).BaseTool.name, description, input_schema, and the execute() method.execute() method must return a string.Adding MCP Servers
Most MCP servers can be installed using uvx or npx:
uvx install mcp-server-sqlite
npm install -g @modelcontextprotocol/server-puppeteer
npm install -g @modelcontextprotocol/server-brave-search
Update mcp_config.json accordingly:
{
"mcpServers": {
"my-server": {
"command": "uvx",
"args": ["my-mcp-server", "--custom-arg", "value"],
"description": "What this server provides",
"enabled": true,
"env": {
"API_KEY": "required-key"
}
}
}
}
Development Workflow
vim tools/newtool.pypython thinkchain.py/refresh"Use the new tool to do X"Any print statements within execute() will output to the console for debugging. Return specific error strings to allow Claude to interpret and correct issues. Review startup logs to confirm successful tool discovery.
Running Different Interfaces
python run.py # Smart launcher
python thinkchain.py # Full UI with formatting
python thinkchain_cli.py # Minimalist interface
uv run run.py # Automatic dependency handling via uv
Dependencies
Core requirements:
anthropic>=0.25.0sseclient-pypydanticpython-dotenvEnhanced UI (optional):
richprompt_toolkitMCP (optional):
mcpuvx or npxTool-specific dependencies (automatically installed for network tools):
requestsbeautifulsoup4
Jules Extension for Gemini CLI: Asynchronous Tasks and Automated GitHub PRs
Prompt Tools: Open-Source Desktop App to Stop Losing Your Best AI Prompts
What to Eat: AI Recipes and Meal Planning You Can Self-Host
LiveMCPBench: Benchmark AI Agents on Real-World MCP Tool Tasks
Parlant: Build AI Agents That Follow Rules, Not Prompts
LVCHA VPN Review: A Permanently Free VPN with No Ads and Fast Speeds
Chatterbox TTS API: Open Source Text-to-Speech for Developers
AingDesk: Run Local AI Models and Build a Private Knowledge Base
II-Agent Review: An Open-Source LLM Assistant Built for Autonomous Tasks
Nping: A High-Performance Concurrent Ping Tool in Rust with Live Charts
DeerFlow: Modular Multi-Agent Research With LangGraph and MCP
Xiaomi MiMo-7B: Built From Scratch for Math and Code Reasoning