hanzo-mcp 0.7.7__py3-none-any.whl → 0.8.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 (178) hide show
  1. hanzo_mcp/__init__.py +6 -0
  2. hanzo_mcp/__main__.py +1 -1
  3. hanzo_mcp/analytics/__init__.py +2 -2
  4. hanzo_mcp/analytics/posthog_analytics.py +76 -82
  5. hanzo_mcp/cli.py +31 -36
  6. hanzo_mcp/cli_enhanced.py +94 -72
  7. hanzo_mcp/cli_plugin.py +27 -17
  8. hanzo_mcp/config/__init__.py +2 -2
  9. hanzo_mcp/config/settings.py +112 -88
  10. hanzo_mcp/config/tool_config.py +32 -34
  11. hanzo_mcp/dev_server.py +66 -67
  12. hanzo_mcp/prompts/__init__.py +94 -12
  13. hanzo_mcp/prompts/enhanced_prompts.py +809 -0
  14. hanzo_mcp/prompts/example_custom_prompt.py +6 -5
  15. hanzo_mcp/prompts/project_todo_reminder.py +0 -1
  16. hanzo_mcp/prompts/tool_explorer.py +10 -7
  17. hanzo_mcp/server.py +17 -21
  18. hanzo_mcp/server_enhanced.py +15 -22
  19. hanzo_mcp/tools/__init__.py +56 -28
  20. hanzo_mcp/tools/agent/__init__.py +16 -19
  21. hanzo_mcp/tools/agent/agent.py +82 -65
  22. hanzo_mcp/tools/agent/agent_tool.py +152 -122
  23. hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +66 -62
  24. hanzo_mcp/tools/agent/clarification_protocol.py +55 -50
  25. hanzo_mcp/tools/agent/clarification_tool.py +11 -10
  26. hanzo_mcp/tools/agent/claude_cli_tool.py +21 -20
  27. hanzo_mcp/tools/agent/claude_desktop_auth.py +130 -144
  28. hanzo_mcp/tools/agent/cli_agent_base.py +59 -53
  29. hanzo_mcp/tools/agent/code_auth.py +102 -107
  30. hanzo_mcp/tools/agent/code_auth_tool.py +28 -27
  31. hanzo_mcp/tools/agent/codex_cli_tool.py +20 -19
  32. hanzo_mcp/tools/agent/critic_tool.py +86 -73
  33. hanzo_mcp/tools/agent/gemini_cli_tool.py +21 -20
  34. hanzo_mcp/tools/agent/grok_cli_tool.py +21 -20
  35. hanzo_mcp/tools/agent/iching_tool.py +404 -139
  36. hanzo_mcp/tools/agent/network_tool.py +89 -73
  37. hanzo_mcp/tools/agent/prompt.py +2 -1
  38. hanzo_mcp/tools/agent/review_tool.py +101 -98
  39. hanzo_mcp/tools/agent/swarm_alias.py +87 -0
  40. hanzo_mcp/tools/agent/swarm_tool.py +246 -161
  41. hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +134 -92
  42. hanzo_mcp/tools/agent/tool_adapter.py +21 -11
  43. hanzo_mcp/tools/common/__init__.py +1 -1
  44. hanzo_mcp/tools/common/base.py +3 -5
  45. hanzo_mcp/tools/common/batch_tool.py +46 -39
  46. hanzo_mcp/tools/common/config_tool.py +120 -84
  47. hanzo_mcp/tools/common/context.py +1 -5
  48. hanzo_mcp/tools/common/context_fix.py +5 -3
  49. hanzo_mcp/tools/common/critic_tool.py +4 -8
  50. hanzo_mcp/tools/common/decorators.py +58 -56
  51. hanzo_mcp/tools/common/enhanced_base.py +29 -32
  52. hanzo_mcp/tools/common/fastmcp_pagination.py +91 -94
  53. hanzo_mcp/tools/common/forgiving_edit.py +91 -87
  54. hanzo_mcp/tools/common/mode.py +15 -17
  55. hanzo_mcp/tools/common/mode_loader.py +27 -24
  56. hanzo_mcp/tools/common/paginated_base.py +61 -53
  57. hanzo_mcp/tools/common/paginated_response.py +72 -79
  58. hanzo_mcp/tools/common/pagination.py +50 -53
  59. hanzo_mcp/tools/common/permissions.py +4 -4
  60. hanzo_mcp/tools/common/personality.py +186 -138
  61. hanzo_mcp/tools/common/plugin_loader.py +54 -54
  62. hanzo_mcp/tools/common/stats.py +65 -47
  63. hanzo_mcp/tools/common/test_helpers.py +31 -0
  64. hanzo_mcp/tools/common/thinking_tool.py +4 -8
  65. hanzo_mcp/tools/common/tool_disable.py +17 -12
  66. hanzo_mcp/tools/common/tool_enable.py +13 -14
  67. hanzo_mcp/tools/common/tool_list.py +36 -28
  68. hanzo_mcp/tools/common/truncate.py +23 -23
  69. hanzo_mcp/tools/config/__init__.py +4 -4
  70. hanzo_mcp/tools/config/config_tool.py +42 -29
  71. hanzo_mcp/tools/config/index_config.py +37 -34
  72. hanzo_mcp/tools/config/mode_tool.py +175 -55
  73. hanzo_mcp/tools/database/__init__.py +15 -12
  74. hanzo_mcp/tools/database/database_manager.py +77 -75
  75. hanzo_mcp/tools/database/graph.py +137 -91
  76. hanzo_mcp/tools/database/graph_add.py +30 -18
  77. hanzo_mcp/tools/database/graph_query.py +178 -102
  78. hanzo_mcp/tools/database/graph_remove.py +33 -28
  79. hanzo_mcp/tools/database/graph_search.py +97 -75
  80. hanzo_mcp/tools/database/graph_stats.py +91 -59
  81. hanzo_mcp/tools/database/sql.py +107 -79
  82. hanzo_mcp/tools/database/sql_query.py +30 -24
  83. hanzo_mcp/tools/database/sql_search.py +29 -25
  84. hanzo_mcp/tools/database/sql_stats.py +47 -35
  85. hanzo_mcp/tools/editor/neovim_command.py +25 -28
  86. hanzo_mcp/tools/editor/neovim_edit.py +21 -23
  87. hanzo_mcp/tools/editor/neovim_session.py +60 -54
  88. hanzo_mcp/tools/filesystem/__init__.py +31 -30
  89. hanzo_mcp/tools/filesystem/ast_multi_edit.py +329 -249
  90. hanzo_mcp/tools/filesystem/ast_tool.py +4 -4
  91. hanzo_mcp/tools/filesystem/base.py +1 -1
  92. hanzo_mcp/tools/filesystem/batch_search.py +316 -224
  93. hanzo_mcp/tools/filesystem/content_replace.py +4 -4
  94. hanzo_mcp/tools/filesystem/diff.py +71 -59
  95. hanzo_mcp/tools/filesystem/directory_tree.py +7 -7
  96. hanzo_mcp/tools/filesystem/directory_tree_paginated.py +49 -37
  97. hanzo_mcp/tools/filesystem/edit.py +4 -4
  98. hanzo_mcp/tools/filesystem/find.py +173 -80
  99. hanzo_mcp/tools/filesystem/find_files.py +73 -52
  100. hanzo_mcp/tools/filesystem/git_search.py +157 -104
  101. hanzo_mcp/tools/filesystem/grep.py +8 -8
  102. hanzo_mcp/tools/filesystem/multi_edit.py +4 -8
  103. hanzo_mcp/tools/filesystem/read.py +12 -10
  104. hanzo_mcp/tools/filesystem/rules_tool.py +59 -43
  105. hanzo_mcp/tools/filesystem/search_tool.py +263 -207
  106. hanzo_mcp/tools/filesystem/symbols_tool.py +94 -54
  107. hanzo_mcp/tools/filesystem/tree.py +35 -33
  108. hanzo_mcp/tools/filesystem/unix_aliases.py +13 -18
  109. hanzo_mcp/tools/filesystem/watch.py +37 -36
  110. hanzo_mcp/tools/filesystem/write.py +4 -8
  111. hanzo_mcp/tools/jupyter/__init__.py +4 -4
  112. hanzo_mcp/tools/jupyter/base.py +4 -5
  113. hanzo_mcp/tools/jupyter/jupyter.py +67 -47
  114. hanzo_mcp/tools/jupyter/notebook_edit.py +4 -4
  115. hanzo_mcp/tools/jupyter/notebook_read.py +4 -7
  116. hanzo_mcp/tools/llm/__init__.py +5 -7
  117. hanzo_mcp/tools/llm/consensus_tool.py +72 -52
  118. hanzo_mcp/tools/llm/llm_manage.py +101 -60
  119. hanzo_mcp/tools/llm/llm_tool.py +226 -166
  120. hanzo_mcp/tools/llm/provider_tools.py +25 -26
  121. hanzo_mcp/tools/lsp/__init__.py +1 -1
  122. hanzo_mcp/tools/lsp/lsp_tool.py +228 -143
  123. hanzo_mcp/tools/mcp/__init__.py +2 -3
  124. hanzo_mcp/tools/mcp/mcp_add.py +27 -25
  125. hanzo_mcp/tools/mcp/mcp_remove.py +7 -8
  126. hanzo_mcp/tools/mcp/mcp_stats.py +23 -22
  127. hanzo_mcp/tools/mcp/mcp_tool.py +129 -98
  128. hanzo_mcp/tools/memory/__init__.py +39 -21
  129. hanzo_mcp/tools/memory/knowledge_tools.py +124 -99
  130. hanzo_mcp/tools/memory/memory_tools.py +90 -108
  131. hanzo_mcp/tools/search/__init__.py +7 -2
  132. hanzo_mcp/tools/search/find_tool.py +297 -212
  133. hanzo_mcp/tools/search/unified_search.py +366 -314
  134. hanzo_mcp/tools/shell/__init__.py +8 -7
  135. hanzo_mcp/tools/shell/auto_background.py +56 -49
  136. hanzo_mcp/tools/shell/base.py +1 -1
  137. hanzo_mcp/tools/shell/base_process.py +75 -75
  138. hanzo_mcp/tools/shell/bash_session.py +2 -2
  139. hanzo_mcp/tools/shell/bash_session_executor.py +4 -4
  140. hanzo_mcp/tools/shell/bash_tool.py +24 -31
  141. hanzo_mcp/tools/shell/command_executor.py +12 -12
  142. hanzo_mcp/tools/shell/logs.py +43 -33
  143. hanzo_mcp/tools/shell/npx.py +13 -13
  144. hanzo_mcp/tools/shell/npx_background.py +24 -21
  145. hanzo_mcp/tools/shell/npx_tool.py +18 -22
  146. hanzo_mcp/tools/shell/open.py +19 -21
  147. hanzo_mcp/tools/shell/pkill.py +31 -26
  148. hanzo_mcp/tools/shell/process_tool.py +32 -32
  149. hanzo_mcp/tools/shell/processes.py +57 -58
  150. hanzo_mcp/tools/shell/run_background.py +24 -25
  151. hanzo_mcp/tools/shell/run_command.py +5 -5
  152. hanzo_mcp/tools/shell/run_command_windows.py +5 -5
  153. hanzo_mcp/tools/shell/session_storage.py +3 -3
  154. hanzo_mcp/tools/shell/streaming_command.py +141 -126
  155. hanzo_mcp/tools/shell/uvx.py +24 -25
  156. hanzo_mcp/tools/shell/uvx_background.py +35 -33
  157. hanzo_mcp/tools/shell/uvx_tool.py +18 -22
  158. hanzo_mcp/tools/todo/__init__.py +6 -2
  159. hanzo_mcp/tools/todo/todo.py +50 -37
  160. hanzo_mcp/tools/todo/todo_read.py +5 -8
  161. hanzo_mcp/tools/todo/todo_write.py +5 -7
  162. hanzo_mcp/tools/vector/__init__.py +40 -28
  163. hanzo_mcp/tools/vector/ast_analyzer.py +176 -143
  164. hanzo_mcp/tools/vector/git_ingester.py +170 -179
  165. hanzo_mcp/tools/vector/index_tool.py +96 -44
  166. hanzo_mcp/tools/vector/infinity_store.py +283 -228
  167. hanzo_mcp/tools/vector/mock_infinity.py +39 -40
  168. hanzo_mcp/tools/vector/project_manager.py +88 -78
  169. hanzo_mcp/tools/vector/vector.py +59 -42
  170. hanzo_mcp/tools/vector/vector_index.py +30 -27
  171. hanzo_mcp/tools/vector/vector_search.py +64 -45
  172. hanzo_mcp/types.py +6 -4
  173. {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/METADATA +1 -1
  174. hanzo_mcp-0.8.0.dist-info/RECORD +185 -0
  175. hanzo_mcp-0.7.7.dist-info/RECORD +0 -182
  176. {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/WHEEL +0 -0
  177. {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
  178. {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/top_level.txt +0 -0
@@ -4,15 +4,13 @@ This provides common functionality for spawning CLI-based AI coding assistants
4
4
  like Claude Code, OpenAI Codex, Google Gemini, and Grok.
5
5
  """
6
6
 
7
- import asyncio
8
- import json
9
7
  import os
10
8
  import shutil
11
- import subprocess
9
+ import asyncio
12
10
  import tempfile
13
11
  from abc import abstractmethod
14
- from pathlib import Path
15
- from typing import Optional, Dict, Any, List, Tuple
12
+ from typing import List, Optional
13
+
16
14
  from mcp.server.fastmcp import Context as MCPContext
17
15
 
18
16
  from hanzo_mcp.tools.common.base import BaseTool
@@ -22,7 +20,7 @@ from hanzo_mcp.tools.common.permissions import PermissionManager
22
20
 
23
21
  class CLIAgentBase(BaseTool):
24
22
  """Base class for CLI-based AI agent tools."""
25
-
23
+
26
24
  def __init__(
27
25
  self,
28
26
  permission_manager: PermissionManager,
@@ -30,10 +28,10 @@ class CLIAgentBase(BaseTool):
30
28
  provider_name: str,
31
29
  default_model: Optional[str] = None,
32
30
  env_vars: Optional[List[str]] = None,
33
- **kwargs
31
+ **kwargs,
34
32
  ):
35
33
  """Initialize CLI agent base.
36
-
34
+
37
35
  Args:
38
36
  permission_manager: Permission manager for access control
39
37
  command_name: The CLI command name (e.g., 'claude', 'openai')
@@ -47,87 +45,100 @@ class CLIAgentBase(BaseTool):
47
45
  self.provider_name = provider_name
48
46
  self.default_model = default_model
49
47
  self.env_vars = env_vars or []
50
-
48
+
51
49
  def is_installed(self) -> bool:
52
50
  """Check if the CLI tool is installed."""
53
51
  return shutil.which(self.command_name) is not None
54
-
52
+
55
53
  def has_api_key(self) -> bool:
56
54
  """Check if API key is available in environment."""
57
55
  if not self.env_vars:
58
56
  return True # No API key needed
59
-
57
+
60
58
  for var in self.env_vars:
61
59
  if os.environ.get(var):
62
60
  return True
63
61
  return False
64
-
62
+
65
63
  @abstractmethod
66
64
  def get_cli_args(self, prompt: str, **kwargs) -> List[str]:
67
65
  """Get CLI arguments for the specific tool.
68
-
66
+
69
67
  Args:
70
68
  prompt: The prompt to send
71
69
  **kwargs: Additional arguments
72
-
70
+
73
71
  Returns:
74
72
  List of command arguments
75
73
  """
76
74
  pass
77
-
75
+
78
76
  async def execute_cli(
79
77
  self,
80
78
  ctx: MCPContext,
81
79
  prompt: str,
82
80
  working_dir: Optional[str] = None,
83
81
  timeout: int = 300,
84
- **kwargs
82
+ **kwargs,
85
83
  ) -> str:
86
84
  """Execute the CLI command.
87
-
85
+
88
86
  Args:
89
87
  ctx: MCP context
90
88
  prompt: The prompt to send
91
89
  working_dir: Working directory for the command
92
90
  timeout: Command timeout in seconds
93
91
  **kwargs: Additional arguments
94
-
92
+
95
93
  Returns:
96
94
  Command output
97
95
  """
98
96
  tool_ctx = create_tool_context(ctx)
99
-
97
+
100
98
  # Check if installed
101
99
  if not self.is_installed():
102
- error_msg = f"{self.provider_name} CLI ({self.command_name}) is not installed. "
100
+ error_msg = (
101
+ f"{self.provider_name} CLI ({self.command_name}) is not installed. "
102
+ )
103
103
  error_msg += f"Please install it first: https://github.com/anthropics/{self.command_name}"
104
104
  await tool_ctx.error(error_msg)
105
105
  return f"Error: {error_msg}"
106
-
106
+
107
107
  # Check API key if needed
108
108
  if not self.has_api_key():
109
109
  error_msg = f"No API key found for {self.provider_name}. "
110
110
  error_msg += f"Set one of: {', '.join(self.env_vars)}"
111
111
  await tool_ctx.error(error_msg)
112
112
  return f"Error: {error_msg}"
113
-
113
+
114
114
  # Get command arguments
115
115
  cli_args = self.get_cli_args(prompt, **kwargs)
116
-
116
+
117
117
  # Log command
118
- await tool_ctx.info(f"Executing {self.provider_name}: {self.command_name} {' '.join(cli_args[:3])}...")
119
-
118
+ await tool_ctx.info(
119
+ f"Executing {self.provider_name}: {self.command_name} {' '.join(cli_args[:3])}..."
120
+ )
121
+
120
122
  try:
121
123
  # Create temp file for prompt if needed
122
- with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
124
+ with tempfile.NamedTemporaryFile(
125
+ mode="w", suffix=".txt", delete=False
126
+ ) as f:
123
127
  f.write(prompt)
124
128
  prompt_file = f.name
125
-
129
+
126
130
  # Some CLIs might need the prompt via stdin or file
127
- if '--prompt-file' in cli_args:
131
+ if "--prompt-file" in cli_args:
128
132
  # Replace placeholder with actual file
129
- cli_args = [arg.replace('--prompt-file', prompt_file) if arg == '--prompt-file' else arg for arg in cli_args]
130
-
133
+ cli_args = [
134
+ (
135
+ arg.replace("--prompt-file", prompt_file)
136
+ if arg == "--prompt-file"
137
+ else arg
138
+ )
139
+ for arg in cli_args
140
+ ]
141
+
131
142
  # Execute command
132
143
  process = await asyncio.create_subprocess_exec(
133
144
  self.command_name,
@@ -135,57 +146,52 @@ class CLIAgentBase(BaseTool):
135
146
  stdout=asyncio.subprocess.PIPE,
136
147
  stderr=asyncio.subprocess.PIPE,
137
148
  stdin=asyncio.subprocess.PIPE,
138
- cwd=working_dir or os.getcwd()
149
+ cwd=working_dir or os.getcwd(),
139
150
  )
140
-
151
+
141
152
  # Send prompt via stdin if not using file
142
- if '--prompt-file' not in cli_args:
153
+ if "--prompt-file" not in cli_args:
143
154
  stdout, stderr = await asyncio.wait_for(
144
- process.communicate(input=prompt.encode()),
145
- timeout=timeout
155
+ process.communicate(input=prompt.encode()), timeout=timeout
146
156
  )
147
157
  else:
148
158
  stdout, stderr = await asyncio.wait_for(
149
- process.communicate(),
150
- timeout=timeout
159
+ process.communicate(), timeout=timeout
151
160
  )
152
-
161
+
153
162
  # Clean up temp file
154
163
  try:
155
164
  os.unlink(prompt_file)
156
- except:
165
+ except Exception:
157
166
  pass
158
-
167
+
159
168
  if process.returncode != 0:
160
169
  error_msg = stderr.decode() if stderr else "Unknown error"
161
170
  await tool_ctx.error(f"{self.provider_name} failed: {error_msg}")
162
171
  return f"Error: {error_msg}"
163
-
172
+
164
173
  result = stdout.decode()
165
174
  await tool_ctx.info(f"{self.provider_name} completed successfully")
166
175
  return result
167
-
176
+
168
177
  except asyncio.TimeoutError:
169
- await tool_ctx.error(f"{self.provider_name} timed out after {timeout} seconds")
178
+ await tool_ctx.error(
179
+ f"{self.provider_name} timed out after {timeout} seconds"
180
+ )
170
181
  return f"Error: Command timed out after {timeout} seconds"
171
182
  except Exception as e:
172
183
  await tool_ctx.error(f"{self.provider_name} error: {str(e)}")
173
184
  return f"Error: {str(e)}"
174
-
175
- async def call(
176
- self,
177
- ctx: MCPContext,
178
- prompts: str,
179
- **kwargs
180
- ) -> str:
185
+
186
+ async def call(self, ctx: MCPContext, prompts: str, **kwargs) -> str:
181
187
  """Execute the CLI agent.
182
-
188
+
183
189
  Args:
184
190
  ctx: MCP context
185
191
  prompts: The prompt(s) to send
186
192
  **kwargs: Additional arguments
187
-
193
+
188
194
  Returns:
189
195
  Agent response
190
196
  """
191
- return await self.execute_cli(ctx, prompts, **kwargs)
197
+ return await self.execute_cli(ctx, prompts, **kwargs)