hanzo-mcp 0.5.0__py3-none-any.whl → 0.5.2__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 +1 -1
- hanzo_mcp/config/settings.py +61 -0
- hanzo_mcp/tools/__init__.py +158 -12
- hanzo_mcp/tools/common/base.py +7 -2
- hanzo_mcp/tools/common/config_tool.py +396 -0
- hanzo_mcp/tools/common/stats.py +261 -0
- hanzo_mcp/tools/common/tool_disable.py +144 -0
- hanzo_mcp/tools/common/tool_enable.py +182 -0
- hanzo_mcp/tools/common/tool_list.py +263 -0
- hanzo_mcp/tools/database/__init__.py +71 -0
- hanzo_mcp/tools/database/database_manager.py +246 -0
- hanzo_mcp/tools/database/graph_add.py +257 -0
- hanzo_mcp/tools/database/graph_query.py +536 -0
- hanzo_mcp/tools/database/graph_remove.py +267 -0
- hanzo_mcp/tools/database/graph_search.py +348 -0
- hanzo_mcp/tools/database/graph_stats.py +345 -0
- hanzo_mcp/tools/database/sql_query.py +229 -0
- hanzo_mcp/tools/database/sql_search.py +296 -0
- hanzo_mcp/tools/database/sql_stats.py +254 -0
- hanzo_mcp/tools/editor/__init__.py +11 -0
- hanzo_mcp/tools/editor/neovim_command.py +272 -0
- hanzo_mcp/tools/editor/neovim_edit.py +290 -0
- hanzo_mcp/tools/editor/neovim_session.py +356 -0
- hanzo_mcp/tools/filesystem/__init__.py +20 -1
- hanzo_mcp/tools/filesystem/batch_search.py +812 -0
- hanzo_mcp/tools/filesystem/find_files.py +348 -0
- hanzo_mcp/tools/filesystem/git_search.py +505 -0
- hanzo_mcp/tools/llm/__init__.py +27 -0
- hanzo_mcp/tools/llm/consensus_tool.py +351 -0
- hanzo_mcp/tools/llm/llm_manage.py +413 -0
- hanzo_mcp/tools/llm/llm_tool.py +346 -0
- hanzo_mcp/tools/llm/provider_tools.py +412 -0
- hanzo_mcp/tools/mcp/__init__.py +11 -0
- hanzo_mcp/tools/mcp/mcp_add.py +263 -0
- hanzo_mcp/tools/mcp/mcp_remove.py +127 -0
- hanzo_mcp/tools/mcp/mcp_stats.py +165 -0
- hanzo_mcp/tools/shell/__init__.py +27 -7
- hanzo_mcp/tools/shell/logs.py +265 -0
- hanzo_mcp/tools/shell/npx.py +194 -0
- hanzo_mcp/tools/shell/npx_background.py +254 -0
- hanzo_mcp/tools/shell/pkill.py +262 -0
- hanzo_mcp/tools/shell/processes.py +279 -0
- hanzo_mcp/tools/shell/run_background.py +326 -0
- hanzo_mcp/tools/shell/uvx.py +187 -0
- hanzo_mcp/tools/shell/uvx_background.py +249 -0
- hanzo_mcp/tools/vector/__init__.py +21 -12
- hanzo_mcp/tools/vector/ast_analyzer.py +459 -0
- hanzo_mcp/tools/vector/git_ingester.py +485 -0
- hanzo_mcp/tools/vector/index_tool.py +358 -0
- hanzo_mcp/tools/vector/infinity_store.py +465 -1
- hanzo_mcp/tools/vector/mock_infinity.py +162 -0
- hanzo_mcp/tools/vector/vector_index.py +7 -6
- hanzo_mcp/tools/vector/vector_search.py +22 -7
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/METADATA +68 -20
- hanzo_mcp-0.5.2.dist-info/RECORD +106 -0
- hanzo_mcp-0.5.0.dist-info/RECORD +0 -63
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/licenses/LICENSE +0 -0
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/top_level.txt +0 -0
hanzo_mcp/__init__.py
CHANGED
hanzo_mcp/config/settings.py
CHANGED
|
@@ -280,6 +280,67 @@ def get_project_config_path(project_dir: Optional[str] = None) -> Optional[Path]
|
|
|
280
280
|
return None
|
|
281
281
|
|
|
282
282
|
|
|
283
|
+
def ensure_project_hanzo_dir(project_dir: str) -> Path:
|
|
284
|
+
"""Ensure .hanzo directory exists in project and return its path."""
|
|
285
|
+
project_path = Path(project_dir)
|
|
286
|
+
hanzo_dir = project_path / ".hanzo"
|
|
287
|
+
hanzo_dir.mkdir(exist_ok=True)
|
|
288
|
+
|
|
289
|
+
# Create default structure
|
|
290
|
+
(hanzo_dir / "db").mkdir(exist_ok=True) # Vector database
|
|
291
|
+
|
|
292
|
+
# Create default project config if it doesn't exist
|
|
293
|
+
config_path = hanzo_dir / "mcp-settings.json"
|
|
294
|
+
if not config_path.exists():
|
|
295
|
+
default_project_config = {
|
|
296
|
+
"name": project_path.name,
|
|
297
|
+
"root_path": str(project_path),
|
|
298
|
+
"rules": [
|
|
299
|
+
"Follow project-specific coding standards",
|
|
300
|
+
"Test all changes before committing",
|
|
301
|
+
"Update documentation for new features"
|
|
302
|
+
],
|
|
303
|
+
"workflows": {
|
|
304
|
+
"development": {
|
|
305
|
+
"steps": ["edit", "test", "commit"],
|
|
306
|
+
"tools": ["read", "write", "edit", "run_command"]
|
|
307
|
+
},
|
|
308
|
+
"documentation": {
|
|
309
|
+
"steps": ["read", "analyze", "write"],
|
|
310
|
+
"tools": ["read", "write", "vector_search"]
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
"tasks": [],
|
|
314
|
+
"enabled_tools": {},
|
|
315
|
+
"disabled_tools": [],
|
|
316
|
+
"mcp_servers": []
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
with open(config_path, 'w') as f:
|
|
320
|
+
json.dump(default_project_config, f, indent=2)
|
|
321
|
+
|
|
322
|
+
return hanzo_dir
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def detect_project_from_path(file_path: str) -> Optional[Dict[str, str]]:
|
|
326
|
+
"""Detect project information from a file path by looking for LLM.md."""
|
|
327
|
+
path = Path(file_path).resolve()
|
|
328
|
+
current_path = path.parent if path.is_file() else path
|
|
329
|
+
|
|
330
|
+
while current_path != current_path.parent: # Stop at filesystem root
|
|
331
|
+
llm_md_path = current_path / "LLM.md"
|
|
332
|
+
if llm_md_path.exists():
|
|
333
|
+
return {
|
|
334
|
+
"name": current_path.name,
|
|
335
|
+
"root_path": str(current_path),
|
|
336
|
+
"llm_md_path": str(llm_md_path),
|
|
337
|
+
"hanzo_dir": str(ensure_project_hanzo_dir(str(current_path)))
|
|
338
|
+
}
|
|
339
|
+
current_path = current_path.parent
|
|
340
|
+
|
|
341
|
+
return None
|
|
342
|
+
|
|
343
|
+
|
|
283
344
|
def load_settings(
|
|
284
345
|
project_dir: Optional[str] = None,
|
|
285
346
|
config_overrides: Optional[Dict[str, Any]] = None
|
hanzo_mcp/tools/__init__.py
CHANGED
|
@@ -14,13 +14,22 @@ from fastmcp import FastMCP
|
|
|
14
14
|
from hanzo_mcp.tools.agent import register_agent_tools
|
|
15
15
|
from hanzo_mcp.tools.common import register_batch_tool, register_thinking_tool
|
|
16
16
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
17
|
-
|
|
18
17
|
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
18
|
+
from hanzo_mcp.tools.common.tool_enable import ToolEnableTool
|
|
19
|
+
from hanzo_mcp.tools.common.tool_disable import ToolDisableTool
|
|
20
|
+
from hanzo_mcp.tools.common.tool_list import ToolListTool
|
|
21
|
+
from hanzo_mcp.tools.common.stats import StatsTool
|
|
19
22
|
from hanzo_mcp.tools.filesystem import register_filesystem_tools
|
|
20
23
|
from hanzo_mcp.tools.jupyter import register_jupyter_tools
|
|
21
24
|
from hanzo_mcp.tools.shell import register_shell_tools
|
|
22
25
|
from hanzo_mcp.tools.todo import register_todo_tools
|
|
23
26
|
from hanzo_mcp.tools.vector import register_vector_tools
|
|
27
|
+
from hanzo_mcp.tools.database import register_database_tools, DatabaseManager
|
|
28
|
+
from hanzo_mcp.tools.mcp.mcp_add import McpAddTool
|
|
29
|
+
from hanzo_mcp.tools.mcp.mcp_remove import McpRemoveTool
|
|
30
|
+
from hanzo_mcp.tools.mcp.mcp_stats import McpStatsTool
|
|
31
|
+
from hanzo_mcp.tools.editor import NeovimEditTool, NeovimCommandTool, NeovimSessionTool
|
|
32
|
+
from hanzo_mcp.tools.llm import LLMTool, ConsensusTool, LLMManageTool, create_provider_tools
|
|
24
33
|
|
|
25
34
|
|
|
26
35
|
def register_all_tools(
|
|
@@ -76,13 +85,38 @@ def register_all_tools(
|
|
|
76
85
|
"directory_tree": is_tool_enabled("directory_tree", True),
|
|
77
86
|
"grep": is_tool_enabled("grep", not disable_search_tools),
|
|
78
87
|
"grep_ast": is_tool_enabled("grep_ast", not disable_search_tools),
|
|
88
|
+
"git_search": is_tool_enabled("git_search", not disable_search_tools),
|
|
79
89
|
"content_replace": is_tool_enabled("content_replace", not disable_write_tools),
|
|
90
|
+
"batch_search": is_tool_enabled("batch_search", not disable_search_tools),
|
|
91
|
+
"find_files": is_tool_enabled("find_files", True),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Vector tools setup (needed for unified search)
|
|
95
|
+
project_manager = None
|
|
96
|
+
vector_enabled = {
|
|
97
|
+
"vector_index": is_tool_enabled("vector_index", False),
|
|
98
|
+
"vector_search": is_tool_enabled("vector_search", False),
|
|
80
99
|
}
|
|
81
100
|
|
|
101
|
+
# Create project manager if vector tools or batch_search are enabled
|
|
102
|
+
if any(vector_enabled.values()) or filesystem_enabled.get("batch_search", False):
|
|
103
|
+
if vector_config:
|
|
104
|
+
from hanzo_mcp.tools.vector.project_manager import ProjectVectorManager
|
|
105
|
+
search_paths = [str(path) for path in permission_manager.allowed_paths]
|
|
106
|
+
project_manager = ProjectVectorManager(
|
|
107
|
+
global_db_path=vector_config.get("data_path"),
|
|
108
|
+
embedding_model=vector_config.get("embedding_model", "text-embedding-3-small"),
|
|
109
|
+
dimension=vector_config.get("dimension", 1536),
|
|
110
|
+
)
|
|
111
|
+
# Auto-detect projects from search paths
|
|
112
|
+
detected_projects = project_manager.detect_projects(search_paths)
|
|
113
|
+
print(f"Detected {len(detected_projects)} projects with LLM.md files")
|
|
114
|
+
|
|
82
115
|
filesystem_tools = register_filesystem_tools(
|
|
83
116
|
mcp_server,
|
|
84
117
|
permission_manager,
|
|
85
118
|
enabled_tools=filesystem_enabled,
|
|
119
|
+
project_manager=project_manager,
|
|
86
120
|
)
|
|
87
121
|
for tool in filesystem_tools:
|
|
88
122
|
all_tools[tool.name] = tool
|
|
@@ -137,22 +171,14 @@ def register_all_tools(
|
|
|
137
171
|
for tool in thinking_tool:
|
|
138
172
|
all_tools[tool.name] = tool
|
|
139
173
|
|
|
140
|
-
# Register vector tools if enabled
|
|
141
|
-
vector_enabled
|
|
142
|
-
"vector_index": is_tool_enabled("vector_index", False),
|
|
143
|
-
"vector_search": is_tool_enabled("vector_search", False),
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if any(vector_enabled.values()) and vector_config:
|
|
147
|
-
# Get allowed paths for project detection
|
|
148
|
-
search_paths = [str(path) for path in permission_manager.allowed_paths]
|
|
149
|
-
|
|
174
|
+
# Register vector tools if enabled (reuse project_manager if available)
|
|
175
|
+
if any(vector_enabled.values()) and project_manager:
|
|
150
176
|
vector_tools = register_vector_tools(
|
|
151
177
|
mcp_server,
|
|
152
178
|
permission_manager,
|
|
153
179
|
vector_config=vector_config,
|
|
154
180
|
enabled_tools=vector_enabled,
|
|
155
|
-
|
|
181
|
+
project_manager=project_manager,
|
|
156
182
|
)
|
|
157
183
|
for tool in vector_tools:
|
|
158
184
|
all_tools[tool.name] = tool
|
|
@@ -160,3 +186,123 @@ def register_all_tools(
|
|
|
160
186
|
# Register batch tool if enabled (batch tool is typically always enabled)
|
|
161
187
|
if is_tool_enabled("batch", True):
|
|
162
188
|
register_batch_tool(mcp_server, all_tools)
|
|
189
|
+
|
|
190
|
+
# Register database tools if enabled
|
|
191
|
+
db_manager = None
|
|
192
|
+
database_enabled = {
|
|
193
|
+
"sql_query": is_tool_enabled("sql_query", True),
|
|
194
|
+
"sql_search": is_tool_enabled("sql_search", True),
|
|
195
|
+
"sql_stats": is_tool_enabled("sql_stats", True),
|
|
196
|
+
"graph_add": is_tool_enabled("graph_add", True),
|
|
197
|
+
"graph_remove": is_tool_enabled("graph_remove", True),
|
|
198
|
+
"graph_query": is_tool_enabled("graph_query", True),
|
|
199
|
+
"graph_search": is_tool_enabled("graph_search", True),
|
|
200
|
+
"graph_stats": is_tool_enabled("graph_stats", True),
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if any(database_enabled.values()):
|
|
204
|
+
db_manager = DatabaseManager(permission_manager)
|
|
205
|
+
database_tools = register_database_tools(
|
|
206
|
+
mcp_server,
|
|
207
|
+
permission_manager,
|
|
208
|
+
db_manager=db_manager,
|
|
209
|
+
)
|
|
210
|
+
# Filter based on enabled state
|
|
211
|
+
for tool in database_tools:
|
|
212
|
+
if database_enabled.get(tool.name, True):
|
|
213
|
+
all_tools[tool.name] = tool
|
|
214
|
+
|
|
215
|
+
# Register MCP management tools if enabled
|
|
216
|
+
mcp_enabled = {
|
|
217
|
+
"mcp_add": is_tool_enabled("mcp_add", True),
|
|
218
|
+
"mcp_remove": is_tool_enabled("mcp_remove", True),
|
|
219
|
+
"mcp_stats": is_tool_enabled("mcp_stats", True),
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if mcp_enabled.get("mcp_add", True):
|
|
223
|
+
tool = McpAddTool()
|
|
224
|
+
tool.register(mcp_server)
|
|
225
|
+
all_tools[tool.name] = tool
|
|
226
|
+
|
|
227
|
+
if mcp_enabled.get("mcp_remove", True):
|
|
228
|
+
tool = McpRemoveTool()
|
|
229
|
+
tool.register(mcp_server)
|
|
230
|
+
all_tools[tool.name] = tool
|
|
231
|
+
|
|
232
|
+
if mcp_enabled.get("mcp_stats", True):
|
|
233
|
+
tool = McpStatsTool()
|
|
234
|
+
tool.register(mcp_server)
|
|
235
|
+
all_tools[tool.name] = tool
|
|
236
|
+
|
|
237
|
+
# Register system tools (always enabled)
|
|
238
|
+
# Tool enable/disable tools
|
|
239
|
+
tool_enable = ToolEnableTool()
|
|
240
|
+
tool_enable.register(mcp_server)
|
|
241
|
+
all_tools[tool_enable.name] = tool_enable
|
|
242
|
+
|
|
243
|
+
tool_disable = ToolDisableTool()
|
|
244
|
+
tool_disable.register(mcp_server)
|
|
245
|
+
all_tools[tool_disable.name] = tool_disable
|
|
246
|
+
|
|
247
|
+
tool_list = ToolListTool()
|
|
248
|
+
tool_list.register(mcp_server)
|
|
249
|
+
all_tools[tool_list.name] = tool_list
|
|
250
|
+
|
|
251
|
+
# Stats tool
|
|
252
|
+
stats_tool = StatsTool(db_manager=db_manager)
|
|
253
|
+
stats_tool.register(mcp_server)
|
|
254
|
+
all_tools[stats_tool.name] = stats_tool
|
|
255
|
+
|
|
256
|
+
# Register editor tools if enabled
|
|
257
|
+
editor_enabled = {
|
|
258
|
+
"neovim_edit": is_tool_enabled("neovim_edit", True),
|
|
259
|
+
"neovim_command": is_tool_enabled("neovim_command", True),
|
|
260
|
+
"neovim_session": is_tool_enabled("neovim_session", True),
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if editor_enabled.get("neovim_edit", True):
|
|
264
|
+
tool = NeovimEditTool(permission_manager)
|
|
265
|
+
tool.register(mcp_server)
|
|
266
|
+
all_tools[tool.name] = tool
|
|
267
|
+
|
|
268
|
+
if editor_enabled.get("neovim_command", True):
|
|
269
|
+
tool = NeovimCommandTool(permission_manager)
|
|
270
|
+
tool.register(mcp_server)
|
|
271
|
+
all_tools[tool.name] = tool
|
|
272
|
+
|
|
273
|
+
if editor_enabled.get("neovim_session", True):
|
|
274
|
+
tool = NeovimSessionTool()
|
|
275
|
+
tool.register(mcp_server)
|
|
276
|
+
all_tools[tool.name] = tool
|
|
277
|
+
|
|
278
|
+
# Register LLM tools if enabled
|
|
279
|
+
llm_enabled = {
|
|
280
|
+
"llm": is_tool_enabled("llm", True),
|
|
281
|
+
"consensus": is_tool_enabled("consensus", True),
|
|
282
|
+
"llm_manage": is_tool_enabled("llm_manage", True),
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if llm_enabled.get("llm", True):
|
|
286
|
+
tool = LLMTool()
|
|
287
|
+
if tool.available_providers: # Only register if API keys found
|
|
288
|
+
tool.register(mcp_server)
|
|
289
|
+
all_tools[tool.name] = tool
|
|
290
|
+
|
|
291
|
+
if llm_enabled.get("consensus", True):
|
|
292
|
+
tool = ConsensusTool()
|
|
293
|
+
if tool.llm_tool.available_providers: # Only register if API keys found
|
|
294
|
+
tool.register(mcp_server)
|
|
295
|
+
all_tools[tool.name] = tool
|
|
296
|
+
|
|
297
|
+
if llm_enabled.get("llm_manage", True):
|
|
298
|
+
tool = LLMManageTool()
|
|
299
|
+
tool.register(mcp_server)
|
|
300
|
+
all_tools[tool.name] = tool
|
|
301
|
+
|
|
302
|
+
# Register provider-specific LLM tools
|
|
303
|
+
# These are only registered if their API keys are available
|
|
304
|
+
provider_tools = create_provider_tools()
|
|
305
|
+
for tool in provider_tools:
|
|
306
|
+
if is_tool_enabled(tool.name, True):
|
|
307
|
+
tool.register(mcp_server)
|
|
308
|
+
all_tools[tool.name] = tool
|
hanzo_mcp/tools/common/base.py
CHANGED
|
@@ -170,8 +170,13 @@ class ToolRegistry:
|
|
|
170
170
|
mcp_server: The FastMCP server instance
|
|
171
171
|
tool: The tool to register
|
|
172
172
|
"""
|
|
173
|
-
#
|
|
174
|
-
|
|
173
|
+
# Check if tool is enabled before registering
|
|
174
|
+
# Import here to avoid circular imports
|
|
175
|
+
from hanzo_mcp.tools.common.tool_enable import ToolEnableTool
|
|
176
|
+
|
|
177
|
+
if ToolEnableTool.is_tool_enabled(tool.name):
|
|
178
|
+
# Use the tool's register method which handles all the details
|
|
179
|
+
tool.register(mcp_server)
|
|
175
180
|
|
|
176
181
|
@staticmethod
|
|
177
182
|
def register_tools(mcp_server: FastMCP, tools: list[BaseTool]) -> None:
|