hanzo-mcp 0.6.12__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hanzo-mcp might be problematic. Click here for more details.
- hanzo_mcp/__init__.py +2 -2
- hanzo_mcp/analytics/__init__.py +5 -0
- hanzo_mcp/analytics/posthog_analytics.py +364 -0
- hanzo_mcp/cli.py +5 -5
- hanzo_mcp/cli_enhanced.py +7 -7
- hanzo_mcp/cli_plugin.py +91 -0
- hanzo_mcp/config/__init__.py +1 -1
- hanzo_mcp/config/settings.py +70 -7
- hanzo_mcp/config/tool_config.py +20 -6
- hanzo_mcp/dev_server.py +3 -3
- hanzo_mcp/prompts/project_system.py +1 -1
- hanzo_mcp/server.py +40 -3
- hanzo_mcp/server_enhanced.py +69 -0
- hanzo_mcp/tools/__init__.py +140 -31
- hanzo_mcp/tools/agent/__init__.py +85 -4
- hanzo_mcp/tools/agent/agent_tool.py +104 -6
- hanzo_mcp/tools/agent/agent_tool_v2.py +459 -0
- hanzo_mcp/tools/agent/clarification_protocol.py +220 -0
- hanzo_mcp/tools/agent/clarification_tool.py +68 -0
- hanzo_mcp/tools/agent/claude_cli_tool.py +125 -0
- hanzo_mcp/tools/agent/claude_desktop_auth.py +508 -0
- hanzo_mcp/tools/agent/cli_agent_base.py +191 -0
- hanzo_mcp/tools/agent/code_auth.py +436 -0
- hanzo_mcp/tools/agent/code_auth_tool.py +194 -0
- hanzo_mcp/tools/agent/codex_cli_tool.py +123 -0
- hanzo_mcp/tools/agent/critic_tool.py +376 -0
- hanzo_mcp/tools/agent/gemini_cli_tool.py +128 -0
- hanzo_mcp/tools/agent/grok_cli_tool.py +128 -0
- hanzo_mcp/tools/agent/iching_tool.py +380 -0
- hanzo_mcp/tools/agent/network_tool.py +273 -0
- hanzo_mcp/tools/agent/prompt.py +62 -20
- hanzo_mcp/tools/agent/review_tool.py +433 -0
- hanzo_mcp/tools/agent/swarm_tool.py +535 -0
- hanzo_mcp/tools/agent/swarm_tool_v2.py +594 -0
- hanzo_mcp/tools/common/__init__.py +15 -1
- hanzo_mcp/tools/common/base.py +5 -4
- hanzo_mcp/tools/common/batch_tool.py +103 -11
- hanzo_mcp/tools/common/config_tool.py +2 -2
- hanzo_mcp/tools/common/context.py +2 -2
- hanzo_mcp/tools/common/context_fix.py +26 -0
- hanzo_mcp/tools/common/critic_tool.py +196 -0
- hanzo_mcp/tools/common/decorators.py +208 -0
- hanzo_mcp/tools/common/enhanced_base.py +106 -0
- hanzo_mcp/tools/common/fastmcp_pagination.py +369 -0
- hanzo_mcp/tools/common/forgiving_edit.py +243 -0
- hanzo_mcp/tools/common/mode.py +116 -0
- hanzo_mcp/tools/common/mode_loader.py +105 -0
- hanzo_mcp/tools/common/paginated_base.py +230 -0
- hanzo_mcp/tools/common/paginated_response.py +307 -0
- hanzo_mcp/tools/common/pagination.py +226 -0
- hanzo_mcp/tools/common/permissions.py +1 -1
- hanzo_mcp/tools/common/personality.py +936 -0
- hanzo_mcp/tools/common/plugin_loader.py +287 -0
- hanzo_mcp/tools/common/stats.py +4 -4
- hanzo_mcp/tools/common/tool_list.py +4 -1
- hanzo_mcp/tools/common/truncate.py +101 -0
- hanzo_mcp/tools/common/validation.py +1 -1
- hanzo_mcp/tools/config/__init__.py +3 -1
- hanzo_mcp/tools/config/config_tool.py +1 -1
- hanzo_mcp/tools/config/mode_tool.py +209 -0
- hanzo_mcp/tools/database/__init__.py +1 -1
- hanzo_mcp/tools/editor/__init__.py +1 -1
- hanzo_mcp/tools/filesystem/__init__.py +48 -14
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +562 -0
- hanzo_mcp/tools/filesystem/batch_search.py +3 -3
- hanzo_mcp/tools/filesystem/diff.py +2 -2
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +338 -0
- hanzo_mcp/tools/filesystem/rules_tool.py +235 -0
- hanzo_mcp/tools/filesystem/{unified_search.py → search_tool.py} +12 -12
- hanzo_mcp/tools/filesystem/{symbols_unified.py → symbols_tool.py} +104 -5
- hanzo_mcp/tools/filesystem/watch.py +3 -2
- hanzo_mcp/tools/jupyter/__init__.py +2 -2
- hanzo_mcp/tools/jupyter/jupyter.py +1 -1
- hanzo_mcp/tools/llm/__init__.py +3 -3
- hanzo_mcp/tools/llm/llm_tool.py +648 -143
- hanzo_mcp/tools/lsp/__init__.py +5 -0
- hanzo_mcp/tools/lsp/lsp_tool.py +512 -0
- hanzo_mcp/tools/mcp/__init__.py +2 -2
- hanzo_mcp/tools/mcp/{mcp_unified.py → mcp_tool.py} +3 -3
- hanzo_mcp/tools/memory/__init__.py +76 -0
- hanzo_mcp/tools/memory/knowledge_tools.py +518 -0
- hanzo_mcp/tools/memory/memory_tools.py +456 -0
- hanzo_mcp/tools/search/__init__.py +6 -0
- hanzo_mcp/tools/search/find_tool.py +581 -0
- hanzo_mcp/tools/search/unified_search.py +953 -0
- hanzo_mcp/tools/shell/__init__.py +11 -6
- hanzo_mcp/tools/shell/auto_background.py +203 -0
- hanzo_mcp/tools/shell/base_process.py +57 -29
- hanzo_mcp/tools/shell/bash_session_executor.py +1 -1
- hanzo_mcp/tools/shell/{bash_unified.py → bash_tool.py} +18 -34
- hanzo_mcp/tools/shell/command_executor.py +2 -2
- hanzo_mcp/tools/shell/{npx_unified.py → npx_tool.py} +16 -33
- hanzo_mcp/tools/shell/open.py +2 -2
- hanzo_mcp/tools/shell/{process_unified.py → process_tool.py} +1 -1
- hanzo_mcp/tools/shell/run_command_windows.py +1 -1
- hanzo_mcp/tools/shell/streaming_command.py +594 -0
- hanzo_mcp/tools/shell/uvx.py +47 -2
- hanzo_mcp/tools/shell/uvx_background.py +47 -2
- hanzo_mcp/tools/shell/{uvx_unified.py → uvx_tool.py} +16 -33
- hanzo_mcp/tools/todo/__init__.py +14 -19
- hanzo_mcp/tools/todo/todo.py +22 -1
- hanzo_mcp/tools/vector/__init__.py +1 -1
- hanzo_mcp/tools/vector/infinity_store.py +2 -2
- hanzo_mcp/tools/vector/project_manager.py +1 -1
- hanzo_mcp/types.py +23 -0
- hanzo_mcp-0.7.0.dist-info/METADATA +516 -0
- hanzo_mcp-0.7.0.dist-info/RECORD +180 -0
- {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/entry_points.txt +1 -0
- hanzo_mcp/tools/common/palette.py +0 -344
- hanzo_mcp/tools/common/palette_loader.py +0 -108
- hanzo_mcp/tools/config/palette_tool.py +0 -179
- hanzo_mcp/tools/llm/llm_unified.py +0 -851
- hanzo_mcp-0.6.12.dist-info/METADATA +0 -339
- hanzo_mcp-0.6.12.dist-info/RECORD +0 -135
- hanzo_mcp-0.6.12.dist-info/licenses/LICENSE +0 -21
- {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/top_level.txt +0 -0
|
@@ -21,7 +21,7 @@ from hanzo_mcp.tools.filesystem.base import FilesystemBaseTool
|
|
|
21
21
|
Action = Annotated[
|
|
22
22
|
str,
|
|
23
23
|
Field(
|
|
24
|
-
description="Action: search (default), index, query, list",
|
|
24
|
+
description="Action: search (default), ast, index, query, list",
|
|
25
25
|
default="search",
|
|
26
26
|
),
|
|
27
27
|
]
|
|
@@ -88,7 +88,7 @@ class SymbolsParams(TypedDict, total=False):
|
|
|
88
88
|
|
|
89
89
|
@final
|
|
90
90
|
class SymbolsTool(FilesystemBaseTool):
|
|
91
|
-
"""
|
|
91
|
+
"""Tool for code symbol operations using tree-sitter."""
|
|
92
92
|
|
|
93
93
|
def __init__(self, permission_manager):
|
|
94
94
|
"""Initialize the symbols tool."""
|
|
@@ -105,13 +105,16 @@ class SymbolsTool(FilesystemBaseTool):
|
|
|
105
105
|
@override
|
|
106
106
|
def description(self) -> str:
|
|
107
107
|
"""Get the tool description."""
|
|
108
|
-
return """Code symbols with tree-sitter. Actions: search (default), index, query, list.
|
|
108
|
+
return """Code symbols search with tree-sitter AST. Actions: search (default), ast, index, query, list.
|
|
109
109
|
|
|
110
110
|
Usage:
|
|
111
111
|
symbols "function_name"
|
|
112
|
+
symbols --action ast --pattern "TODO" --path ./src
|
|
112
113
|
symbols --action query --symbol-type function --path ./src
|
|
113
114
|
symbols --action index --path ./project
|
|
114
|
-
symbols --action list --path ./src --symbol-type class
|
|
115
|
+
symbols --action list --path ./src --symbol-type class
|
|
116
|
+
|
|
117
|
+
Finds code structures (functions, classes, methods) with full context."""
|
|
115
118
|
|
|
116
119
|
@override
|
|
117
120
|
async def call(
|
|
@@ -129,6 +132,8 @@ symbols --action list --path ./src --symbol-type class"""
|
|
|
129
132
|
# Route to appropriate handler
|
|
130
133
|
if action == "search":
|
|
131
134
|
return await self._handle_search(params, tool_ctx)
|
|
135
|
+
elif action == "ast" or action == "grep_ast": # Support both for backward compatibility
|
|
136
|
+
return await self._handle_ast(params, tool_ctx)
|
|
132
137
|
elif action == "index":
|
|
133
138
|
return await self._handle_index(params, tool_ctx)
|
|
134
139
|
elif action == "query":
|
|
@@ -136,7 +141,7 @@ symbols --action list --path ./src --symbol-type class"""
|
|
|
136
141
|
elif action == "list":
|
|
137
142
|
return await self._handle_list(params, tool_ctx)
|
|
138
143
|
else:
|
|
139
|
-
return f"Error: Unknown action '{action}'. Valid actions: search, index, query, list"
|
|
144
|
+
return f"Error: Unknown action '{action}'. Valid actions: search, ast, index, query, list"
|
|
140
145
|
|
|
141
146
|
async def _handle_search(self, params: Dict[str, Any], tool_ctx) -> str:
|
|
142
147
|
"""Search for pattern in code with AST context."""
|
|
@@ -222,6 +227,100 @@ symbols --action list --path ./src --symbol-type class"""
|
|
|
222
227
|
|
|
223
228
|
return "\n".join(output)
|
|
224
229
|
|
|
230
|
+
async def _handle_ast(self, params: Dict[str, Any], tool_ctx) -> str:
|
|
231
|
+
"""AST-aware grep - shows code structure context around matches."""
|
|
232
|
+
pattern = params.get("pattern")
|
|
233
|
+
if not pattern:
|
|
234
|
+
return "Error: pattern required for ast action"
|
|
235
|
+
|
|
236
|
+
path = params.get("path", ".")
|
|
237
|
+
ignore_case = params.get("ignore_case", False)
|
|
238
|
+
show_context = params.get("show_context", True)
|
|
239
|
+
limit = params.get("limit", 50)
|
|
240
|
+
|
|
241
|
+
# Validate path
|
|
242
|
+
path_validation = self.validate_path(path)
|
|
243
|
+
if not path_validation.is_valid:
|
|
244
|
+
await tool_ctx.error(f"Invalid path: {path_validation.error_message}")
|
|
245
|
+
return f"Error: Invalid path: {path_validation.error_message}"
|
|
246
|
+
|
|
247
|
+
# Check permissions
|
|
248
|
+
is_allowed, error_message = await self.check_path_allowed(path, tool_ctx)
|
|
249
|
+
if not is_allowed:
|
|
250
|
+
return error_message
|
|
251
|
+
|
|
252
|
+
# Check existence
|
|
253
|
+
is_exists, error_message = await self.check_path_exists(path, tool_ctx)
|
|
254
|
+
if not is_exists:
|
|
255
|
+
return error_message
|
|
256
|
+
|
|
257
|
+
await tool_ctx.info(f"Running AST-aware grep for '{pattern}' in {path}")
|
|
258
|
+
|
|
259
|
+
# Get files to process
|
|
260
|
+
files_to_process = self._get_source_files(path)
|
|
261
|
+
if not files_to_process:
|
|
262
|
+
return f"No source code files found in {path}"
|
|
263
|
+
|
|
264
|
+
# Process files
|
|
265
|
+
results = []
|
|
266
|
+
match_count = 0
|
|
267
|
+
|
|
268
|
+
for file_path in files_to_process:
|
|
269
|
+
if match_count >= limit:
|
|
270
|
+
break
|
|
271
|
+
|
|
272
|
+
try:
|
|
273
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
274
|
+
code = f.read()
|
|
275
|
+
|
|
276
|
+
# Create TreeContext for AST parsing
|
|
277
|
+
tc = TreeContext(
|
|
278
|
+
file_path,
|
|
279
|
+
code,
|
|
280
|
+
color=False,
|
|
281
|
+
verbose=False,
|
|
282
|
+
line_number=True,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# Find matches with case sensitivity option
|
|
286
|
+
if ignore_case:
|
|
287
|
+
import re
|
|
288
|
+
loi = tc.grep(pattern, ignore_case=True)
|
|
289
|
+
else:
|
|
290
|
+
loi = tc.grep(pattern, ignore_case=False)
|
|
291
|
+
|
|
292
|
+
if loi:
|
|
293
|
+
# Always show AST context for grep_ast
|
|
294
|
+
tc.add_lines_of_interest(loi)
|
|
295
|
+
tc.add_context()
|
|
296
|
+
|
|
297
|
+
# Get the formatted output with structure
|
|
298
|
+
output = tc.format()
|
|
299
|
+
|
|
300
|
+
# Add section separator and file info
|
|
301
|
+
results.append(f"\n{'='*60}")
|
|
302
|
+
results.append(f"File: {file_path}")
|
|
303
|
+
results.append(f"Matches: {len(loi)}")
|
|
304
|
+
results.append(f"{'='*60}\n")
|
|
305
|
+
results.append(output)
|
|
306
|
+
|
|
307
|
+
match_count += len(loi)
|
|
308
|
+
|
|
309
|
+
except Exception as e:
|
|
310
|
+
await tool_ctx.warning(f"Could not parse {file_path}: {str(e)}")
|
|
311
|
+
|
|
312
|
+
if not results:
|
|
313
|
+
return f"No matches found for '{pattern}' in {path}"
|
|
314
|
+
|
|
315
|
+
output = [f"=== AST-aware Grep Results for '{pattern}' ==="]
|
|
316
|
+
output.append(f"Total matches: {match_count} in {len([r for r in results if '===' in str(r)])//4} files\n")
|
|
317
|
+
output.extend(results)
|
|
318
|
+
|
|
319
|
+
if match_count >= limit:
|
|
320
|
+
output.append(f"\n(Results limited to {limit} matches)")
|
|
321
|
+
|
|
322
|
+
return "\n".join(output)
|
|
323
|
+
|
|
225
324
|
async def _handle_index(self, params: Dict[str, Any], tool_ctx) -> str:
|
|
226
325
|
"""Index symbols in a codebase."""
|
|
227
326
|
path = params.get("path", ".")
|
|
@@ -23,16 +23,17 @@ class WatchTool(BaseTool):
|
|
|
23
23
|
|
|
24
24
|
@server.tool(name=self.name, description=self.description)
|
|
25
25
|
async def watch_handler(
|
|
26
|
+
ctx: MCPContext,
|
|
26
27
|
path: str,
|
|
27
28
|
pattern: str = "*",
|
|
28
29
|
interval: int = 1,
|
|
29
30
|
recursive: bool = True,
|
|
30
31
|
exclude: str = "",
|
|
31
|
-
duration: int = 30
|
|
32
|
+
duration: int = 30
|
|
32
33
|
) -> str:
|
|
33
34
|
"""Handle watch tool calls."""
|
|
34
35
|
return await self.run(
|
|
35
|
-
|
|
36
|
+
ctx,
|
|
36
37
|
path=path,
|
|
37
38
|
pattern=pattern,
|
|
38
39
|
interval=interval,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Jupyter notebook tools package for Hanzo
|
|
1
|
+
"""Jupyter notebook tools package for Hanzo AI.
|
|
2
2
|
|
|
3
3
|
This package provides tools for working with Jupyter notebooks (.ipynb files),
|
|
4
4
|
including reading and editing notebook cells.
|
|
@@ -29,7 +29,7 @@ def get_read_only_jupyter_tools(
|
|
|
29
29
|
Returns:
|
|
30
30
|
List of Jupyter notebook tool instances
|
|
31
31
|
"""
|
|
32
|
-
return [] #
|
|
32
|
+
return [] # Tool handles both read and write
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
def get_jupyter_tools(permission_manager: PermissionManager) -> list[BaseTool]:
|
hanzo_mcp/tools/llm/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"""LLM tools for Hanzo
|
|
1
|
+
"""LLM tools for Hanzo AI."""
|
|
2
2
|
|
|
3
|
-
from hanzo_mcp.tools.llm.
|
|
3
|
+
from hanzo_mcp.tools.llm.llm_tool import LLMTool
|
|
4
4
|
|
|
5
5
|
# Legacy imports for backwards compatibility
|
|
6
6
|
from hanzo_mcp.tools.llm.llm_tool import LLMTool
|
|
@@ -17,7 +17,7 @@ from hanzo_mcp.tools.llm.provider_tools import (
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
__all__ = [
|
|
20
|
-
"
|
|
20
|
+
"LLMTool",
|
|
21
21
|
"LLMTool",
|
|
22
22
|
"ConsensusTool",
|
|
23
23
|
"LLMManageTool",
|