hanzo-mcp 0.5.1__py3-none-any.whl β 0.6.1__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/cli.py +32 -0
- hanzo_mcp/dev_server.py +246 -0
- hanzo_mcp/prompts/__init__.py +1 -1
- hanzo_mcp/prompts/project_system.py +43 -7
- hanzo_mcp/server.py +5 -1
- hanzo_mcp/tools/__init__.py +168 -6
- hanzo_mcp/tools/agent/__init__.py +1 -1
- hanzo_mcp/tools/agent/agent.py +401 -0
- hanzo_mcp/tools/agent/agent_tool.py +3 -4
- hanzo_mcp/tools/common/__init__.py +1 -1
- hanzo_mcp/tools/common/base.py +9 -4
- hanzo_mcp/tools/common/batch_tool.py +3 -5
- hanzo_mcp/tools/common/config_tool.py +1 -1
- hanzo_mcp/tools/common/context.py +1 -1
- hanzo_mcp/tools/common/palette.py +344 -0
- hanzo_mcp/tools/common/palette_loader.py +108 -0
- hanzo_mcp/tools/common/stats.py +261 -0
- hanzo_mcp/tools/common/thinking_tool.py +3 -5
- 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 +260 -0
- hanzo_mcp/tools/config/__init__.py +10 -0
- hanzo_mcp/tools/config/config_tool.py +212 -0
- hanzo_mcp/tools/config/index_config.py +176 -0
- hanzo_mcp/tools/config/palette_tool.py +166 -0
- hanzo_mcp/tools/database/__init__.py +71 -0
- hanzo_mcp/tools/database/database_manager.py +246 -0
- hanzo_mcp/tools/database/graph.py +482 -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.py +411 -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 +52 -13
- hanzo_mcp/tools/filesystem/base.py +1 -1
- hanzo_mcp/tools/filesystem/batch_search.py +812 -0
- hanzo_mcp/tools/filesystem/content_replace.py +3 -5
- hanzo_mcp/tools/filesystem/diff.py +193 -0
- hanzo_mcp/tools/filesystem/directory_tree.py +3 -5
- hanzo_mcp/tools/filesystem/edit.py +3 -5
- hanzo_mcp/tools/filesystem/find.py +443 -0
- hanzo_mcp/tools/filesystem/find_files.py +348 -0
- hanzo_mcp/tools/filesystem/git_search.py +505 -0
- hanzo_mcp/tools/filesystem/grep.py +2 -2
- hanzo_mcp/tools/filesystem/multi_edit.py +3 -5
- hanzo_mcp/tools/filesystem/read.py +17 -5
- hanzo_mcp/tools/filesystem/{grep_ast_tool.py β symbols.py} +17 -27
- hanzo_mcp/tools/filesystem/symbols_unified.py +376 -0
- hanzo_mcp/tools/filesystem/tree.py +268 -0
- hanzo_mcp/tools/filesystem/unified_search.py +465 -443
- hanzo_mcp/tools/filesystem/unix_aliases.py +99 -0
- hanzo_mcp/tools/filesystem/watch.py +174 -0
- hanzo_mcp/tools/filesystem/write.py +3 -5
- hanzo_mcp/tools/jupyter/__init__.py +9 -12
- hanzo_mcp/tools/jupyter/base.py +1 -1
- hanzo_mcp/tools/jupyter/jupyter.py +326 -0
- hanzo_mcp/tools/jupyter/notebook_edit.py +3 -4
- hanzo_mcp/tools/jupyter/notebook_read.py +3 -5
- hanzo_mcp/tools/llm/__init__.py +31 -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/llm_unified.py +851 -0
- hanzo_mcp/tools/llm/provider_tools.py +412 -0
- hanzo_mcp/tools/mcp/__init__.py +15 -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/mcp/mcp_unified.py +503 -0
- hanzo_mcp/tools/shell/__init__.py +21 -23
- hanzo_mcp/tools/shell/base.py +1 -1
- hanzo_mcp/tools/shell/base_process.py +303 -0
- hanzo_mcp/tools/shell/bash_unified.py +134 -0
- 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/npx_unified.py +101 -0
- hanzo_mcp/tools/shell/open.py +107 -0
- hanzo_mcp/tools/shell/pkill.py +262 -0
- hanzo_mcp/tools/shell/process_unified.py +131 -0
- hanzo_mcp/tools/shell/processes.py +279 -0
- hanzo_mcp/tools/shell/run_background.py +326 -0
- hanzo_mcp/tools/shell/run_command.py +3 -4
- hanzo_mcp/tools/shell/run_command_windows.py +3 -4
- hanzo_mcp/tools/shell/uvx.py +187 -0
- hanzo_mcp/tools/shell/uvx_background.py +249 -0
- hanzo_mcp/tools/shell/uvx_unified.py +101 -0
- hanzo_mcp/tools/todo/__init__.py +1 -1
- hanzo_mcp/tools/todo/base.py +1 -1
- hanzo_mcp/tools/todo/todo.py +265 -0
- hanzo_mcp/tools/todo/todo_read.py +3 -5
- hanzo_mcp/tools/todo/todo_write.py +3 -5
- hanzo_mcp/tools/vector/__init__.py +6 -1
- hanzo_mcp/tools/vector/git_ingester.py +3 -0
- hanzo_mcp/tools/vector/index_tool.py +358 -0
- hanzo_mcp/tools/vector/infinity_store.py +98 -0
- hanzo_mcp/tools/vector/project_manager.py +27 -5
- hanzo_mcp/tools/vector/vector.py +311 -0
- hanzo_mcp/tools/vector/vector_index.py +1 -1
- hanzo_mcp/tools/vector/vector_search.py +12 -7
- hanzo_mcp-0.6.1.dist-info/METADATA +336 -0
- hanzo_mcp-0.6.1.dist-info/RECORD +134 -0
- hanzo_mcp-0.6.1.dist-info/entry_points.txt +3 -0
- hanzo_mcp-0.5.1.dist-info/METADATA +0 -276
- hanzo_mcp-0.5.1.dist-info/RECORD +0 -68
- hanzo_mcp-0.5.1.dist-info/entry_points.txt +0 -2
- {hanzo_mcp-0.5.1.dist-info β hanzo_mcp-0.6.1.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.5.1.dist-info β hanzo_mcp-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {hanzo_mcp-0.5.1.dist-info β hanzo_mcp-0.6.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""Unified vector store tool."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated, TypedDict, Unpack, final, override, Optional, List, Dict, Any
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from mcp.server.fastmcp import Context as MCPContext
|
|
7
|
+
from pydantic import Field
|
|
8
|
+
|
|
9
|
+
from hanzo_mcp.tools.common.base import BaseTool
|
|
10
|
+
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
11
|
+
from hanzo_mcp.tools.vector.project_manager import ProjectVectorManager
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Parameter types
|
|
15
|
+
Action = Annotated[
|
|
16
|
+
str,
|
|
17
|
+
Field(
|
|
18
|
+
description="Action: search (default), index, stats, clear",
|
|
19
|
+
default="search",
|
|
20
|
+
),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
Query = Annotated[
|
|
24
|
+
Optional[str],
|
|
25
|
+
Field(
|
|
26
|
+
description="Search query for semantic similarity",
|
|
27
|
+
default=None,
|
|
28
|
+
),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
Path = Annotated[
|
|
32
|
+
Optional[str],
|
|
33
|
+
Field(
|
|
34
|
+
description="Path to index or search within",
|
|
35
|
+
default=".",
|
|
36
|
+
),
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
Include = Annotated[
|
|
40
|
+
Optional[str],
|
|
41
|
+
Field(
|
|
42
|
+
description="File pattern to include (e.g., '*.py')",
|
|
43
|
+
default=None,
|
|
44
|
+
),
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
Exclude = Annotated[
|
|
48
|
+
Optional[str],
|
|
49
|
+
Field(
|
|
50
|
+
description="File pattern to exclude",
|
|
51
|
+
default=None,
|
|
52
|
+
),
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
Limit = Annotated[
|
|
56
|
+
int,
|
|
57
|
+
Field(
|
|
58
|
+
description="Maximum results to return",
|
|
59
|
+
default=10,
|
|
60
|
+
),
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
IncludeGit = Annotated[
|
|
64
|
+
bool,
|
|
65
|
+
Field(
|
|
66
|
+
description="Include git history in indexing",
|
|
67
|
+
default=True,
|
|
68
|
+
),
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
ForceReindex = Annotated[
|
|
72
|
+
bool,
|
|
73
|
+
Field(
|
|
74
|
+
description="Force reindexing even if up to date",
|
|
75
|
+
default=False,
|
|
76
|
+
),
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class VectorParams(TypedDict, total=False):
|
|
81
|
+
"""Parameters for vector tool."""
|
|
82
|
+
action: str
|
|
83
|
+
query: Optional[str]
|
|
84
|
+
path: Optional[str]
|
|
85
|
+
include: Optional[str]
|
|
86
|
+
exclude: Optional[str]
|
|
87
|
+
limit: int
|
|
88
|
+
include_git: bool
|
|
89
|
+
force_reindex: bool
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@final
|
|
93
|
+
class VectorTool(BaseTool):
|
|
94
|
+
"""Unified vector store tool for semantic search."""
|
|
95
|
+
|
|
96
|
+
def __init__(self, permission_manager: PermissionManager, project_manager: ProjectVectorManager):
|
|
97
|
+
"""Initialize the vector tool."""
|
|
98
|
+
super().__init__(permission_manager)
|
|
99
|
+
self.project_manager = project_manager
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
@override
|
|
103
|
+
def name(self) -> str:
|
|
104
|
+
"""Get the tool name."""
|
|
105
|
+
return "vector"
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
@override
|
|
109
|
+
def description(self) -> str:
|
|
110
|
+
"""Get the tool description."""
|
|
111
|
+
return """Semantic search with embeddings. Actions: search (default), index, stats, clear.
|
|
112
|
+
|
|
113
|
+
Usage:
|
|
114
|
+
vector "find authentication logic"
|
|
115
|
+
vector --action index --path ./src --include "*.py"
|
|
116
|
+
vector --action stats
|
|
117
|
+
vector --action clear --path ./old_code
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
@override
|
|
121
|
+
async def call(
|
|
122
|
+
self,
|
|
123
|
+
ctx: MCPContext,
|
|
124
|
+
**params: Unpack[VectorParams],
|
|
125
|
+
) -> str:
|
|
126
|
+
"""Execute vector operation."""
|
|
127
|
+
tool_ctx = self.create_tool_context(ctx)
|
|
128
|
+
|
|
129
|
+
# Extract action
|
|
130
|
+
action = params.get("action", "search")
|
|
131
|
+
|
|
132
|
+
# Route to appropriate handler
|
|
133
|
+
if action == "search":
|
|
134
|
+
return await self._handle_search(params, tool_ctx)
|
|
135
|
+
elif action == "index":
|
|
136
|
+
return await self._handle_index(params, tool_ctx)
|
|
137
|
+
elif action == "stats":
|
|
138
|
+
return await self._handle_stats(params, tool_ctx)
|
|
139
|
+
elif action == "clear":
|
|
140
|
+
return await self._handle_clear(params, tool_ctx)
|
|
141
|
+
else:
|
|
142
|
+
return f"Error: Unknown action '{action}'. Valid actions: search, index, stats, clear"
|
|
143
|
+
|
|
144
|
+
async def _handle_search(self, params: Dict[str, Any], tool_ctx) -> str:
|
|
145
|
+
"""Handle semantic search."""
|
|
146
|
+
query = params.get("query")
|
|
147
|
+
if not query:
|
|
148
|
+
return "Error: query is required for search action"
|
|
149
|
+
|
|
150
|
+
path = params.get("path", ".")
|
|
151
|
+
limit = params.get("limit", 10)
|
|
152
|
+
|
|
153
|
+
# Validate path
|
|
154
|
+
allowed, error_msg = await self.check_path_allowed(path, tool_ctx)
|
|
155
|
+
if not allowed:
|
|
156
|
+
return error_msg
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
# Determine search scope
|
|
160
|
+
project = self.project_manager.get_project_for_path(path)
|
|
161
|
+
if not project:
|
|
162
|
+
return "Error: No indexed project found for this path. Run 'vector --action index' first."
|
|
163
|
+
|
|
164
|
+
# Search
|
|
165
|
+
await tool_ctx.info(f"Searching for: {query}")
|
|
166
|
+
results = project.search(query, k=limit)
|
|
167
|
+
|
|
168
|
+
if not results:
|
|
169
|
+
return f"No results found for: {query}"
|
|
170
|
+
|
|
171
|
+
# Format results
|
|
172
|
+
output = [f"=== Vector Search Results for '{query}' ==="]
|
|
173
|
+
output.append(f"Found {len(results)} matches\n")
|
|
174
|
+
|
|
175
|
+
for i, result in enumerate(results, 1):
|
|
176
|
+
score = result.get("score", 0)
|
|
177
|
+
file_path = result.get("file_path", "unknown")
|
|
178
|
+
content = result.get("content", "")
|
|
179
|
+
chunk_type = result.get("metadata", {}).get("type", "content")
|
|
180
|
+
|
|
181
|
+
output.append(f"Result {i} - Score: {score:.1%}")
|
|
182
|
+
output.append(f"File: {file_path}")
|
|
183
|
+
if chunk_type != "content":
|
|
184
|
+
output.append(f"Type: {chunk_type}")
|
|
185
|
+
output.append("-" * 60)
|
|
186
|
+
|
|
187
|
+
# Truncate content if too long
|
|
188
|
+
if len(content) > 300:
|
|
189
|
+
content = content[:300] + "..."
|
|
190
|
+
output.append(content)
|
|
191
|
+
output.append("")
|
|
192
|
+
|
|
193
|
+
return "\n".join(output)
|
|
194
|
+
|
|
195
|
+
except Exception as e:
|
|
196
|
+
await tool_ctx.error(f"Search failed: {str(e)}")
|
|
197
|
+
return f"Error during search: {str(e)}"
|
|
198
|
+
|
|
199
|
+
async def _handle_index(self, params: Dict[str, Any], tool_ctx) -> str:
|
|
200
|
+
"""Handle indexing files."""
|
|
201
|
+
path = params.get("path", ".")
|
|
202
|
+
include = params.get("include")
|
|
203
|
+
exclude = params.get("exclude")
|
|
204
|
+
include_git = params.get("include_git", True)
|
|
205
|
+
force = params.get("force_reindex", False)
|
|
206
|
+
|
|
207
|
+
# Validate path
|
|
208
|
+
allowed, error_msg = await self.check_path_allowed(path, tool_ctx)
|
|
209
|
+
if not allowed:
|
|
210
|
+
return error_msg
|
|
211
|
+
|
|
212
|
+
try:
|
|
213
|
+
await tool_ctx.info(f"Indexing {path}...")
|
|
214
|
+
|
|
215
|
+
# Get or create project
|
|
216
|
+
project = self.project_manager.get_or_create_project(path)
|
|
217
|
+
|
|
218
|
+
# Index files
|
|
219
|
+
stats = await project.index_directory(
|
|
220
|
+
path,
|
|
221
|
+
include_pattern=include,
|
|
222
|
+
exclude_pattern=exclude,
|
|
223
|
+
force_reindex=force
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# Index git history if requested
|
|
227
|
+
if include_git and Path(path).joinpath(".git").exists():
|
|
228
|
+
await tool_ctx.info("Indexing git history...")
|
|
229
|
+
git_stats = await project.index_git_history(path)
|
|
230
|
+
stats["git_commits"] = git_stats.get("commits_indexed", 0)
|
|
231
|
+
|
|
232
|
+
# Format output
|
|
233
|
+
output = [f"=== Indexing Complete ==="]
|
|
234
|
+
output.append(f"Path: {path}")
|
|
235
|
+
output.append(f"Files indexed: {stats.get('files_indexed', 0)}")
|
|
236
|
+
output.append(f"Chunks created: {stats.get('chunks_created', 0)}")
|
|
237
|
+
if stats.get("git_commits"):
|
|
238
|
+
output.append(f"Git commits indexed: {stats['git_commits']}")
|
|
239
|
+
output.append(f"Total documents: {project.get_stats().get('total_documents', 0)}")
|
|
240
|
+
|
|
241
|
+
return "\n".join(output)
|
|
242
|
+
|
|
243
|
+
except Exception as e:
|
|
244
|
+
await tool_ctx.error(f"Indexing failed: {str(e)}")
|
|
245
|
+
return f"Error during indexing: {str(e)}"
|
|
246
|
+
|
|
247
|
+
async def _handle_stats(self, params: Dict[str, Any], tool_ctx) -> str:
|
|
248
|
+
"""Get vector store statistics."""
|
|
249
|
+
path = params.get("path")
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
if path:
|
|
253
|
+
# Stats for specific project
|
|
254
|
+
project = self.project_manager.get_project_for_path(path)
|
|
255
|
+
if not project:
|
|
256
|
+
return f"No indexed project found for path: {path}"
|
|
257
|
+
|
|
258
|
+
stats = project.get_stats()
|
|
259
|
+
output = [f"=== Vector Store Stats for {project.name} ==="]
|
|
260
|
+
else:
|
|
261
|
+
# Global stats
|
|
262
|
+
stats = self.project_manager.get_global_stats()
|
|
263
|
+
output = ["=== Global Vector Store Stats ==="]
|
|
264
|
+
|
|
265
|
+
output.append(f"Total documents: {stats.get('total_documents', 0)}")
|
|
266
|
+
output.append(f"Total size: {stats.get('total_size_mb', 0):.1f} MB")
|
|
267
|
+
|
|
268
|
+
if stats.get("projects"):
|
|
269
|
+
output.append(f"\nProjects indexed: {len(stats['projects'])}")
|
|
270
|
+
for proj in stats["projects"]:
|
|
271
|
+
output.append(f" - {proj['name']}: {proj['documents']} docs, {proj['size_mb']:.1f} MB")
|
|
272
|
+
|
|
273
|
+
return "\n".join(output)
|
|
274
|
+
|
|
275
|
+
except Exception as e:
|
|
276
|
+
await tool_ctx.error(f"Failed to get stats: {str(e)}")
|
|
277
|
+
return f"Error getting stats: {str(e)}"
|
|
278
|
+
|
|
279
|
+
async def _handle_clear(self, params: Dict[str, Any], tool_ctx) -> str:
|
|
280
|
+
"""Clear vector store."""
|
|
281
|
+
path = params.get("path")
|
|
282
|
+
|
|
283
|
+
if not path:
|
|
284
|
+
return "Error: path is required for clear action"
|
|
285
|
+
|
|
286
|
+
# Validate path
|
|
287
|
+
allowed, error_msg = await self.check_path_allowed(path, tool_ctx)
|
|
288
|
+
if not allowed:
|
|
289
|
+
return error_msg
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
project = self.project_manager.get_project_for_path(path)
|
|
293
|
+
if not project:
|
|
294
|
+
return f"No indexed project found for path: {path}"
|
|
295
|
+
|
|
296
|
+
# Get stats before clearing
|
|
297
|
+
stats = project.get_stats()
|
|
298
|
+
doc_count = stats.get("total_documents", 0)
|
|
299
|
+
|
|
300
|
+
# Clear
|
|
301
|
+
project.clear()
|
|
302
|
+
|
|
303
|
+
return f"Cleared {doc_count} documents from vector store for {project.name}"
|
|
304
|
+
|
|
305
|
+
except Exception as e:
|
|
306
|
+
await tool_ctx.error(f"Failed to clear: {str(e)}")
|
|
307
|
+
return f"Error clearing vector store: {str(e)}"
|
|
308
|
+
|
|
309
|
+
def register(self, mcp_server) -> None:
|
|
310
|
+
"""Register this tool with the MCP server."""
|
|
311
|
+
pass
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from typing import Dict, List, Optional, TypedDict, Unpack, final
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
-
from fastmcp import Context as MCPContext
|
|
6
|
+
from mcp.server.fastmcp import Context as MCPContext
|
|
7
7
|
from pydantic import Field
|
|
8
8
|
|
|
9
9
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
@@ -4,7 +4,7 @@ from typing import Dict, List, Optional, TypedDict, Unpack, final
|
|
|
4
4
|
import json
|
|
5
5
|
import asyncio
|
|
6
6
|
|
|
7
|
-
from fastmcp import Context as MCPContext
|
|
7
|
+
from mcp.server.fastmcp import Context as MCPContext
|
|
8
8
|
from pydantic import Field
|
|
9
9
|
|
|
10
10
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
@@ -48,13 +48,18 @@ class VectorSearchTool(BaseTool):
|
|
|
48
48
|
@property
|
|
49
49
|
def description(self) -> str:
|
|
50
50
|
"""Get the tool description."""
|
|
51
|
-
return """
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
return """Pure semantic/vector search using Infinity embedded database.
|
|
52
|
+
|
|
53
|
+
Searches indexed documents using vector embeddings to find semantically similar content.
|
|
54
|
+
This is NOT keyword search - it finds documents based on meaning and context similarity.
|
|
55
|
+
|
|
56
|
+
Features:
|
|
57
|
+
- Searches across project-specific vector databases
|
|
58
|
+
- Returns similarity scores (0-1, higher is better)
|
|
59
|
+
- Supports filtering by project or file
|
|
60
|
+
- Automatically detects projects via LLM.md files
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
Use 'grep' for exact text/pattern matching, 'vector_search' for semantic similarity."""
|
|
58
63
|
|
|
59
64
|
async def call(
|
|
60
65
|
self,
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hanzo-mcp
|
|
3
|
+
Version: 0.6.1
|
|
4
|
+
Summary: The Zen of Hanzo MCP: One server to rule them all. The ultimate MCP that orchestrates all others.
|
|
5
|
+
Author-email: Hanzo Industries Inc <dev@hanzo.ai>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/hanzoai/mcp
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/hanzoai/mcp/issues
|
|
9
|
+
Project-URL: Documentation, https://mcp.hanzo.ai
|
|
10
|
+
Keywords: mcp,claude,hanzo,code,agent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: mcp>=1.6.0
|
|
18
|
+
Requires-Dist: fastmcp>=2.8.0
|
|
19
|
+
Requires-Dist: httpx>=0.27.0
|
|
20
|
+
Requires-Dist: uvicorn>=0.23.1
|
|
21
|
+
Requires-Dist: openai>=1.50.0
|
|
22
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
23
|
+
Requires-Dist: litellm>=1.40.14
|
|
24
|
+
Requires-Dist: grep-ast>=0.8.1
|
|
25
|
+
Requires-Dist: bashlex>=0.18
|
|
26
|
+
Requires-Dist: libtmux>=0.39.0
|
|
27
|
+
Requires-Dist: nbformat>=5.10.4
|
|
28
|
+
Requires-Dist: psutil>=6.1.0
|
|
29
|
+
Requires-Dist: pydantic>=2.10.0
|
|
30
|
+
Requires-Dist: typing-extensions>=4.12.2
|
|
31
|
+
Requires-Dist: watchdog>=3.0.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
36
|
+
Requires-Dist: black>=23.3.0; extra == "dev"
|
|
37
|
+
Requires-Dist: sphinx>=8.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: sphinx-rtd-theme>=3.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: myst-parser>=4.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: sphinx-copybutton>=0.5.0; extra == "dev"
|
|
41
|
+
Provides-Extra: docs
|
|
42
|
+
Requires-Dist: sphinx>=8.0.0; extra == "docs"
|
|
43
|
+
Requires-Dist: sphinx-rtd-theme>=3.0.0; extra == "docs"
|
|
44
|
+
Requires-Dist: myst-parser>=4.0.0; extra == "docs"
|
|
45
|
+
Requires-Dist: sphinx-copybutton>=0.5.0; extra == "docs"
|
|
46
|
+
Provides-Extra: test
|
|
47
|
+
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
48
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "test"
|
|
49
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "test"
|
|
50
|
+
Requires-Dist: pytest-asyncio>=0.25.3; extra == "test"
|
|
51
|
+
Requires-Dist: twisted; extra == "test"
|
|
52
|
+
Provides-Extra: performance
|
|
53
|
+
Requires-Dist: ujson>=5.7.0; extra == "performance"
|
|
54
|
+
Requires-Dist: orjson>=3.9.0; extra == "performance"
|
|
55
|
+
Provides-Extra: publish
|
|
56
|
+
Requires-Dist: twine>=4.0.2; extra == "publish"
|
|
57
|
+
Requires-Dist: build>=1.0.3; extra == "publish"
|
|
58
|
+
Dynamic: license-file
|
|
59
|
+
|
|
60
|
+
# Hanzo MCP - The Zen of Model Context Protocol
|
|
61
|
+
|
|
62
|
+
[](https://mcp.hanzo.ai)
|
|
63
|
+
[](https://pypi.org/project/hanzo-mcp/)
|
|
64
|
+
[](https://github.com/hanzoai/mcp/blob/main/LICENSE)
|
|
65
|
+
[](https://discord.gg/hanzoai)
|
|
66
|
+
|
|
67
|
+
## π₯· One MCP to Rule Them All
|
|
68
|
+
|
|
69
|
+
**Start here. Add other MCPs later. Control everything through one opinionated interface.**
|
|
70
|
+
|
|
71
|
+
Hanzo MCP isn't just another Model Context Protocol serverβit's **THE** MCP server. While others give you fragments, we give you the complete toolkit. One server that orchestrates all others, with the power to add, remove, and control any MCP server dynamically.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Install and rule your development world
|
|
75
|
+
uvx hanzo-mcp
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## π― Why Hanzo MCP?
|
|
79
|
+
|
|
80
|
+
### The Problem with Other MCPs
|
|
81
|
+
- **Fragmented Experience**: Install 10 different MCPs for 10 different tasks
|
|
82
|
+
- **Inconsistent Interfaces**: Each MCP has its own conventions and quirks
|
|
83
|
+
- **Limited Scope**: Most MCPs do one thing, leaving you to juggle multiple servers
|
|
84
|
+
- **No Orchestration**: No way to coordinate between different MCP servers
|
|
85
|
+
|
|
86
|
+
### The Hanzo Way
|
|
87
|
+
- **One Installation**: 65+ professional tools out of the box
|
|
88
|
+
- **Unified Philosophy**: Consistent, opinionated interface following Unix principles
|
|
89
|
+
- **MCP Orchestration**: Install and control other MCP servers through Hanzo
|
|
90
|
+
- **Swappable Opinions**: Don't like our way? Load a different palette and change everything
|
|
91
|
+
|
|
92
|
+
## π Features That Set Us Apart
|
|
93
|
+
|
|
94
|
+
### π¨ Palette System - Opinions Are Just Configurations
|
|
95
|
+
```python
|
|
96
|
+
# Don't like our shell tools? Swap the palette
|
|
97
|
+
palette_load(palette="minimal") # Just the essentials
|
|
98
|
+
palette_load(palette="pentesting") # Security focused tools
|
|
99
|
+
palette_load(palette="data-science") # Jupyter, pandas, numpy focused
|
|
100
|
+
palette_load(palette="your-custom") # Your tools, your way
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### π MCP Server Orchestration
|
|
104
|
+
```python
|
|
105
|
+
# Add any MCP server dynamically
|
|
106
|
+
mcp_add(url="github.com/someone/their-mcp", alias="their")
|
|
107
|
+
|
|
108
|
+
# Use their tools through our unified interface
|
|
109
|
+
their_tool(action="whatever", params=...)
|
|
110
|
+
|
|
111
|
+
# Remove when done
|
|
112
|
+
mcp_remove(alias="their")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### π οΈ 65+ Battle-Tested Tools
|
|
116
|
+
|
|
117
|
+
#### Intelligent Multi-Modal Search
|
|
118
|
+
- **search**: Combines grep, AST analysis, vector embeddings, and git history
|
|
119
|
+
- **symbols**: Find any code symbol across languages instantly
|
|
120
|
+
- **git_search**: Search through git history, branches, and commits
|
|
121
|
+
|
|
122
|
+
#### Advanced Development
|
|
123
|
+
- **agent**: Delegate complex tasks to specialized AI agents
|
|
124
|
+
- **llm**: Query multiple LLM providers with consensus
|
|
125
|
+
- **jupyter**: Full Jupyter notebook support
|
|
126
|
+
- **neovim**: Integrated Neovim for power users
|
|
127
|
+
|
|
128
|
+
#### File Operations That Just Work
|
|
129
|
+
- **edit/multi_edit**: Intelligent pattern-based editing
|
|
130
|
+
- **read/write**: Automatic encoding detection
|
|
131
|
+
- **tree**: Visual directory structures
|
|
132
|
+
- **watch**: Monitor file changes in real-time
|
|
133
|
+
|
|
134
|
+
#### Process & System Control
|
|
135
|
+
- **run_command**: Secure command execution with timeout
|
|
136
|
+
- **processes**: Monitor and manage system processes
|
|
137
|
+
- **npx/uvx**: Package runners with background support
|
|
138
|
+
|
|
139
|
+
#### And So Much More
|
|
140
|
+
- Database tools (SQL, Graph)
|
|
141
|
+
- Vector search and indexing
|
|
142
|
+
- Todo management
|
|
143
|
+
- Configuration management
|
|
144
|
+
- MCP server management
|
|
145
|
+
- Statistical analysis
|
|
146
|
+
- Batch operations
|
|
147
|
+
|
|
148
|
+
## π― The Zen of Hanzo
|
|
149
|
+
|
|
150
|
+
1. **One Tool, One Purpose** - Each tool does one thing exceptionally well
|
|
151
|
+
2. **Actions Over Tools** - Complex tools support multiple actions, not multiple interfaces
|
|
152
|
+
3. **Parallel by Default** - Run multiple operations concurrently
|
|
153
|
+
4. **Smart Fallbacks** - Automatically choose the best available backend
|
|
154
|
+
5. **Secure by Design** - Fine-grained permissions and audit trails
|
|
155
|
+
6. **Opinionated but Flexible** - Strong defaults with palette customization
|
|
156
|
+
|
|
157
|
+
## π Quick Start
|
|
158
|
+
|
|
159
|
+
### Installation
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Install globally with uvx (recommended)
|
|
163
|
+
uvx hanzo-mcp
|
|
164
|
+
|
|
165
|
+
# Or install with pip
|
|
166
|
+
pip install hanzo-mcp
|
|
167
|
+
|
|
168
|
+
# Or install from source for development
|
|
169
|
+
git clone https://github.com/hanzoai/mcp
|
|
170
|
+
cd mcp
|
|
171
|
+
make install
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Add to Claude Desktop
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# Automatic installation
|
|
178
|
+
make install-desktop
|
|
179
|
+
|
|
180
|
+
# Or manual configuration
|
|
181
|
+
cat >> ~/Library/Application\ Support/Claude/claude_desktop_config.json << 'EOF'
|
|
182
|
+
{
|
|
183
|
+
"mcpServers": {
|
|
184
|
+
"hanzo": {
|
|
185
|
+
"command": "uvx",
|
|
186
|
+
"args": ["hanzo-mcp"]
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
EOF
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Your First Session
|
|
194
|
+
|
|
195
|
+
1. Open Claude Desktop
|
|
196
|
+
2. Start with `search` to explore any codebase
|
|
197
|
+
3. Use `tree` to understand structure
|
|
198
|
+
4. Edit files with `edit` or `multi_edit`
|
|
199
|
+
5. Run commands with `run_command`
|
|
200
|
+
6. Add other MCP servers with `mcp_add`
|
|
201
|
+
|
|
202
|
+
## π¨ Palette System
|
|
203
|
+
|
|
204
|
+
Palettes let you completely transform Hanzo MCP's behavior:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
# List available palettes
|
|
208
|
+
palette_list()
|
|
209
|
+
|
|
210
|
+
# Load a different personality
|
|
211
|
+
palette_load(palette="minimal") # Just core tools
|
|
212
|
+
palette_load(palette="academic") # Research and writing focused
|
|
213
|
+
palette_load(palette="devops") # Infrastructure and deployment
|
|
214
|
+
|
|
215
|
+
# Create your own
|
|
216
|
+
palette_create(
|
|
217
|
+
name="my-workflow",
|
|
218
|
+
tools=["read", "write", "edit", "search", "my-custom-tool"],
|
|
219
|
+
config={"editor": "vim", "search_backend": "ripgrep"}
|
|
220
|
+
)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## π MCP Orchestration
|
|
224
|
+
|
|
225
|
+
Hanzo MCP can manage other MCP servers:
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
# Add any MCP server
|
|
229
|
+
mcp_add(url="github.com/modelcontextprotocol/servers/tree/main/postgres")
|
|
230
|
+
|
|
231
|
+
# List installed servers
|
|
232
|
+
mcp_stats()
|
|
233
|
+
|
|
234
|
+
# Use tools from other servers seamlessly
|
|
235
|
+
postgres_query(query="SELECT * FROM users")
|
|
236
|
+
|
|
237
|
+
# Remove when done
|
|
238
|
+
mcp_remove(alias="postgres")
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## π Advanced Features
|
|
242
|
+
|
|
243
|
+
### Intelligent Search
|
|
244
|
+
```python
|
|
245
|
+
# Multi-modal search across your codebase
|
|
246
|
+
results = search(
|
|
247
|
+
query="authentication",
|
|
248
|
+
include_git=True, # Search git history
|
|
249
|
+
include_vector=True, # Semantic search
|
|
250
|
+
include_ast=True, # AST symbol search
|
|
251
|
+
parallel=True # Search all modes concurrently
|
|
252
|
+
)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Agent Orchestration
|
|
256
|
+
```python
|
|
257
|
+
# Delegate complex tasks to specialized agents
|
|
258
|
+
agent(
|
|
259
|
+
task="Refactor this codebase to use async/await",
|
|
260
|
+
files=["src/**/*.py"],
|
|
261
|
+
instructions="Maintain backwards compatibility"
|
|
262
|
+
)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Consensus LLM Queries
|
|
266
|
+
```python
|
|
267
|
+
# Query multiple LLMs and get consensus
|
|
268
|
+
llm(
|
|
269
|
+
action="consensus",
|
|
270
|
+
prompt="Is this code secure?",
|
|
271
|
+
providers=["openai", "anthropic", "google"],
|
|
272
|
+
threshold=0.8
|
|
273
|
+
)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## ποΈ Architecture
|
|
277
|
+
|
|
278
|
+
Built on modern Python with:
|
|
279
|
+
- **FastMCP**: High-performance MCP framework
|
|
280
|
+
- **UV**: Lightning-fast Python package management
|
|
281
|
+
- **Parallel Execution**: Concurrent operations by default
|
|
282
|
+
- **Smart Backends**: Automatic selection of best available tools
|
|
283
|
+
- **Type Safety**: Full type hints and validation
|
|
284
|
+
|
|
285
|
+
## π€ Contributing
|
|
286
|
+
|
|
287
|
+
We welcome contributions! The codebase is designed for extensibility:
|
|
288
|
+
|
|
289
|
+
1. **Add a Tool**: Drop a file in `hanzo_mcp/tools/`
|
|
290
|
+
2. **Create a Palette**: Define tool collections and configurations
|
|
291
|
+
3. **Improve Existing Tools**: Each tool is independently testable
|
|
292
|
+
|
|
293
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
294
|
+
|
|
295
|
+
## π Documentation
|
|
296
|
+
|
|
297
|
+
- **[Quick Start Guide](https://mcp.hanzo.ai/quickstart)** - Get running in 5 minutes
|
|
298
|
+
- **[Tool Reference](https://mcp.hanzo.ai/tools)** - Detailed documentation for all 65+ tools
|
|
299
|
+
- **[Palette System](https://mcp.hanzo.ai/palettes)** - Customize your experience
|
|
300
|
+
- **[MCP Orchestration](https://mcp.hanzo.ai/orchestration)** - Control other MCP servers
|
|
301
|
+
- **[Best Practices](https://mcp.hanzo.ai/best-practices)** - Tips from power users
|
|
302
|
+
|
|
303
|
+
## π Why Developers Choose Hanzo MCP
|
|
304
|
+
|
|
305
|
+
> "I replaced 12 different MCP servers with just Hanzo. The palette system means I can switch contexts instantlyβfrom web dev to data science to DevOps." - *Power User*
|
|
306
|
+
|
|
307
|
+
> "The agent orchestration is incredible. I can delegate entire refactoring tasks and it just works." - *Sr. Engineer*
|
|
308
|
+
|
|
309
|
+
> "Finally, an MCP that thinks like a developer. Smart defaults, great errors, and everything is parallel." - *Tech Lead*
|
|
310
|
+
|
|
311
|
+
## π Stats
|
|
312
|
+
|
|
313
|
+
- **65+** Professional Tools
|
|
314
|
+
- **10x** Faster than installing multiple MCPs
|
|
315
|
+
- **1** Unified interface to rule them all
|
|
316
|
+
- **β** Possibilities with the palette system
|
|
317
|
+
|
|
318
|
+
## π License
|
|
319
|
+
|
|
320
|
+
MIT - Use it, extend it, make it yours.
|
|
321
|
+
|
|
322
|
+
## π Links
|
|
323
|
+
|
|
324
|
+
- [GitHub](https://github.com/hanzoai/mcp)
|
|
325
|
+
- [Documentation](https://mcp.hanzo.ai)
|
|
326
|
+
- [PyPI](https://pypi.org/project/hanzo-mcp/)
|
|
327
|
+
- [Discord Community](https://discord.gg/hanzoai)
|
|
328
|
+
- [Report Issues](https://github.com/hanzoai/mcp/issues)
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
<p align="center">
|
|
333
|
+
<b>The Zen of Hanzo MCP</b><br>
|
|
334
|
+
<i>One server. All tools. Your way.</i><br><br>
|
|
335
|
+
<code>uvx hanzo-mcp</code>
|
|
336
|
+
</p>
|