mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
Add detailed documentation with examples for: - hanzo-tools-fs: read, write, edit, tree, find, search, ast - hanzo-tools-shell: cmd, ps, zsh, bash, auto-backgrounding - hanzo-tools-browser: 70+ Playwright actions, device emulation - hanzo-tools-memory: memories, facts, knowledge bases, scopes - hanzo-tools-reasoning: think and critic tools - hanzo-tools-lsp: go-to-definition, references, rename, hover - hanzo-tools-refactor: rename, extract, inline, batch operations - hanzo-tools-agent: multi-agent orchestration, consensus, swarm - hanzo-tools-llm: unified LLM interface with 100+ models Each doc includes: - Installation instructions - Quick start examples - Full API reference - Usage examples - Best practices
262 lines
5.6 KiB
Markdown
262 lines
5.6 KiB
Markdown
# hanzo-tools-core
|
|
|
|
The foundation package for all Hanzo tool implementations. Provides base classes, type definitions, and utilities for building MCP-compatible tools.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
pip install hanzo-tools-core
|
|
```
|
|
|
|
Or as part of the full toolkit:
|
|
|
|
```bash
|
|
pip install hanzo-mcp[tools-all]
|
|
```
|
|
|
|
## Overview
|
|
|
|
`hanzo-tools-core` provides:
|
|
|
|
- **BaseTool** - Abstract base class for all tool implementations
|
|
- **FileSystemTool** - Specialized base for file operations
|
|
- **ToolRegistry** - Central registry for tool management
|
|
- **MCPResourceDocument** - Structured response format
|
|
- **ToolContext** - Runtime context for tool execution
|
|
- **PermissionManager** - Path-based access control
|
|
|
|
## Quick Start
|
|
|
|
### Creating a Custom Tool
|
|
|
|
```python
|
|
from hanzo_tools.core import BaseTool, ToolContext
|
|
|
|
class MyTool(BaseTool):
|
|
"""A custom tool implementation."""
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return "my_tool"
|
|
|
|
@property
|
|
def description(self) -> str:
|
|
return "Does something useful"
|
|
|
|
async def call(self, ctx: ToolContext, message: str) -> str:
|
|
"""Execute the tool.
|
|
|
|
Args:
|
|
ctx: Tool execution context
|
|
message: Input message to process
|
|
|
|
Returns:
|
|
Processed result
|
|
"""
|
|
return f"Processed: {message}"
|
|
|
|
def register(self, mcp_server):
|
|
"""Register with MCP server."""
|
|
@mcp_server.tool(name=self.name, description=self.description)
|
|
async def handler(message: str) -> str:
|
|
ctx = ToolContext()
|
|
return await self.call(ctx, message=message)
|
|
```
|
|
|
|
### Using the Tool Registry
|
|
|
|
```python
|
|
from hanzo_tools.core import ToolRegistry, BaseTool
|
|
|
|
# Register tools
|
|
registry = ToolRegistry()
|
|
registry.register(MyTool())
|
|
|
|
# Get a tool by name
|
|
tool = registry.get("my_tool")
|
|
|
|
# List all registered tools
|
|
for name, tool in registry.items():
|
|
print(f"{name}: {tool.description}")
|
|
```
|
|
|
|
## Base Classes
|
|
|
|
### BaseTool
|
|
|
|
The abstract base class all tools must inherit from:
|
|
|
|
```python
|
|
from abc import ABC, abstractmethod
|
|
|
|
class BaseTool(ABC):
|
|
"""Abstract base class for all Hanzo tools."""
|
|
|
|
@property
|
|
@abstractmethod
|
|
def name(self) -> str:
|
|
"""Unique identifier for the tool."""
|
|
...
|
|
|
|
@property
|
|
@abstractmethod
|
|
def description(self) -> str:
|
|
"""Human-readable description shown to LLMs."""
|
|
...
|
|
|
|
@abstractmethod
|
|
async def call(self, ctx: ToolContext, **params) -> str:
|
|
"""Execute the tool with given parameters."""
|
|
...
|
|
|
|
@abstractmethod
|
|
def register(self, mcp_server: FastMCP) -> None:
|
|
"""Register the tool with an MCP server."""
|
|
...
|
|
```
|
|
|
|
### FileSystemTool
|
|
|
|
Specialized base class for tools that operate on the filesystem:
|
|
|
|
```python
|
|
from hanzo_tools.core import FileSystemTool
|
|
|
|
class ReadTool(FileSystemTool):
|
|
"""Read file contents."""
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return "read"
|
|
|
|
async def call(self, ctx, file_path: str) -> str:
|
|
# Automatic path validation and permission checking
|
|
validated_path = self.validate_path(file_path)
|
|
async with aiofiles.open(validated_path) as f:
|
|
return await f.read()
|
|
```
|
|
|
|
## Response Format
|
|
|
|
### MCPResourceDocument
|
|
|
|
Structured format for tool responses:
|
|
|
|
```python
|
|
from hanzo_tools.core import MCPResourceDocument
|
|
|
|
# Create a document response
|
|
doc = MCPResourceDocument(
|
|
uri="file:///path/to/file.py",
|
|
mime_type="text/x-python",
|
|
text="def hello(): pass"
|
|
)
|
|
|
|
# Convert to JSON string for MCP
|
|
response = doc.to_json_string()
|
|
```
|
|
|
|
## Context Management
|
|
|
|
### ToolContext
|
|
|
|
Runtime context passed to every tool invocation:
|
|
|
|
```python
|
|
from hanzo_tools.core import ToolContext, create_tool_context
|
|
|
|
# Create context with custom settings
|
|
ctx = create_tool_context(
|
|
allowed_paths=["/home/user/project"],
|
|
enable_write=True,
|
|
timeout=30.0
|
|
)
|
|
|
|
# Access context in tool
|
|
async def call(self, ctx: ToolContext, **params):
|
|
if ctx.enable_write:
|
|
# Perform write operation
|
|
...
|
|
```
|
|
|
|
## Permission Management
|
|
|
|
### PermissionManager
|
|
|
|
Controls which paths tools can access:
|
|
|
|
```python
|
|
from hanzo_tools.core import PermissionManager
|
|
|
|
pm = PermissionManager(
|
|
allowed_paths=[
|
|
"/home/user/project",
|
|
"/tmp"
|
|
],
|
|
denied_paths=[
|
|
"/home/user/project/.env",
|
|
"/home/user/project/secrets"
|
|
]
|
|
)
|
|
|
|
# Check if path is allowed
|
|
if pm.is_allowed("/home/user/project/src/main.py"):
|
|
# Safe to access
|
|
...
|
|
```
|
|
|
|
## Decorators
|
|
|
|
### auto_timeout
|
|
|
|
Automatically handle timeouts for long-running operations:
|
|
|
|
```python
|
|
from hanzo_tools.core import auto_timeout
|
|
|
|
class SlowTool(BaseTool):
|
|
@auto_timeout(seconds=30)
|
|
async def call(self, ctx, **params):
|
|
# Will automatically timeout after 30 seconds
|
|
result = await slow_operation()
|
|
return result
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
Tools should return error messages as strings rather than raising exceptions:
|
|
|
|
```python
|
|
async def call(self, ctx, file_path: str) -> str:
|
|
try:
|
|
content = await read_file(file_path)
|
|
return content
|
|
except FileNotFoundError:
|
|
return f"Error: File not found: {file_path}"
|
|
except PermissionError:
|
|
return f"Error: Permission denied: {file_path}"
|
|
except Exception as e:
|
|
return f"Error: {type(e).__name__}: {str(e)}"
|
|
```
|
|
|
|
## API Reference
|
|
|
|
::: hanzo_tools.core.base.BaseTool
|
|
options:
|
|
show_source: false
|
|
members:
|
|
- name
|
|
- description
|
|
- call
|
|
- register
|
|
|
|
::: hanzo_tools.core.base.FileSystemTool
|
|
|
|
::: hanzo_tools.core.base.ToolRegistry
|
|
|
|
::: hanzo_tools.core.types.MCPResourceDocument
|
|
|
|
::: hanzo_tools.core.context.ToolContext
|
|
|
|
::: hanzo_tools.core.permissions.PermissionManager
|