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:
2025-12-21 04:05:20 -08:00
parent c8a5399113
commit 1b95cdc976
18 changed files with 42 additions and 59 deletions
@@ -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...")
+2 -2
View File
@@ -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": {
+1 -1
View File
@@ -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):
+2 -2
View File
@@ -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",
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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}"
+1 -1
View File
@@ -1003,7 +1003,7 @@ wheels = [
[[package]]
name = "hanzo-mcp"
version = "0.9.8"
version = "0.9.9"
source = { editable = "." }
dependencies = [
{ name = "bashlex" },