mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
decomplect: HIP-0300 wire surface is the only public contract
The MCP wire (what tools/list reports) ships exactly one tool per axis: fs, exec, code, git, fetch, plan — action-routed. The per-action classes (ReadTool, WriteTool, EditTool, …) stay importable for in-process read-only sandboxing (swarm sub-agents) but are NOT on the wire. PyPI 0.3.1 of hanzo-tools-fs shipped the legacy split (7 tools) while the local 0.3.1 source had already migrated to TOOLS=[FsTool]. Same version number, two different contracts — the source of the 'Python MCP surfaces 32 tools, Node MCP surfaces 13' divergence that breaks contract parity. Bumping to 0.3.2 publishes the HIP-0300 surface for the first time. - pkg/hanzo-tools-fs 0.3.1 → 0.3.2: TOOLS=[FsTool]; legacy classes importable; dropped 'Edit = EditTool' alias; cleaner __init__. - pkg/hanzo-tools-shell 0.6.3 → 0.6.4: bump only (source already TOOLS=_get_detected_shell_tools()). - pkg/hanzo-tools-code 0.1.0 → 0.1.1: bump only (TOOLS=[CodeTool]). - pkg/hanzo-tools-vcs 0.1.0 → 0.1.1: bump only (TOOLS=[GitTool]). - pkg/hanzo-tools-net 0.1.0 → 0.1.1: bump only (TOOLS=[FetchTool]). - pkg/hanzo-tools-plan 0.1.0 → 0.1.1: bump only (TOOLS=[PlanTool]). - pkg/hanzo-tools-agent 0.3.1 → 0.3.2: 'Edit' alias is gone — call EditTool by its real name in swarm_tool.py. - pkg/hanzo-mcp 0.15.3 → 0.15.4: gets the HIP-0300-clean wire when consumed via 'uvx --refresh-package hanzo-tools-fs hanzo-mcp serve'.
This commit is contained in:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "hanzo-mcp"
|
||||
version = "0.15.3"
|
||||
version = "0.15.4"
|
||||
description = "The Zen of Hanzo MCP: One server to rule them all. The ultimate MCP that orchestrates all others."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
@@ -154,7 +154,7 @@ except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
from hanzo_tools.fs import Edit, get_read_only_filesystem_tools
|
||||
from hanzo_tools.fs import EditTool, get_read_only_filesystem_tools
|
||||
from hanzo_tools.core import BaseTool, PermissionManager, create_tool_context
|
||||
from hanzo_tools.jupyter import get_read_only_jupyter_tools
|
||||
|
||||
@@ -518,8 +518,8 @@ Models can be specified as:
|
||||
get_read_only_jupyter_tools(self.permission_manager)
|
||||
)
|
||||
|
||||
# Add edit tools
|
||||
self.available_tools.append(Edit(self.permission_manager))
|
||||
# Add edit tool
|
||||
self.available_tools.append(EditTool(self.permission_manager))
|
||||
|
||||
@override
|
||||
@auto_timeout("swarm")
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "hanzo-tools-agent"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
description = "Agent tools for Hanzo AI - multi-agent orchestration, CLI agents, swarms"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "hanzo-tools-code"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
description = "Code semantic tools for Hanzo AI (HIP-0300)"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
@@ -1,76 +1,38 @@
|
||||
"""Filesystem tools for Hanzo AI (HIP-0300).
|
||||
|
||||
Tools:
|
||||
- fs: Unified filesystem tool (HIP-0300)
|
||||
- read: Read file contents (returns hash)
|
||||
- write: Create new files
|
||||
- stat: File metadata
|
||||
- list: Directory listing
|
||||
- apply_patch: Edit with base_hash precondition
|
||||
- search_text: Text search
|
||||
- mkdir: Create directory
|
||||
- rm: Remove (requires confirm=true)
|
||||
The MCP wire surface is a single action-routed tool: `fs`.
|
||||
|
||||
IMPORTANT: apply_patch is the ONLY way to edit existing files.
|
||||
It requires base_hash from a previous read to prevent stale edits.
|
||||
fs.read fs.write fs.stat fs.list
|
||||
fs.apply_patch fs.search_text
|
||||
fs.mkdir fs.rm
|
||||
|
||||
Install:
|
||||
pip install hanzo-tools-fs
|
||||
`apply_patch` is the only way to edit an existing file and requires
|
||||
`base_hash` from a prior `read` so stale edits are impossible.
|
||||
|
||||
Usage:
|
||||
from hanzo_tools.fs import register_tools, TOOLS
|
||||
|
||||
# Register with MCP server
|
||||
register_tools(mcp_server, permission_manager)
|
||||
|
||||
# Or access the unified tool
|
||||
from hanzo_tools.fs import FsTool
|
||||
The per-action classes (ReadTool, WriteTool, …) are kept importable for
|
||||
in-process consumers that need read-only sandboxes — they are NOT
|
||||
registered with the MCP server. The wire contract is `fs` only.
|
||||
"""
|
||||
|
||||
# HIP-0300: Unified fs tool
|
||||
# Legacy tools (backward compatibility)
|
||||
from hanzo_tools.fs.ast import ASTTool
|
||||
from hanzo_tools.fs.edit import EditTool
|
||||
from hanzo_tools.fs.find import FindTool
|
||||
from hanzo_tools.fs.fs_tool import FsTool, fs_tool
|
||||
from hanzo_tools.fs.read import ReadTool
|
||||
from hanzo_tools.fs.search import SearchTool
|
||||
from hanzo_tools.fs.tree import TreeTool
|
||||
from hanzo_tools.fs.write import WriteTool
|
||||
from hanzo_tools.fs.search import SearchTool
|
||||
from hanzo_tools.fs.fs_tool import FsTool, fs_tool
|
||||
|
||||
# Backwards compatibility aliases
|
||||
Edit = EditTool
|
||||
Read = ReadTool
|
||||
Write = WriteTool
|
||||
# HIP-0300 wire surface — what entry-point discovery registers with MCP.
|
||||
TOOLS: list[type] = [FsTool]
|
||||
|
||||
# Read-only tools (for agent sandboxing)
|
||||
READ_ONLY_TOOLS = [
|
||||
ReadTool,
|
||||
TreeTool,
|
||||
FindTool,
|
||||
SearchTool,
|
||||
ASTTool,
|
||||
]
|
||||
|
||||
# Export list for tool discovery - HIP-0300 unified tool
|
||||
TOOLS = [FsTool]
|
||||
|
||||
# Legacy tools list (for backward compatibility)
|
||||
LEGACY_TOOLS = [
|
||||
ReadTool,
|
||||
WriteTool,
|
||||
EditTool,
|
||||
TreeTool,
|
||||
FindTool,
|
||||
SearchTool,
|
||||
ASTTool,
|
||||
]
|
||||
# In-process read-only set, used by sandboxed agents (e.g. swarm subagents).
|
||||
# NOT on the MCP wire.
|
||||
READ_ONLY_TOOLS: list[type] = [ReadTool, TreeTool, FindTool, SearchTool, ASTTool]
|
||||
|
||||
__all__ = [
|
||||
# HIP-0300 unified tool
|
||||
"FsTool",
|
||||
"fs_tool",
|
||||
# Legacy tool classes
|
||||
"ReadTool",
|
||||
"WriteTool",
|
||||
"EditTool",
|
||||
@@ -78,78 +40,45 @@ __all__ = [
|
||||
"FindTool",
|
||||
"SearchTool",
|
||||
"ASTTool",
|
||||
# Aliases
|
||||
"Edit",
|
||||
"Read",
|
||||
"Write",
|
||||
# Registration
|
||||
"READ_ONLY_TOOLS",
|
||||
"TOOLS",
|
||||
"register_tools",
|
||||
"get_read_only_filesystem_tools",
|
||||
"TOOLS",
|
||||
"LEGACY_TOOLS",
|
||||
"READ_ONLY_TOOLS",
|
||||
]
|
||||
|
||||
|
||||
def get_read_only_filesystem_tools(permission_manager) -> list:
|
||||
"""Get read-only filesystem tools for sandboxed agents.
|
||||
"""Instantiate the read-only filesystem tool set for sandboxed agents.
|
||||
|
||||
Returns tools that can only read files, not modify them:
|
||||
- read: Read file contents
|
||||
- tree: View directory structure
|
||||
- find: Find files by pattern
|
||||
- search: Search file contents
|
||||
- ast: Code structure analysis
|
||||
|
||||
Args:
|
||||
permission_manager: PermissionManager instance
|
||||
|
||||
Returns:
|
||||
List of instantiated read-only tools
|
||||
These are NOT exposed on the MCP wire — they're used in-process by
|
||||
agent runtimes that need to grant a sub-agent read-only file access
|
||||
without giving it `fs.write` / `fs.apply_patch` / `fs.rm`.
|
||||
"""
|
||||
tools = []
|
||||
for tool_class in READ_ONLY_TOOLS:
|
||||
out = []
|
||||
for cls in READ_ONLY_TOOLS:
|
||||
try:
|
||||
tools.append(tool_class(permission_manager))
|
||||
out.append(cls(permission_manager))
|
||||
except TypeError:
|
||||
tools.append(tool_class())
|
||||
return tools
|
||||
out.append(cls())
|
||||
return out
|
||||
|
||||
|
||||
def register_tools(
|
||||
mcp_server, permission_manager, enabled_tools: dict[str, bool] | None = None
|
||||
):
|
||||
"""Register all filesystem tools with the MCP server.
|
||||
|
||||
Args:
|
||||
mcp_server: FastMCP server instance
|
||||
permission_manager: PermissionManager for access control
|
||||
enabled_tools: Dict of tool_name -> enabled state
|
||||
|
||||
Returns:
|
||||
List of registered tool instances
|
||||
"""
|
||||
"""Register the unified `fs` tool with the MCP server."""
|
||||
from hanzo_tools.core import ToolRegistry
|
||||
|
||||
enabled = enabled_tools or {}
|
||||
registered = []
|
||||
|
||||
for tool_class in TOOLS:
|
||||
tool_name = (
|
||||
tool_class.name
|
||||
if hasattr(tool_class, "name")
|
||||
else tool_class.__name__.lower()
|
||||
)
|
||||
|
||||
if enabled.get(tool_name, True): # Enabled by default
|
||||
try:
|
||||
tool = tool_class(permission_manager)
|
||||
ToolRegistry.register_tool(mcp_server, tool)
|
||||
registered.append(tool)
|
||||
except TypeError:
|
||||
# Tool doesn't need permission_manager
|
||||
tool = tool_class()
|
||||
ToolRegistry.register_tool(mcp_server, tool)
|
||||
registered.append(tool)
|
||||
|
||||
name = getattr(tool_class, "name", tool_class.__name__.lower())
|
||||
if not enabled.get(name, True):
|
||||
continue
|
||||
try:
|
||||
tool = tool_class(permission_manager)
|
||||
except TypeError:
|
||||
tool = tool_class()
|
||||
ToolRegistry.register_tool(mcp_server, tool)
|
||||
registered.append(tool)
|
||||
return registered
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "hanzo-tools-fs"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
description = "Filesystem tools for Hanzo AI - read, write, edit, search, find"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "hanzo-tools-net"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
description = "Network tools for Hanzo AI (HIP-0300)"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "hanzo-tools-plan"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
description = "Plan orchestration tools for Hanzo AI (HIP-0300)"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "hanzo-tools-shell"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
description = "Shell/command execution tools with auto-detection - only exposes your active shell (zsh, bash, fish, dash, ksh, tcsh, csh)"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "hanzo-tools-vcs"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
description = "Unified version control tool for Hanzo AI (HIP-0300)"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
Reference in New Issue
Block a user