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
|
@@ -150,11 +150,56 @@ Use 'processes' to list running processes and 'pkill' to stop them.
|
|
|
150
150
|
|
|
151
151
|
# Check if uvx is available
|
|
152
152
|
if not shutil.which("uvx"):
|
|
153
|
-
|
|
153
|
+
await tool_ctx.info("uvx not found, attempting to install...")
|
|
154
|
+
|
|
155
|
+
# Try to auto-install uvx
|
|
156
|
+
install_cmd = "curl -LsSf https://astral.sh/uv/install.sh | sh"
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
# Run installation
|
|
160
|
+
install_result = subprocess.run(
|
|
161
|
+
install_cmd,
|
|
162
|
+
shell=True,
|
|
163
|
+
capture_output=True,
|
|
164
|
+
text=True,
|
|
165
|
+
timeout=60
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
if install_result.returncode == 0:
|
|
169
|
+
await tool_ctx.info("uvx installed successfully!")
|
|
170
|
+
|
|
171
|
+
# Add to PATH for current session
|
|
172
|
+
import os
|
|
173
|
+
home = os.path.expanduser("~")
|
|
174
|
+
os.environ["PATH"] = f"{home}/.cargo/bin:{os.environ.get('PATH', '')}"
|
|
175
|
+
|
|
176
|
+
# Check again
|
|
177
|
+
if not shutil.which("uvx"):
|
|
178
|
+
return """Error: uvx installed but not found in PATH.
|
|
179
|
+
Please add ~/.cargo/bin to your PATH and restart your shell.
|
|
180
|
+
|
|
181
|
+
Add to ~/.zshrc or ~/.bashrc:
|
|
182
|
+
export PATH="$HOME/.cargo/bin:$PATH"
|
|
183
|
+
"""
|
|
184
|
+
else:
|
|
185
|
+
return f"""Error: Failed to install uvx automatically.
|
|
186
|
+
|
|
187
|
+
Install manually with:
|
|
154
188
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
155
189
|
|
|
156
190
|
Or on macOS:
|
|
157
|
-
brew install uv
|
|
191
|
+
brew install uv
|
|
192
|
+
|
|
193
|
+
Error details: {install_result.stderr}"""
|
|
194
|
+
|
|
195
|
+
except subprocess.TimeoutExpired:
|
|
196
|
+
return """Error: Installation timed out. Install uvx manually with:
|
|
197
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh"""
|
|
198
|
+
except Exception as e:
|
|
199
|
+
return f"""Error: Failed to auto-install uvx: {str(e)}
|
|
200
|
+
|
|
201
|
+
Install manually with:
|
|
202
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh"""
|
|
158
203
|
|
|
159
204
|
# Build command
|
|
160
205
|
cmd = ["uvx"]
|
|
@@ -18,13 +18,15 @@ class UvxTool(BaseBinaryTool):
|
|
|
18
18
|
@override
|
|
19
19
|
def description(self) -> str:
|
|
20
20
|
"""Get the tool description."""
|
|
21
|
-
return """Run Python packages with uvx
|
|
21
|
+
return """Run Python packages with uvx with automatic backgrounding for long-running processes.
|
|
22
|
+
|
|
23
|
+
Commands that run for more than 2 minutes will automatically continue in the background.
|
|
22
24
|
|
|
23
25
|
Usage:
|
|
24
26
|
uvx ruff check .
|
|
25
|
-
uvx
|
|
27
|
+
uvx mkdocs serve # Auto-backgrounds after 2 minutes
|
|
26
28
|
uvx black --check src/
|
|
27
|
-
uvx
|
|
29
|
+
uvx jupyter lab --port 8888 # Auto-backgrounds if needed"""
|
|
28
30
|
|
|
29
31
|
@override
|
|
30
32
|
def get_binary_name(self) -> str:
|
|
@@ -37,22 +39,20 @@ uvx --action background jupyter lab --port 8888"""
|
|
|
37
39
|
ctx: MCPContext,
|
|
38
40
|
package: str,
|
|
39
41
|
args: str = "",
|
|
40
|
-
action: str = "run",
|
|
41
42
|
cwd: Optional[str] = None,
|
|
42
43
|
python: Optional[str] = None,
|
|
43
44
|
) -> str:
|
|
44
|
-
"""Run a uvx command.
|
|
45
|
+
"""Run a uvx command with auto-backgrounding.
|
|
45
46
|
|
|
46
47
|
Args:
|
|
47
48
|
ctx: MCP context
|
|
48
49
|
package: Python package to run
|
|
49
50
|
args: Additional arguments
|
|
50
|
-
action: Action to perform (run, background)
|
|
51
51
|
cwd: Working directory
|
|
52
52
|
python: Python version constraint
|
|
53
53
|
|
|
54
54
|
Returns:
|
|
55
|
-
Command output or
|
|
55
|
+
Command output or background status
|
|
56
56
|
"""
|
|
57
57
|
# Prepare working directory
|
|
58
58
|
work_dir = Path(cwd).resolve() if cwd else Path.cwd()
|
|
@@ -65,28 +65,14 @@ uvx --action background jupyter lab --port 8888"""
|
|
|
65
65
|
# Build full command
|
|
66
66
|
full_args = args.split() if args else []
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
f"Started uvx process in background\n"
|
|
77
|
-
f"Process ID: {result['process_id']}\n"
|
|
78
|
-
f"PID: {result['pid']}\n"
|
|
79
|
-
f"Log file: {result['log_file']}"
|
|
80
|
-
)
|
|
81
|
-
else:
|
|
82
|
-
# Default to sync execution
|
|
83
|
-
return await self.execute_sync(
|
|
84
|
-
package,
|
|
85
|
-
cwd=work_dir,
|
|
86
|
-
flags=flags,
|
|
87
|
-
args=full_args,
|
|
88
|
-
timeout=300 # 5 minute timeout for uvx
|
|
89
|
-
)
|
|
68
|
+
# Always use execute_sync which now has auto-backgrounding
|
|
69
|
+
return await self.execute_sync(
|
|
70
|
+
package,
|
|
71
|
+
cwd=work_dir,
|
|
72
|
+
flags=flags,
|
|
73
|
+
args=full_args,
|
|
74
|
+
timeout=None # Let auto-backgrounding handle timeout
|
|
75
|
+
)
|
|
90
76
|
|
|
91
77
|
def register(self, server: FastMCP) -> None:
|
|
92
78
|
"""Register the tool with the MCP server."""
|
|
@@ -97,15 +83,13 @@ uvx --action background jupyter lab --port 8888"""
|
|
|
97
83
|
ctx: MCPContext,
|
|
98
84
|
package: str,
|
|
99
85
|
args: str = "",
|
|
100
|
-
action: str = "run",
|
|
101
86
|
cwd: Optional[str] = None,
|
|
102
|
-
python: Optional[str] = None
|
|
87
|
+
python: Optional[str] = None
|
|
103
88
|
) -> str:
|
|
104
89
|
return await tool_self.run(
|
|
105
90
|
ctx,
|
|
106
91
|
package=package,
|
|
107
92
|
args=args,
|
|
108
|
-
action=action,
|
|
109
93
|
cwd=cwd,
|
|
110
94
|
python=python
|
|
111
95
|
)
|
|
@@ -116,7 +100,6 @@ uvx --action background jupyter lab --port 8888"""
|
|
|
116
100
|
ctx,
|
|
117
101
|
package=params["package"],
|
|
118
102
|
args=params.get("args", ""),
|
|
119
|
-
action=params.get("action", "run"),
|
|
120
103
|
cwd=params.get("cwd"),
|
|
121
104
|
python=params.get("python")
|
|
122
105
|
)
|
hanzo_mcp/tools/todo/__init__.py
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
"""Todo tools package for Hanzo
|
|
1
|
+
"""Todo tools package for Hanzo AI.
|
|
2
2
|
|
|
3
|
-
This package provides
|
|
4
|
-
|
|
3
|
+
This package provides a unified todo management tool for organizing tasks
|
|
4
|
+
within Claude Desktop sessions.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from mcp.server import FastMCP
|
|
8
8
|
|
|
9
9
|
from hanzo_mcp.tools.common.base import BaseTool, ToolRegistry
|
|
10
|
-
from hanzo_mcp.tools.todo.
|
|
11
|
-
from hanzo_mcp.tools.todo.todo_write import TodoWriteTool
|
|
10
|
+
from hanzo_mcp.tools.todo.todo import TodoTool
|
|
12
11
|
|
|
13
12
|
# Export all tool classes
|
|
14
13
|
__all__ = [
|
|
15
|
-
"
|
|
16
|
-
"TodoWriteTool",
|
|
14
|
+
"TodoTool",
|
|
17
15
|
"get_todo_tools",
|
|
18
16
|
"register_todo_tools",
|
|
19
17
|
]
|
|
@@ -26,8 +24,7 @@ def get_todo_tools() -> list[BaseTool]:
|
|
|
26
24
|
List of todo tool instances
|
|
27
25
|
"""
|
|
28
26
|
return [
|
|
29
|
-
|
|
30
|
-
TodoWriteTool(),
|
|
27
|
+
TodoTool(),
|
|
31
28
|
]
|
|
32
29
|
|
|
33
30
|
|
|
@@ -44,23 +41,21 @@ def register_todo_tools(
|
|
|
44
41
|
Returns:
|
|
45
42
|
List of registered tools
|
|
46
43
|
"""
|
|
47
|
-
# Define tool mapping
|
|
44
|
+
# Define tool mapping - single unified todo tool
|
|
48
45
|
tool_classes = {
|
|
49
|
-
"
|
|
50
|
-
"todo_write": TodoWriteTool,
|
|
46
|
+
"todo": TodoTool,
|
|
51
47
|
}
|
|
52
|
-
|
|
48
|
+
|
|
53
49
|
tools = []
|
|
54
|
-
|
|
50
|
+
|
|
55
51
|
if enabled_tools:
|
|
56
52
|
# Use individual tool configuration
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
tools.append(tool_class())
|
|
53
|
+
# Support both old names and new name for backward compatibility
|
|
54
|
+
if enabled_tools.get("todo", True) or enabled_tools.get("todo_read", True) or enabled_tools.get("todo_write", True):
|
|
55
|
+
tools.append(TodoTool())
|
|
61
56
|
else:
|
|
62
57
|
# Use all tools (backward compatibility)
|
|
63
58
|
tools = get_todo_tools()
|
|
64
|
-
|
|
59
|
+
|
|
65
60
|
ToolRegistry.register_tools(mcp_server, tools)
|
|
66
61
|
return tools
|
hanzo_mcp/tools/todo/todo.py
CHANGED
|
@@ -260,6 +260,27 @@ todo --filter in_progress
|
|
|
260
260
|
self.write_todos([])
|
|
261
261
|
return f"Cleared all {count} todo(s)"
|
|
262
262
|
|
|
263
|
+
@override
|
|
263
264
|
def register(self, mcp_server) -> None:
|
|
264
265
|
"""Register this tool with the MCP server."""
|
|
265
|
-
|
|
266
|
+
tool_self = self # Create a reference to self for use in the closure
|
|
267
|
+
|
|
268
|
+
@mcp_server.tool(name=self.name, description=self.description)
|
|
269
|
+
async def todo(
|
|
270
|
+
action: Action = "list",
|
|
271
|
+
content: Content = None,
|
|
272
|
+
id: TodoId = None,
|
|
273
|
+
status: Status = None,
|
|
274
|
+
priority: Priority = None,
|
|
275
|
+
filter: Filter = None,
|
|
276
|
+
ctx: MCPContext = None,
|
|
277
|
+
) -> str:
|
|
278
|
+
return await tool_self.call(
|
|
279
|
+
ctx,
|
|
280
|
+
action=action,
|
|
281
|
+
content=content,
|
|
282
|
+
id=id,
|
|
283
|
+
status=status,
|
|
284
|
+
priority=priority,
|
|
285
|
+
filter=filter,
|
|
286
|
+
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Infinity vector database integration for Hanzo
|
|
1
|
+
"""Infinity vector database integration for Hanzo AI."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import hashlib
|
|
@@ -45,7 +45,7 @@ class SymbolSearchResult:
|
|
|
45
45
|
|
|
46
46
|
@dataclass
|
|
47
47
|
class UnifiedSearchResult:
|
|
48
|
-
"""
|
|
48
|
+
"""Search result combining text, vector, and symbol search."""
|
|
49
49
|
type: str # 'document', 'symbol', 'reference'
|
|
50
50
|
content: str
|
|
51
51
|
file_path: str
|
hanzo_mcp/types.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Type definitions for Hanzo MCP tools."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any, Optional, List
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class MCPResourceDocument:
|
|
9
|
+
"""Resource document returned by MCP tools."""
|
|
10
|
+
data: Dict[str, Any]
|
|
11
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
12
|
+
|
|
13
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
14
|
+
"""Convert to dictionary format."""
|
|
15
|
+
result = {"data": self.data}
|
|
16
|
+
if self.metadata:
|
|
17
|
+
result["metadata"] = self.metadata
|
|
18
|
+
return result
|
|
19
|
+
|
|
20
|
+
def to_json_string(self) -> str:
|
|
21
|
+
"""Convert to JSON string."""
|
|
22
|
+
import json
|
|
23
|
+
return json.dumps(self.to_dict(), indent=2)
|