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.
- hanzo_mcp/__init__.py +6 -0
- hanzo_mcp/__main__.py +1 -1
- hanzo_mcp/analytics/__init__.py +2 -2
- hanzo_mcp/analytics/posthog_analytics.py +76 -82
- hanzo_mcp/cli.py +31 -36
- hanzo_mcp/cli_enhanced.py +94 -72
- hanzo_mcp/cli_plugin.py +27 -17
- hanzo_mcp/config/__init__.py +2 -2
- hanzo_mcp/config/settings.py +112 -88
- hanzo_mcp/config/tool_config.py +32 -34
- hanzo_mcp/dev_server.py +66 -67
- hanzo_mcp/prompts/__init__.py +94 -12
- hanzo_mcp/prompts/enhanced_prompts.py +809 -0
- hanzo_mcp/prompts/example_custom_prompt.py +6 -5
- hanzo_mcp/prompts/project_todo_reminder.py +0 -1
- hanzo_mcp/prompts/tool_explorer.py +10 -7
- hanzo_mcp/server.py +17 -21
- hanzo_mcp/server_enhanced.py +15 -22
- hanzo_mcp/tools/__init__.py +56 -28
- hanzo_mcp/tools/agent/__init__.py +16 -19
- hanzo_mcp/tools/agent/agent.py +82 -65
- hanzo_mcp/tools/agent/agent_tool.py +152 -122
- hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +66 -62
- hanzo_mcp/tools/agent/clarification_protocol.py +55 -50
- hanzo_mcp/tools/agent/clarification_tool.py +11 -10
- hanzo_mcp/tools/agent/claude_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/claude_desktop_auth.py +130 -144
- hanzo_mcp/tools/agent/cli_agent_base.py +59 -53
- hanzo_mcp/tools/agent/code_auth.py +102 -107
- hanzo_mcp/tools/agent/code_auth_tool.py +28 -27
- hanzo_mcp/tools/agent/codex_cli_tool.py +20 -19
- hanzo_mcp/tools/agent/critic_tool.py +86 -73
- hanzo_mcp/tools/agent/gemini_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/grok_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/iching_tool.py +404 -139
- hanzo_mcp/tools/agent/network_tool.py +89 -73
- hanzo_mcp/tools/agent/prompt.py +2 -1
- hanzo_mcp/tools/agent/review_tool.py +101 -98
- hanzo_mcp/tools/agent/swarm_alias.py +87 -0
- hanzo_mcp/tools/agent/swarm_tool.py +246 -161
- hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +134 -92
- hanzo_mcp/tools/agent/tool_adapter.py +21 -11
- hanzo_mcp/tools/common/__init__.py +1 -1
- hanzo_mcp/tools/common/base.py +3 -5
- hanzo_mcp/tools/common/batch_tool.py +46 -39
- hanzo_mcp/tools/common/config_tool.py +120 -84
- hanzo_mcp/tools/common/context.py +1 -5
- hanzo_mcp/tools/common/context_fix.py +5 -3
- hanzo_mcp/tools/common/critic_tool.py +4 -8
- hanzo_mcp/tools/common/decorators.py +58 -56
- hanzo_mcp/tools/common/enhanced_base.py +29 -32
- hanzo_mcp/tools/common/fastmcp_pagination.py +91 -94
- hanzo_mcp/tools/common/forgiving_edit.py +91 -87
- hanzo_mcp/tools/common/mode.py +15 -17
- hanzo_mcp/tools/common/mode_loader.py +27 -24
- hanzo_mcp/tools/common/paginated_base.py +61 -53
- hanzo_mcp/tools/common/paginated_response.py +72 -79
- hanzo_mcp/tools/common/pagination.py +50 -53
- hanzo_mcp/tools/common/permissions.py +4 -4
- hanzo_mcp/tools/common/personality.py +186 -138
- hanzo_mcp/tools/common/plugin_loader.py +54 -54
- hanzo_mcp/tools/common/stats.py +65 -47
- hanzo_mcp/tools/common/test_helpers.py +31 -0
- hanzo_mcp/tools/common/thinking_tool.py +4 -8
- hanzo_mcp/tools/common/tool_disable.py +17 -12
- hanzo_mcp/tools/common/tool_enable.py +13 -14
- hanzo_mcp/tools/common/tool_list.py +36 -28
- hanzo_mcp/tools/common/truncate.py +23 -23
- hanzo_mcp/tools/config/__init__.py +4 -4
- hanzo_mcp/tools/config/config_tool.py +42 -29
- hanzo_mcp/tools/config/index_config.py +37 -34
- hanzo_mcp/tools/config/mode_tool.py +175 -55
- hanzo_mcp/tools/database/__init__.py +15 -12
- hanzo_mcp/tools/database/database_manager.py +77 -75
- hanzo_mcp/tools/database/graph.py +137 -91
- hanzo_mcp/tools/database/graph_add.py +30 -18
- hanzo_mcp/tools/database/graph_query.py +178 -102
- hanzo_mcp/tools/database/graph_remove.py +33 -28
- hanzo_mcp/tools/database/graph_search.py +97 -75
- hanzo_mcp/tools/database/graph_stats.py +91 -59
- hanzo_mcp/tools/database/sql.py +107 -79
- hanzo_mcp/tools/database/sql_query.py +30 -24
- hanzo_mcp/tools/database/sql_search.py +29 -25
- hanzo_mcp/tools/database/sql_stats.py +47 -35
- hanzo_mcp/tools/editor/neovim_command.py +25 -28
- hanzo_mcp/tools/editor/neovim_edit.py +21 -23
- hanzo_mcp/tools/editor/neovim_session.py +60 -54
- hanzo_mcp/tools/filesystem/__init__.py +31 -30
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +329 -249
- hanzo_mcp/tools/filesystem/ast_tool.py +4 -4
- hanzo_mcp/tools/filesystem/base.py +1 -1
- hanzo_mcp/tools/filesystem/batch_search.py +316 -224
- hanzo_mcp/tools/filesystem/content_replace.py +4 -4
- hanzo_mcp/tools/filesystem/diff.py +71 -59
- hanzo_mcp/tools/filesystem/directory_tree.py +7 -7
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +49 -37
- hanzo_mcp/tools/filesystem/edit.py +4 -4
- hanzo_mcp/tools/filesystem/find.py +173 -80
- hanzo_mcp/tools/filesystem/find_files.py +73 -52
- hanzo_mcp/tools/filesystem/git_search.py +157 -104
- hanzo_mcp/tools/filesystem/grep.py +8 -8
- hanzo_mcp/tools/filesystem/multi_edit.py +4 -8
- hanzo_mcp/tools/filesystem/read.py +12 -10
- hanzo_mcp/tools/filesystem/rules_tool.py +59 -43
- hanzo_mcp/tools/filesystem/search_tool.py +263 -207
- hanzo_mcp/tools/filesystem/symbols_tool.py +94 -54
- hanzo_mcp/tools/filesystem/tree.py +35 -33
- hanzo_mcp/tools/filesystem/unix_aliases.py +13 -18
- hanzo_mcp/tools/filesystem/watch.py +37 -36
- hanzo_mcp/tools/filesystem/write.py +4 -8
- hanzo_mcp/tools/jupyter/__init__.py +4 -4
- hanzo_mcp/tools/jupyter/base.py +4 -5
- hanzo_mcp/tools/jupyter/jupyter.py +67 -47
- hanzo_mcp/tools/jupyter/notebook_edit.py +4 -4
- hanzo_mcp/tools/jupyter/notebook_read.py +4 -7
- hanzo_mcp/tools/llm/__init__.py +5 -7
- hanzo_mcp/tools/llm/consensus_tool.py +72 -52
- hanzo_mcp/tools/llm/llm_manage.py +101 -60
- hanzo_mcp/tools/llm/llm_tool.py +226 -166
- hanzo_mcp/tools/llm/provider_tools.py +25 -26
- hanzo_mcp/tools/lsp/__init__.py +1 -1
- hanzo_mcp/tools/lsp/lsp_tool.py +228 -143
- hanzo_mcp/tools/mcp/__init__.py +2 -3
- hanzo_mcp/tools/mcp/mcp_add.py +27 -25
- hanzo_mcp/tools/mcp/mcp_remove.py +7 -8
- hanzo_mcp/tools/mcp/mcp_stats.py +23 -22
- hanzo_mcp/tools/mcp/mcp_tool.py +129 -98
- hanzo_mcp/tools/memory/__init__.py +39 -21
- hanzo_mcp/tools/memory/knowledge_tools.py +124 -99
- hanzo_mcp/tools/memory/memory_tools.py +90 -108
- hanzo_mcp/tools/search/__init__.py +7 -2
- hanzo_mcp/tools/search/find_tool.py +297 -212
- hanzo_mcp/tools/search/unified_search.py +366 -314
- hanzo_mcp/tools/shell/__init__.py +8 -7
- hanzo_mcp/tools/shell/auto_background.py +56 -49
- hanzo_mcp/tools/shell/base.py +1 -1
- hanzo_mcp/tools/shell/base_process.py +75 -75
- hanzo_mcp/tools/shell/bash_session.py +2 -2
- hanzo_mcp/tools/shell/bash_session_executor.py +4 -4
- hanzo_mcp/tools/shell/bash_tool.py +24 -31
- hanzo_mcp/tools/shell/command_executor.py +12 -12
- hanzo_mcp/tools/shell/logs.py +43 -33
- hanzo_mcp/tools/shell/npx.py +13 -13
- hanzo_mcp/tools/shell/npx_background.py +24 -21
- hanzo_mcp/tools/shell/npx_tool.py +18 -22
- hanzo_mcp/tools/shell/open.py +19 -21
- hanzo_mcp/tools/shell/pkill.py +31 -26
- hanzo_mcp/tools/shell/process_tool.py +32 -32
- hanzo_mcp/tools/shell/processes.py +57 -58
- hanzo_mcp/tools/shell/run_background.py +24 -25
- hanzo_mcp/tools/shell/run_command.py +5 -5
- hanzo_mcp/tools/shell/run_command_windows.py +5 -5
- hanzo_mcp/tools/shell/session_storage.py +3 -3
- hanzo_mcp/tools/shell/streaming_command.py +141 -126
- hanzo_mcp/tools/shell/uvx.py +24 -25
- hanzo_mcp/tools/shell/uvx_background.py +35 -33
- hanzo_mcp/tools/shell/uvx_tool.py +18 -22
- hanzo_mcp/tools/todo/__init__.py +6 -2
- hanzo_mcp/tools/todo/todo.py +50 -37
- hanzo_mcp/tools/todo/todo_read.py +5 -8
- hanzo_mcp/tools/todo/todo_write.py +5 -7
- hanzo_mcp/tools/vector/__init__.py +40 -28
- hanzo_mcp/tools/vector/ast_analyzer.py +176 -143
- hanzo_mcp/tools/vector/git_ingester.py +170 -179
- hanzo_mcp/tools/vector/index_tool.py +96 -44
- hanzo_mcp/tools/vector/infinity_store.py +283 -228
- hanzo_mcp/tools/vector/mock_infinity.py +39 -40
- hanzo_mcp/tools/vector/project_manager.py +88 -78
- hanzo_mcp/tools/vector/vector.py +59 -42
- hanzo_mcp/tools/vector/vector_index.py +30 -27
- hanzo_mcp/tools/vector/vector_search.py +64 -45
- hanzo_mcp/types.py +6 -4
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/METADATA +1 -1
- hanzo_mcp-0.8.0.dist-info/RECORD +185 -0
- hanzo_mcp-0.7.7.dist-info/RECORD +0 -182
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
- {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
|
|
9
|
+
import asyncio
|
|
12
10
|
import tempfile
|
|
13
11
|
from abc import abstractmethod
|
|
14
|
-
from
|
|
15
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
|
131
|
+
if "--prompt-file" in cli_args:
|
|
128
132
|
# Replace placeholder with actual file
|
|
129
|
-
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
|
|
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(
|
|
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)
|