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.

Files changed (117) hide show
  1. hanzo_mcp/__init__.py +2 -2
  2. hanzo_mcp/analytics/__init__.py +5 -0
  3. hanzo_mcp/analytics/posthog_analytics.py +364 -0
  4. hanzo_mcp/cli.py +5 -5
  5. hanzo_mcp/cli_enhanced.py +7 -7
  6. hanzo_mcp/cli_plugin.py +91 -0
  7. hanzo_mcp/config/__init__.py +1 -1
  8. hanzo_mcp/config/settings.py +70 -7
  9. hanzo_mcp/config/tool_config.py +20 -6
  10. hanzo_mcp/dev_server.py +3 -3
  11. hanzo_mcp/prompts/project_system.py +1 -1
  12. hanzo_mcp/server.py +40 -3
  13. hanzo_mcp/server_enhanced.py +69 -0
  14. hanzo_mcp/tools/__init__.py +140 -31
  15. hanzo_mcp/tools/agent/__init__.py +85 -4
  16. hanzo_mcp/tools/agent/agent_tool.py +104 -6
  17. hanzo_mcp/tools/agent/agent_tool_v2.py +459 -0
  18. hanzo_mcp/tools/agent/clarification_protocol.py +220 -0
  19. hanzo_mcp/tools/agent/clarification_tool.py +68 -0
  20. hanzo_mcp/tools/agent/claude_cli_tool.py +125 -0
  21. hanzo_mcp/tools/agent/claude_desktop_auth.py +508 -0
  22. hanzo_mcp/tools/agent/cli_agent_base.py +191 -0
  23. hanzo_mcp/tools/agent/code_auth.py +436 -0
  24. hanzo_mcp/tools/agent/code_auth_tool.py +194 -0
  25. hanzo_mcp/tools/agent/codex_cli_tool.py +123 -0
  26. hanzo_mcp/tools/agent/critic_tool.py +376 -0
  27. hanzo_mcp/tools/agent/gemini_cli_tool.py +128 -0
  28. hanzo_mcp/tools/agent/grok_cli_tool.py +128 -0
  29. hanzo_mcp/tools/agent/iching_tool.py +380 -0
  30. hanzo_mcp/tools/agent/network_tool.py +273 -0
  31. hanzo_mcp/tools/agent/prompt.py +62 -20
  32. hanzo_mcp/tools/agent/review_tool.py +433 -0
  33. hanzo_mcp/tools/agent/swarm_tool.py +535 -0
  34. hanzo_mcp/tools/agent/swarm_tool_v2.py +594 -0
  35. hanzo_mcp/tools/common/__init__.py +15 -1
  36. hanzo_mcp/tools/common/base.py +5 -4
  37. hanzo_mcp/tools/common/batch_tool.py +103 -11
  38. hanzo_mcp/tools/common/config_tool.py +2 -2
  39. hanzo_mcp/tools/common/context.py +2 -2
  40. hanzo_mcp/tools/common/context_fix.py +26 -0
  41. hanzo_mcp/tools/common/critic_tool.py +196 -0
  42. hanzo_mcp/tools/common/decorators.py +208 -0
  43. hanzo_mcp/tools/common/enhanced_base.py +106 -0
  44. hanzo_mcp/tools/common/fastmcp_pagination.py +369 -0
  45. hanzo_mcp/tools/common/forgiving_edit.py +243 -0
  46. hanzo_mcp/tools/common/mode.py +116 -0
  47. hanzo_mcp/tools/common/mode_loader.py +105 -0
  48. hanzo_mcp/tools/common/paginated_base.py +230 -0
  49. hanzo_mcp/tools/common/paginated_response.py +307 -0
  50. hanzo_mcp/tools/common/pagination.py +226 -0
  51. hanzo_mcp/tools/common/permissions.py +1 -1
  52. hanzo_mcp/tools/common/personality.py +936 -0
  53. hanzo_mcp/tools/common/plugin_loader.py +287 -0
  54. hanzo_mcp/tools/common/stats.py +4 -4
  55. hanzo_mcp/tools/common/tool_list.py +4 -1
  56. hanzo_mcp/tools/common/truncate.py +101 -0
  57. hanzo_mcp/tools/common/validation.py +1 -1
  58. hanzo_mcp/tools/config/__init__.py +3 -1
  59. hanzo_mcp/tools/config/config_tool.py +1 -1
  60. hanzo_mcp/tools/config/mode_tool.py +209 -0
  61. hanzo_mcp/tools/database/__init__.py +1 -1
  62. hanzo_mcp/tools/editor/__init__.py +1 -1
  63. hanzo_mcp/tools/filesystem/__init__.py +48 -14
  64. hanzo_mcp/tools/filesystem/ast_multi_edit.py +562 -0
  65. hanzo_mcp/tools/filesystem/batch_search.py +3 -3
  66. hanzo_mcp/tools/filesystem/diff.py +2 -2
  67. hanzo_mcp/tools/filesystem/directory_tree_paginated.py +338 -0
  68. hanzo_mcp/tools/filesystem/rules_tool.py +235 -0
  69. hanzo_mcp/tools/filesystem/{unified_search.py → search_tool.py} +12 -12
  70. hanzo_mcp/tools/filesystem/{symbols_unified.py → symbols_tool.py} +104 -5
  71. hanzo_mcp/tools/filesystem/watch.py +3 -2
  72. hanzo_mcp/tools/jupyter/__init__.py +2 -2
  73. hanzo_mcp/tools/jupyter/jupyter.py +1 -1
  74. hanzo_mcp/tools/llm/__init__.py +3 -3
  75. hanzo_mcp/tools/llm/llm_tool.py +648 -143
  76. hanzo_mcp/tools/lsp/__init__.py +5 -0
  77. hanzo_mcp/tools/lsp/lsp_tool.py +512 -0
  78. hanzo_mcp/tools/mcp/__init__.py +2 -2
  79. hanzo_mcp/tools/mcp/{mcp_unified.py → mcp_tool.py} +3 -3
  80. hanzo_mcp/tools/memory/__init__.py +76 -0
  81. hanzo_mcp/tools/memory/knowledge_tools.py +518 -0
  82. hanzo_mcp/tools/memory/memory_tools.py +456 -0
  83. hanzo_mcp/tools/search/__init__.py +6 -0
  84. hanzo_mcp/tools/search/find_tool.py +581 -0
  85. hanzo_mcp/tools/search/unified_search.py +953 -0
  86. hanzo_mcp/tools/shell/__init__.py +11 -6
  87. hanzo_mcp/tools/shell/auto_background.py +203 -0
  88. hanzo_mcp/tools/shell/base_process.py +57 -29
  89. hanzo_mcp/tools/shell/bash_session_executor.py +1 -1
  90. hanzo_mcp/tools/shell/{bash_unified.py → bash_tool.py} +18 -34
  91. hanzo_mcp/tools/shell/command_executor.py +2 -2
  92. hanzo_mcp/tools/shell/{npx_unified.py → npx_tool.py} +16 -33
  93. hanzo_mcp/tools/shell/open.py +2 -2
  94. hanzo_mcp/tools/shell/{process_unified.py → process_tool.py} +1 -1
  95. hanzo_mcp/tools/shell/run_command_windows.py +1 -1
  96. hanzo_mcp/tools/shell/streaming_command.py +594 -0
  97. hanzo_mcp/tools/shell/uvx.py +47 -2
  98. hanzo_mcp/tools/shell/uvx_background.py +47 -2
  99. hanzo_mcp/tools/shell/{uvx_unified.py → uvx_tool.py} +16 -33
  100. hanzo_mcp/tools/todo/__init__.py +14 -19
  101. hanzo_mcp/tools/todo/todo.py +22 -1
  102. hanzo_mcp/tools/vector/__init__.py +1 -1
  103. hanzo_mcp/tools/vector/infinity_store.py +2 -2
  104. hanzo_mcp/tools/vector/project_manager.py +1 -1
  105. hanzo_mcp/types.py +23 -0
  106. hanzo_mcp-0.7.0.dist-info/METADATA +516 -0
  107. hanzo_mcp-0.7.0.dist-info/RECORD +180 -0
  108. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/entry_points.txt +1 -0
  109. hanzo_mcp/tools/common/palette.py +0 -344
  110. hanzo_mcp/tools/common/palette_loader.py +0 -108
  111. hanzo_mcp/tools/config/palette_tool.py +0 -179
  112. hanzo_mcp/tools/llm/llm_unified.py +0 -851
  113. hanzo_mcp-0.6.12.dist-info/METADATA +0 -339
  114. hanzo_mcp-0.6.12.dist-info/RECORD +0 -135
  115. hanzo_mcp-0.6.12.dist-info/licenses/LICENSE +0 -21
  116. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/WHEEL +0 -0
  117. {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
- return """Error: uvx is not installed. Install it with:
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. Actions: run (default), background.
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 --action background mkdocs serve
27
+ uvx mkdocs serve # Auto-backgrounds after 2 minutes
26
28
  uvx black --check src/
27
- uvx --action background jupyter lab --port 8888"""
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 process info
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
- if action == "background":
69
- result = await self.execute_background(
70
- package,
71
- cwd=work_dir,
72
- flags=flags,
73
- args=full_args
74
- )
75
- return (
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
  )
@@ -1,19 +1,17 @@
1
- """Todo tools package for Hanzo MCP.
1
+ """Todo tools package for Hanzo AI.
2
2
 
3
- This package provides tools for managing todo lists across different Claude Desktop sessions,
4
- using in-memory storage to maintain separate task lists for each conversation.
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.todo_read import TodoReadTool
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
- "TodoReadTool",
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
- TodoReadTool(),
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
- "todo_read": TodoReadTool,
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
- for tool_name, enabled in enabled_tools.items():
58
- if enabled and tool_name in tool_classes:
59
- tool_class = tool_classes[tool_name]
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
@@ -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
- pass
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
- """Vector database tools for Hanzo MCP.
1
+ """Vector database tools for Hanzo AI.
2
2
 
3
3
  This package provides tools for working with local vector databases for semantic search,
4
4
  document indexing, and retrieval-augmented generation (RAG) workflows.
@@ -1,4 +1,4 @@
1
- """Infinity vector database integration for Hanzo MCP."""
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
- """Unified search result combining text, vector, and symbol search."""
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
@@ -1,4 +1,4 @@
1
- """Project-aware vector database management for Hanzo MCP."""
1
+ """Project-aware vector database management for Hanzo AI."""
2
2
 
3
3
  import os
4
4
  from pathlib import Path
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)