mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
refactor(hanzo-mcp): rename directory_tree to tree, remove symbols alias
- Rename directory_tree tool to tree for brevity - Remove symbols alias (use ast tool directly) - Fix search tool registration to handle new factory functions - Update all references in configs, prompts, examples, and tests - Bump version to 0.9.10 Note: zsh_tool and shell_tool already existed MCP naming (mcp__hanzo__*) is standard MCP protocol format, cannot be changed
This commit is contained in:
@@ -53,7 +53,7 @@ async def batch_analyze_codebase(project_path: str) -> Dict[str, Any]:
|
||||
"-A": 10, # Get 10 lines after to see full import block
|
||||
},
|
||||
},
|
||||
{"tool_name": "directory_tree", "input": {"path": project_path, "depth": 3}},
|
||||
{"tool_name": "tree", "input": {"path": project_path, "depth": 3}},
|
||||
]
|
||||
|
||||
print(f"Running {len(batch_tasks)} analysis tasks in parallel...")
|
||||
|
||||
@@ -140,7 +140,7 @@ class TestModels(unittest.TestCase):
|
||||
"agent": agent,
|
||||
"read": read,
|
||||
"write": write,
|
||||
"directory_tree": tree,
|
||||
"tree": tree,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -156,7 +156,7 @@ class TestModels(unittest.TestCase):
|
||||
ctx,
|
||||
description="Analyze project",
|
||||
invocations=[
|
||||
{"tool_name": "directory_tree", "input": {"path": test_dir}},
|
||||
{"tool_name": "tree", "input": {"path": test_dir}},
|
||||
{
|
||||
"tool_name": "agent",
|
||||
"input": {
|
||||
|
||||
@@ -297,7 +297,7 @@ def apply_cli_overrides(args: argparse.Namespace) -> Dict[str, Any]:
|
||||
"write",
|
||||
"edit",
|
||||
"multi_edit",
|
||||
"directory_tree",
|
||||
"tree",
|
||||
"grep",
|
||||
"grep_ast",
|
||||
"content_replace",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"write": true,
|
||||
"edit": true,
|
||||
"multi_edit": true,
|
||||
"directory_tree": true,
|
||||
"tree": true,
|
||||
"rules": true,
|
||||
"grep": true,
|
||||
"find": true,
|
||||
@@ -127,7 +127,7 @@
|
||||
"categories": {
|
||||
"_comment": "Tool categories for easier management",
|
||||
"essential": [
|
||||
"read", "write", "edit", "multi_edit", "directory_tree", "rules", "grep", "find",
|
||||
"read", "write", "edit", "multi_edit", "tree", "rules", "grep", "find",
|
||||
"run_command", "run", "bash", "shell", "zsh", "stats", "tool_list", "tool_enable", "tool_disable"
|
||||
],
|
||||
"agent": [
|
||||
|
||||
@@ -61,8 +61,8 @@ TOOL_REGISTRY: Dict[str, ToolConfig] = {
|
||||
description="Perform multiple edits to a single file in one operation",
|
||||
cli_flag="--disable-multi-edit",
|
||||
),
|
||||
"directory_tree": ToolConfig(
|
||||
name="directory_tree",
|
||||
"tree": ToolConfig(
|
||||
name="tree",
|
||||
category=ToolCategory.FILESYSTEM,
|
||||
description="Display directory structure as a tree",
|
||||
cli_flag="--disable-directory-tree",
|
||||
|
||||
@@ -7,7 +7,7 @@ QUICK_START_PROMPT = """# Hanzo MCP Quick Start Guide
|
||||
### 1. Explore a New Codebase
|
||||
```python
|
||||
# Get project overview
|
||||
directory_tree(path=".", depth=3)
|
||||
tree(path=".", depth=3)
|
||||
|
||||
# Find main entry points
|
||||
find(pattern="main.*|index.*", path=".")
|
||||
|
||||
@@ -21,12 +21,11 @@ Tools for file and directory operations:
|
||||
- **write_file**: Create or overwrite files
|
||||
- **edit_file**: Make precise edits to files
|
||||
- **multi_edit**: Multiple edits in one operation
|
||||
- **directory_tree**: View directory structure
|
||||
- **tree**: View directory structure
|
||||
- **find**: Find files by pattern
|
||||
- **grep**: Search file contents
|
||||
- **grep_ast**: Search with AST context
|
||||
- **search_content**: Unified search across multiple methods
|
||||
- **symbols**: Find code symbols
|
||||
- **content_replace**: Replace patterns across files
|
||||
- **batch_search**: Run multiple searches in parallel
|
||||
|
||||
@@ -89,7 +88,7 @@ The batch tool allows you to run multiple tools in parallel for maximum efficien
|
||||
batch(
|
||||
description="Analyze project structure",
|
||||
invocations=[
|
||||
{"tool_name": "directory_tree", "input": {"path": "/project"}},
|
||||
{"tool_name": "tree", "input": {"path": "/project"}},
|
||||
{"tool_name": "grep", "input": {"pattern": "TODO", "path": "/project"}},
|
||||
{"tool_name": "find", "input": {"pattern": "*.test.js", "path": "/project"}}
|
||||
]
|
||||
@@ -101,7 +100,7 @@ batch(
|
||||
### Example 1: Code Analysis Workflow
|
||||
```python
|
||||
# First, explore the project structure
|
||||
directory_tree(path="/project", depth=3)
|
||||
tree(path="/project", depth=3)
|
||||
|
||||
# Search for specific patterns
|
||||
batch(
|
||||
@@ -257,7 +256,7 @@ content_replace(
|
||||
### Directory Exploration
|
||||
```python
|
||||
# View directory structure
|
||||
directory_tree(path="/project", depth=3, include_filtered=False)
|
||||
tree(path="/project", depth=3, include_filtered=False)
|
||||
|
||||
# Find specific file types
|
||||
find(
|
||||
@@ -462,7 +461,7 @@ batch(
|
||||
invocations=[
|
||||
{"tool_name": "run_command", "input": {"command": "npm install"}},
|
||||
{"tool_name": "run_command", "input": {"command": "pip install -r requirements.txt"}},
|
||||
{"tool_name": "directory_tree", "input": {"path": ".", "depth": 2}}
|
||||
{"tool_name": "tree", "input": {"path": ".", "depth": 2}}
|
||||
]
|
||||
)
|
||||
```
|
||||
@@ -568,14 +567,14 @@ fix_batch = batch(
|
||||
The following tools can be used in batch operations:
|
||||
- dispatch_agent
|
||||
- read_files
|
||||
- directory_tree
|
||||
- tree
|
||||
- grep
|
||||
- grep_ast
|
||||
- run_command
|
||||
- notebook_read
|
||||
- find
|
||||
- search_content
|
||||
- symbols
|
||||
- ast
|
||||
- git_search
|
||||
|
||||
Tools NOT available in batch (require state/session):
|
||||
|
||||
@@ -52,7 +52,7 @@ def get_os_info() -> tuple[str, str, str]:
|
||||
|
||||
|
||||
def get_directory_structure(path: str, max_depth: int = 3, include_filtered: bool = False) -> str:
|
||||
"""Get a directory structure similar to directory_tree tool.
|
||||
"""Get a directory structure similar to tree tool.
|
||||
|
||||
Args:
|
||||
path: The directory path to scan
|
||||
@@ -68,7 +68,7 @@ def get_directory_structure(path: str, max_depth: int = 3, include_filtered: boo
|
||||
if not dir_path.exists() or not dir_path.is_dir():
|
||||
return f"Error: {path} is not a valid directory"
|
||||
|
||||
# Define filtered directories (same as directory_tree.py)
|
||||
# Define filtered directories (same as tree tool)
|
||||
FILTERED_DIRECTORIES = {
|
||||
".git",
|
||||
"node_modules",
|
||||
|
||||
@@ -181,7 +181,7 @@ def register_all_tools(
|
||||
"write": is_tool_enabled("write", not disable_write_tools),
|
||||
"edit": is_tool_enabled("edit", not disable_write_tools),
|
||||
"multi_edit": is_tool_enabled("multi_edit", not disable_write_tools),
|
||||
"directory_tree": is_tool_enabled("directory_tree", True),
|
||||
"tree": is_tool_enabled("tree", True),
|
||||
"ast": is_tool_enabled("ast", not disable_search_tools),
|
||||
"rules": is_tool_enabled("rules", True),
|
||||
"search": is_tool_enabled("search", not disable_search_tools),
|
||||
|
||||
@@ -140,9 +140,9 @@ To make a batch call, provide the following:
|
||||
|
||||
|
||||
Available tools in batch call:
|
||||
Tool: dispatch_agent,read,directory_tree,grep,grep_ast,run_command,notebook_read
|
||||
Tool: dispatch_agent,read,tree,grep,grep_ast,run_command,notebook_read
|
||||
CLI Tools: claude,cc,codex,gemini,grok,openhands,oh,hanzo_dev,cline,aider
|
||||
AST/Symbols: ast,symbols (tree-sitter based code analysis)
|
||||
AST: ast (tree-sitter based code analysis)
|
||||
Not available: think,write,edit,multi_edit,notebook_edit
|
||||
"""
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ class ToolListTool(BaseTool):
|
||||
"legacy": [
|
||||
("directory_tree", "Legacy: Use 'tree' instead"),
|
||||
("grep", "Legacy: Use 'find' instead"),
|
||||
("grep_ast", "Legacy: Use 'symbols' instead"),
|
||||
("grep_ast", "Legacy: Use 'ast' instead"),
|
||||
("batch_search", "Legacy: Use 'search' instead"),
|
||||
("find_files", "Legacy: Use 'glob' instead"),
|
||||
("run_background", "Legacy: Use 'run_command --background'"),
|
||||
|
||||
@@ -157,7 +157,7 @@ def register_filesystem_tools(
|
||||
"write": Write,
|
||||
"edit": Edit,
|
||||
"multi_edit": MultiEdit,
|
||||
"directory_tree": DirectoryTreeTool,
|
||||
"tree": DirectoryTreeTool,
|
||||
"grep": Grep,
|
||||
"ast": ASTTool, # AST-based code structure search with tree-sitter
|
||||
"git_search": GitSearchTool,
|
||||
@@ -182,15 +182,18 @@ def register_filesystem_tools(
|
||||
for tool_name, enabled in enabled_tools.items():
|
||||
if enabled and tool_name in tool_classes:
|
||||
tool_class = tool_classes[tool_name]
|
||||
if tool_name in ["batch_search", "search"]:
|
||||
# Batch search and search require project_manager
|
||||
if tool_name == "batch_search":
|
||||
# Batch search requires project_manager
|
||||
tools.append(tool_class(permission_manager, project_manager))
|
||||
elif tool_name == "watch":
|
||||
# Watch tool is a singleton
|
||||
tools.append(tool_class(permission_manager))
|
||||
elif tool_name in ["search", "find"]:
|
||||
# New search tools are factory functions
|
||||
elif tool_name in ["search", "find"] and SEARCH_AVAILABLE:
|
||||
# New search tools are factory functions that take no args
|
||||
tools.append(tool_class(permission_manager))
|
||||
elif tool_name == "search":
|
||||
# Old search tool requires project_manager
|
||||
tools.append(tool_class(permission_manager, project_manager))
|
||||
else:
|
||||
tools.append(tool_class(permission_manager))
|
||||
else:
|
||||
@@ -219,23 +222,4 @@ def register_filesystem_tools(
|
||||
tools = get_filesystem_tools(permission_manager, project_manager)
|
||||
|
||||
ToolRegistry.register_tools(mcp_server, tools)
|
||||
|
||||
# Register 'symbols' as an alias for 'ast' to match common terminology
|
||||
try:
|
||||
ast_tool = next((t for t in tools if getattr(t, "name", "") == "ast"), None)
|
||||
if ast_tool is not None:
|
||||
|
||||
class _SymbolsAlias(ASTTool): # type: ignore[misc]
|
||||
@property
|
||||
def name(self) -> str: # type: ignore[override]
|
||||
return "symbols"
|
||||
|
||||
@property
|
||||
def description(self) -> str: # type: ignore[override]
|
||||
return f"Alias of 'ast' tool.\n\n{ast_tool.description}"
|
||||
|
||||
ToolRegistry.register_tool(mcp_server, _SymbolsAlias(permission_manager))
|
||||
except Exception:
|
||||
# Alias is best-effort; don't fail tool registration if aliasing fails
|
||||
pass
|
||||
return tools
|
||||
|
||||
@@ -67,7 +67,7 @@ class DirectoryTreeTool(FilesystemBaseTool):
|
||||
Returns:
|
||||
Tool name
|
||||
"""
|
||||
return "directory_tree"
|
||||
return "tree"
|
||||
|
||||
@property
|
||||
@override
|
||||
@@ -86,7 +86,7 @@ indented list for readability. By default, common development directories like
|
||||
requested. Only works within allowed directories."""
|
||||
|
||||
@override
|
||||
@auto_timeout("directory_tree")
|
||||
@auto_timeout("tree")
|
||||
async def call(
|
||||
self,
|
||||
ctx: MCPContext,
|
||||
@@ -290,7 +290,7 @@ requested. Only works within allowed directories."""
|
||||
tool_self = self # Create a reference to self for use in the closure
|
||||
|
||||
@mcp_server.tool(name=self.name, description=self.description)
|
||||
async def directory_tree(
|
||||
async def tree(
|
||||
ctx: MCPContext,
|
||||
path: DirectoryPath,
|
||||
depth: Depth = 3,
|
||||
|
||||
@@ -111,8 +111,8 @@ class RunCommandTool(ShellBaseTool):
|
||||
Before executing the command, please follow these steps:
|
||||
|
||||
1. Directory Verification:
|
||||
- If the command will create new directories or files, first use the directory_tree tool to verify the parent directory exists and is the correct location
|
||||
- For example, before running \"mkdir foo/bar\", first use directory_tree to check that \"foo\" exists and is the intended parent directory
|
||||
- If the command will create new directories or files, first use the tree tool to verify the parent directory exists and is the correct location
|
||||
- For example, before running \"mkdir foo/bar\", first use tree to check that \"foo\" exists and is the intended parent directory
|
||||
|
||||
2. Command Execution:
|
||||
- After ensuring proper quoting, execute the command.
|
||||
@@ -134,7 +134,7 @@ Interactive Process Handling:
|
||||
- Send control sequences (\"C-c\", \"C-z\", \"C-d\") as commands with is_input=true to interrupt processes
|
||||
- The tool prevents sending new commands while a previous command is still running (use is_input=true to interact)
|
||||
|
||||
VERY IMPORTANT: You MUST avoid using search commands like `grep`. Instead use grep, or dispatch_agent to search. You MUST avoid read tools like `cat`, `head`, `tail`, and `ls`, and use read and directory_tree to read files.
|
||||
VERY IMPORTANT: You MUST avoid using search commands like `grep`. Instead use grep, or dispatch_agent to search. You MUST avoid read tools like `cat`, `head`, `tail`, and `ls`, and use read and tree to read files.
|
||||
- If you _still_ need to run `grep`, STOP. ALWAYS USE ripgrep at `rg` first, which all Hanzo users have pre-installed.
|
||||
- When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines are ok in quoted strings).
|
||||
- Working Directory: New sessions start in the user's home directory. Use 'cd' commands to navigate to different directories within a session. Directory changes persist within the same session.
|
||||
|
||||
@@ -54,8 +54,8 @@ class RunCommandTool(ShellBaseTool):
|
||||
Before executing the command, please follow these steps:
|
||||
|
||||
1. Directory Verification:
|
||||
- If the command will create new directories or files, first use the directory_tree tool to verify the parent directory exists and is the correct location
|
||||
- For example, before running \"mkdir foo/bar\", first use directory_tree to check that \"foo\" exists and is the intended parent directory
|
||||
- If the command will create new directories or files, first use the tree tool to verify the parent directory exists and is the correct location
|
||||
- For example, before running \"mkdir foo/bar\", first use tree to check that \"foo\" exists and is the intended parent directory
|
||||
|
||||
2. Command Execution:
|
||||
- After ensuring proper quoting, execute the command.
|
||||
@@ -66,7 +66,7 @@ Usage notes:
|
||||
- You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will timeout after 120000ms (2 minutes).
|
||||
- It is very helpful if you write a clear, concise description of what this command does in 5-10 words.
|
||||
- If the output exceeds 30000 characters, output will be truncated before being returned to you.
|
||||
- VERY IMPORTANT: You MUST avoid using search commands like `find` and `grep`. Instead use Grep, Glob, or Task to search. You MUST avoid read tools like `cat`, `head`, `tail`, and `ls`, and use read and directory_tree to read files.
|
||||
- VERY IMPORTANT: You MUST avoid using search commands like `find` and `grep`. Instead use Grep, Glob, or Task to search. You MUST avoid read tools like `cat`, `head`, `tail`, and `ls`, and use read and tree to read files.
|
||||
- If you _still_ need to run `grep`, STOP. ALWAYS USE ripgrep at `rg` (or /opt/homebrew/Cellar/ripgrep/14.1.1/bin/rg) first, which all Hanzo Code users have pre-installed.
|
||||
- When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines are ok in quoted strings).
|
||||
<good-example>
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "hanzo-mcp"
|
||||
version = "0.9.9"
|
||||
version = "0.9.10"
|
||||
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"
|
||||
|
||||
@@ -46,7 +46,7 @@ class TestAgentTool:
|
||||
def mock_tools(self):
|
||||
"""Create a list of mock tools."""
|
||||
tools = []
|
||||
for name in ["read_files", "search_content", "directory_tree"]:
|
||||
for name in ["read_files", "search_content", "tree"]:
|
||||
tool = MagicMock(spec=BaseTool)
|
||||
tool.name = name
|
||||
tool.description = f"Description for {name}"
|
||||
|
||||
Generated
+1
-1
@@ -1003,7 +1003,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "hanzo-mcp"
|
||||
version = "0.9.8"
|
||||
version = "0.9.9"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "bashlex" },
|
||||
|
||||
Reference in New Issue
Block a user