hanzo-mcp 0.8.11__py3-none-any.whl → 0.9.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 (166) hide show
  1. hanzo_mcp/__init__.py +1 -3
  2. hanzo_mcp/analytics/posthog_analytics.py +3 -9
  3. hanzo_mcp/bridge.py +9 -25
  4. hanzo_mcp/cli.py +6 -15
  5. hanzo_mcp/cli_enhanced.py +5 -14
  6. hanzo_mcp/cli_plugin.py +3 -9
  7. hanzo_mcp/config/settings.py +6 -20
  8. hanzo_mcp/config/tool_config.py +1 -3
  9. hanzo_mcp/core/base_agent.py +88 -88
  10. hanzo_mcp/core/model_registry.py +238 -210
  11. hanzo_mcp/dev_server.py +5 -15
  12. hanzo_mcp/prompts/__init__.py +2 -6
  13. hanzo_mcp/prompts/project_todo_reminder.py +3 -9
  14. hanzo_mcp/prompts/tool_explorer.py +1 -3
  15. hanzo_mcp/prompts/utils.py +7 -21
  16. hanzo_mcp/server.py +2 -6
  17. hanzo_mcp/tools/__init__.py +26 -27
  18. hanzo_mcp/tools/agent/__init__.py +2 -1
  19. hanzo_mcp/tools/agent/agent.py +10 -30
  20. hanzo_mcp/tools/agent/agent_tool.py +22 -15
  21. hanzo_mcp/tools/agent/claude_desktop_auth.py +3 -9
  22. hanzo_mcp/tools/agent/cli_agent_base.py +7 -24
  23. hanzo_mcp/tools/agent/cli_tools.py +75 -74
  24. hanzo_mcp/tools/agent/code_auth.py +1 -3
  25. hanzo_mcp/tools/agent/code_auth_tool.py +2 -6
  26. hanzo_mcp/tools/agent/critic_tool.py +8 -24
  27. hanzo_mcp/tools/agent/iching_tool.py +12 -36
  28. hanzo_mcp/tools/agent/network_tool.py +7 -18
  29. hanzo_mcp/tools/agent/prompt.py +1 -5
  30. hanzo_mcp/tools/agent/review_tool.py +10 -25
  31. hanzo_mcp/tools/agent/swarm_alias.py +1 -3
  32. hanzo_mcp/tools/agent/unified_cli_tools.py +38 -38
  33. hanzo_mcp/tools/common/batch_tool.py +15 -45
  34. hanzo_mcp/tools/common/config_tool.py +9 -28
  35. hanzo_mcp/tools/common/context.py +1 -3
  36. hanzo_mcp/tools/common/critic_tool.py +1 -3
  37. hanzo_mcp/tools/common/decorators.py +2 -6
  38. hanzo_mcp/tools/common/enhanced_base.py +2 -6
  39. hanzo_mcp/tools/common/fastmcp_pagination.py +4 -12
  40. hanzo_mcp/tools/common/forgiving_edit.py +9 -28
  41. hanzo_mcp/tools/common/mode.py +1 -5
  42. hanzo_mcp/tools/common/paginated_base.py +3 -11
  43. hanzo_mcp/tools/common/paginated_response.py +10 -30
  44. hanzo_mcp/tools/common/pagination.py +3 -9
  45. hanzo_mcp/tools/common/path_utils.py +34 -0
  46. hanzo_mcp/tools/common/permissions.py +14 -13
  47. hanzo_mcp/tools/common/personality.py +983 -701
  48. hanzo_mcp/tools/common/plugin_loader.py +3 -15
  49. hanzo_mcp/tools/common/stats.py +6 -18
  50. hanzo_mcp/tools/common/thinking_tool.py +1 -3
  51. hanzo_mcp/tools/common/tool_disable.py +2 -6
  52. hanzo_mcp/tools/common/tool_list.py +2 -6
  53. hanzo_mcp/tools/common/validation.py +1 -3
  54. hanzo_mcp/tools/compiler/__init__.py +8 -0
  55. hanzo_mcp/tools/compiler/sandboxed_compiler.py +681 -0
  56. hanzo_mcp/tools/config/config_tool.py +7 -13
  57. hanzo_mcp/tools/config/index_config.py +1 -3
  58. hanzo_mcp/tools/config/mode_tool.py +5 -15
  59. hanzo_mcp/tools/database/database_manager.py +3 -9
  60. hanzo_mcp/tools/database/graph.py +1 -3
  61. hanzo_mcp/tools/database/graph_add.py +3 -9
  62. hanzo_mcp/tools/database/graph_query.py +11 -34
  63. hanzo_mcp/tools/database/graph_remove.py +3 -9
  64. hanzo_mcp/tools/database/graph_search.py +6 -20
  65. hanzo_mcp/tools/database/graph_stats.py +11 -33
  66. hanzo_mcp/tools/database/sql.py +4 -12
  67. hanzo_mcp/tools/database/sql_query.py +6 -10
  68. hanzo_mcp/tools/database/sql_search.py +2 -6
  69. hanzo_mcp/tools/database/sql_stats.py +5 -15
  70. hanzo_mcp/tools/editor/neovim_command.py +1 -3
  71. hanzo_mcp/tools/editor/neovim_session.py +7 -13
  72. hanzo_mcp/tools/environment/__init__.py +8 -0
  73. hanzo_mcp/tools/environment/environment_detector.py +594 -0
  74. hanzo_mcp/tools/filesystem/__init__.py +28 -26
  75. hanzo_mcp/tools/filesystem/ast_multi_edit.py +14 -43
  76. hanzo_mcp/tools/filesystem/ast_tool.py +3 -0
  77. hanzo_mcp/tools/filesystem/base.py +20 -12
  78. hanzo_mcp/tools/filesystem/content_replace.py +7 -12
  79. hanzo_mcp/tools/filesystem/diff.py +2 -10
  80. hanzo_mcp/tools/filesystem/directory_tree.py +285 -51
  81. hanzo_mcp/tools/filesystem/edit.py +10 -18
  82. hanzo_mcp/tools/filesystem/find.py +312 -179
  83. hanzo_mcp/tools/filesystem/git_search.py +12 -24
  84. hanzo_mcp/tools/filesystem/multi_edit.py +10 -18
  85. hanzo_mcp/tools/filesystem/read.py +14 -30
  86. hanzo_mcp/tools/filesystem/rules_tool.py +9 -17
  87. hanzo_mcp/tools/filesystem/search.py +1160 -0
  88. hanzo_mcp/tools/filesystem/watch.py +2 -4
  89. hanzo_mcp/tools/filesystem/write.py +7 -10
  90. hanzo_mcp/tools/framework/__init__.py +8 -0
  91. hanzo_mcp/tools/framework/framework_modes.py +714 -0
  92. hanzo_mcp/tools/jupyter/base.py +6 -20
  93. hanzo_mcp/tools/jupyter/jupyter.py +4 -12
  94. hanzo_mcp/tools/llm/consensus_tool.py +8 -24
  95. hanzo_mcp/tools/llm/llm_manage.py +2 -6
  96. hanzo_mcp/tools/llm/llm_tool.py +17 -58
  97. hanzo_mcp/tools/llm/llm_unified.py +18 -59
  98. hanzo_mcp/tools/llm/provider_tools.py +1 -3
  99. hanzo_mcp/tools/lsp/lsp_tool.py +621 -481
  100. hanzo_mcp/tools/mcp/mcp_add.py +1 -3
  101. hanzo_mcp/tools/mcp/mcp_stats.py +1 -3
  102. hanzo_mcp/tools/mcp/mcp_tool.py +9 -23
  103. hanzo_mcp/tools/memory/__init__.py +10 -27
  104. hanzo_mcp/tools/memory/conversation_memory.py +636 -0
  105. hanzo_mcp/tools/memory/knowledge_tools.py +7 -25
  106. hanzo_mcp/tools/memory/memory_tools.py +6 -18
  107. hanzo_mcp/tools/search/find_tool.py +12 -34
  108. hanzo_mcp/tools/search/unified_search.py +24 -78
  109. hanzo_mcp/tools/shell/__init__.py +16 -4
  110. hanzo_mcp/tools/shell/auto_background.py +2 -6
  111. hanzo_mcp/tools/shell/base.py +1 -5
  112. hanzo_mcp/tools/shell/base_process.py +5 -7
  113. hanzo_mcp/tools/shell/bash_session.py +7 -24
  114. hanzo_mcp/tools/shell/bash_session_executor.py +5 -15
  115. hanzo_mcp/tools/shell/bash_tool.py +3 -7
  116. hanzo_mcp/tools/shell/command_executor.py +26 -79
  117. hanzo_mcp/tools/shell/logs.py +4 -16
  118. hanzo_mcp/tools/shell/npx.py +2 -8
  119. hanzo_mcp/tools/shell/npx_tool.py +1 -3
  120. hanzo_mcp/tools/shell/pkill.py +4 -12
  121. hanzo_mcp/tools/shell/process_tool.py +2 -8
  122. hanzo_mcp/tools/shell/processes.py +5 -17
  123. hanzo_mcp/tools/shell/run_background.py +1 -3
  124. hanzo_mcp/tools/shell/run_command.py +1 -3
  125. hanzo_mcp/tools/shell/run_command_windows.py +1 -3
  126. hanzo_mcp/tools/shell/run_tool.py +56 -0
  127. hanzo_mcp/tools/shell/session_manager.py +2 -6
  128. hanzo_mcp/tools/shell/session_storage.py +2 -6
  129. hanzo_mcp/tools/shell/streaming_command.py +7 -23
  130. hanzo_mcp/tools/shell/uvx.py +4 -14
  131. hanzo_mcp/tools/shell/uvx_background.py +2 -6
  132. hanzo_mcp/tools/shell/uvx_tool.py +1 -3
  133. hanzo_mcp/tools/shell/zsh_tool.py +12 -20
  134. hanzo_mcp/tools/todo/todo.py +1 -3
  135. hanzo_mcp/tools/vector/__init__.py +97 -50
  136. hanzo_mcp/tools/vector/ast_analyzer.py +6 -20
  137. hanzo_mcp/tools/vector/git_ingester.py +10 -30
  138. hanzo_mcp/tools/vector/index_tool.py +3 -9
  139. hanzo_mcp/tools/vector/infinity_store.py +7 -27
  140. hanzo_mcp/tools/vector/mock_infinity.py +1 -3
  141. hanzo_mcp/tools/vector/node_tool.py +538 -0
  142. hanzo_mcp/tools/vector/project_manager.py +4 -12
  143. hanzo_mcp/tools/vector/unified_vector.py +384 -0
  144. hanzo_mcp/tools/vector/vector.py +2 -6
  145. hanzo_mcp/tools/vector/vector_index.py +8 -8
  146. hanzo_mcp/tools/vector/vector_search.py +7 -21
  147. {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.9.0.dist-info}/METADATA +2 -2
  148. hanzo_mcp-0.9.0.dist-info/RECORD +191 -0
  149. hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +0 -645
  150. hanzo_mcp/tools/agent/swarm_tool.py +0 -718
  151. hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +0 -577
  152. hanzo_mcp/tools/filesystem/batch_search.py +0 -900
  153. hanzo_mcp/tools/filesystem/directory_tree_paginated.py +0 -350
  154. hanzo_mcp/tools/filesystem/find_files.py +0 -369
  155. hanzo_mcp/tools/filesystem/grep.py +0 -467
  156. hanzo_mcp/tools/filesystem/search_tool.py +0 -767
  157. hanzo_mcp/tools/filesystem/symbols_tool.py +0 -515
  158. hanzo_mcp/tools/filesystem/tree.py +0 -270
  159. hanzo_mcp/tools/jupyter/notebook_edit.py +0 -317
  160. hanzo_mcp/tools/jupyter/notebook_read.py +0 -147
  161. hanzo_mcp/tools/todo/todo_read.py +0 -143
  162. hanzo_mcp/tools/todo/todo_write.py +0 -374
  163. hanzo_mcp-0.8.11.dist-info/RECORD +0 -193
  164. {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.9.0.dist-info}/WHEEL +0 -0
  165. {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.9.0.dist-info}/entry_points.txt +0 -0
  166. {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.9.0.dist-info}/top_level.txt +0 -0
@@ -1,350 +0,0 @@
1
- """Paginated directory tree tool implementation.
2
-
3
- This module provides a paginated version of DirectoryTreeTool that supports
4
- MCP cursor-based pagination for large directory structures.
5
- """
6
-
7
- from typing import (
8
- Any,
9
- Dict,
10
- List,
11
- Unpack,
12
- Optional,
13
- Annotated,
14
- TypedDict,
15
- final,
16
- override,
17
- )
18
- from pathlib import Path
19
-
20
- from pydantic import Field
21
- from mcp.server import FastMCP
22
- from mcp.server.fastmcp import Context as MCPContext
23
-
24
- from hanzo_mcp.tools.filesystem.base import FilesystemBaseTool
25
- from hanzo_mcp.tools.common.pagination import (
26
- CursorManager,
27
- paginate_list,
28
- )
29
-
30
- DirectoryPath = Annotated[
31
- str,
32
- Field(
33
- description="The path to the directory to view",
34
- title="Path",
35
- ),
36
- ]
37
-
38
- Depth = Annotated[
39
- int,
40
- Field(
41
- default=3,
42
- description="The maximum depth to traverse (0 for unlimited)",
43
- title="Depth",
44
- ),
45
- ]
46
-
47
- IncludeFiltered = Annotated[
48
- bool,
49
- Field(
50
- default=False,
51
- description="Include directories that are normally filtered",
52
- title="Include Filtered",
53
- ),
54
- ]
55
-
56
- PageSize = Annotated[
57
- int,
58
- Field(
59
- default=100,
60
- description="Number of entries per page",
61
- title="Page Size",
62
- ),
63
- ]
64
-
65
- Cursor = Annotated[
66
- Optional[str],
67
- Field(
68
- default=None,
69
- description="Pagination cursor for continuing from previous request",
70
- title="Cursor",
71
- ),
72
- ]
73
-
74
-
75
- class DirectoryTreePaginatedParams(TypedDict):
76
- """Parameters for the paginated DirectoryTreeTool.
77
-
78
- Attributes:
79
- path: The path to the directory to view
80
- depth: The maximum depth to traverse (0 for unlimited)
81
- include_filtered: Include directories that are normally filtered
82
- page_size: Number of entries per page
83
- cursor: Pagination cursor
84
- """
85
-
86
- path: DirectoryPath
87
- depth: Depth
88
- include_filtered: IncludeFiltered
89
- page_size: PageSize
90
- cursor: Cursor
91
-
92
-
93
- @final
94
- class DirectoryTreePaginatedTool(FilesystemBaseTool):
95
- """Tool for viewing directory structure as a tree with pagination support."""
96
-
97
- @property
98
- @override
99
- def name(self) -> str:
100
- """Get the tool name."""
101
- return "directory_tree_paginated"
102
-
103
- @property
104
- @override
105
- def description(self) -> str:
106
- """Get the tool description."""
107
- return """Get a paginated recursive tree view of files and directories.
108
-
109
- This is a paginated version of directory_tree that supports cursor-based pagination
110
- for large directory structures. Returns a structured view with files and subdirectories.
111
-
112
- Directories are marked with trailing slashes. Common development directories like
113
- .git, node_modules, and venv are noted but not traversed unless explicitly requested.
114
-
115
- Use the cursor field to continue from where the previous request left off.
116
- Returns nextCursor if more entries are available."""
117
-
118
- @override
119
- async def call(
120
- self,
121
- ctx: MCPContext,
122
- **params: Unpack[DirectoryTreePaginatedParams],
123
- ) -> Dict[str, Any]:
124
- """Execute the tool with the given parameters.
125
-
126
- Args:
127
- ctx: MCP context
128
- **params: Tool parameters
129
-
130
- Returns:
131
- Dictionary with entries and optional nextCursor
132
- """
133
- tool_ctx = self.create_tool_context(ctx)
134
-
135
- # Extract parameters
136
- path: DirectoryPath = params["path"]
137
- depth = params.get("depth", 3)
138
- include_filtered = params.get("include_filtered", False)
139
- page_size = params.get("page_size", 100)
140
- cursor = params.get("cursor")
141
-
142
- # Validate cursor if provided
143
- if cursor:
144
- cursor_data = CursorManager.parse_cursor(cursor)
145
- if not cursor_data:
146
- await tool_ctx.error("Invalid cursor provided")
147
- return {"error": "Invalid cursor"}
148
-
149
- # Validate path parameter
150
- path_validation = self.validate_path(path)
151
- if path_validation.is_error:
152
- await tool_ctx.error(path_validation.error_message)
153
- return {"error": path_validation.error_message}
154
-
155
- await tool_ctx.info(
156
- f"Getting paginated directory tree: {path} (depth: {depth}, page_size: {page_size})"
157
- )
158
-
159
- # Check if path is allowed
160
- allowed, error_msg = await self.check_path_allowed(path, tool_ctx)
161
- if not allowed:
162
- return {"error": error_msg}
163
-
164
- try:
165
- dir_path = Path(path)
166
-
167
- # Check if path exists
168
- exists, error_msg = await self.check_path_exists(path, tool_ctx)
169
- if not exists:
170
- return {"error": error_msg}
171
-
172
- # Check if path is a directory
173
- is_dir, error_msg = await self.check_is_directory(path, tool_ctx)
174
- if not is_dir:
175
- return {"error": error_msg}
176
-
177
- # Define filtered directories
178
- FILTERED_DIRECTORIES = {
179
- ".git",
180
- "node_modules",
181
- ".venv",
182
- "venv",
183
- "__pycache__",
184
- ".pytest_cache",
185
- ".idea",
186
- ".vs",
187
- ".vscode",
188
- "dist",
189
- "build",
190
- "target",
191
- ".ruff_cache",
192
- ".llm-context",
193
- }
194
-
195
- # Check if a directory should be filtered
196
- def should_filter(current_path: Path) -> bool:
197
- if str(current_path.absolute()) == str(dir_path.absolute()):
198
- return False
199
- return (
200
- current_path.name in FILTERED_DIRECTORIES and not include_filtered
201
- )
202
-
203
- # Collect all entries in a flat list for pagination
204
- all_entries: List[Dict[str, Any]] = []
205
-
206
- # Build the tree and collect entries
207
- def collect_entries(
208
- current_path: Path, current_depth: int = 0, parent_path: str = ""
209
- ) -> None:
210
- """Collect entries in a flat list for pagination."""
211
- if not self.is_path_allowed(str(current_path)):
212
- return
213
-
214
- try:
215
- # Sort entries: directories first, then files alphabetically
216
- entries = sorted(
217
- current_path.iterdir(), key=lambda x: (not x.is_dir(), x.name)
218
- )
219
-
220
- for entry in entries:
221
- if not self.is_path_allowed(str(entry)):
222
- continue
223
-
224
- # Calculate relative path for display
225
- relative_path = (
226
- f"{parent_path}/{entry.name}" if parent_path else entry.name
227
- )
228
-
229
- if entry.is_dir():
230
- entry_data: Dict[str, Any] = {
231
- "path": relative_path,
232
- "type": "directory",
233
- "depth": current_depth,
234
- }
235
-
236
- # Check if we should filter this directory
237
- if should_filter(entry):
238
- entry_data["skipped"] = "filtered-directory"
239
- all_entries.append(entry_data)
240
- continue
241
-
242
- # Check depth limit
243
- if depth > 0 and current_depth >= depth:
244
- entry_data["skipped"] = "depth-limit"
245
- all_entries.append(entry_data)
246
- continue
247
-
248
- # Add directory entry
249
- all_entries.append(entry_data)
250
-
251
- # Process children recursively
252
- collect_entries(entry, current_depth + 1, relative_path)
253
- else:
254
- # Add file entry
255
- if depth <= 0 or current_depth < depth:
256
- all_entries.append(
257
- {
258
- "path": relative_path,
259
- "type": "file",
260
- "depth": current_depth,
261
- }
262
- )
263
-
264
- except Exception as e:
265
- await tool_ctx.warning(f"Error processing {current_path}: {str(e)}")
266
-
267
- # Collect all entries
268
- await tool_ctx.info("Collecting directory entries...")
269
- collect_entries(dir_path)
270
-
271
- # Paginate the results
272
- paginated = paginate_list(all_entries, cursor, page_size)
273
-
274
- # Format the paginated entries for display
275
- formatted_entries = []
276
- for entry in paginated.items:
277
- indent = " " * entry["depth"]
278
- if entry["type"] == "directory":
279
- if "skipped" in entry:
280
- formatted_entries.append(
281
- {
282
- "entry": f"{indent}{entry['path'].split('/')[-1]}/ [skipped - {entry['skipped']}]",
283
- "type": "directory",
284
- "skipped": entry.get("skipped"),
285
- }
286
- )
287
- else:
288
- formatted_entries.append(
289
- {
290
- "entry": f"{indent}{entry['path'].split('/')[-1]}/",
291
- "type": "directory",
292
- }
293
- )
294
- else:
295
- formatted_entries.append(
296
- {
297
- "entry": f"{indent}{entry['path'].split('/')[-1]}",
298
- "type": "file",
299
- }
300
- )
301
-
302
- # Build response
303
- response = {
304
- "entries": formatted_entries,
305
- "total_collected": len(all_entries),
306
- "page_size": page_size,
307
- "current_page_count": len(formatted_entries),
308
- }
309
-
310
- # Add next cursor if available
311
- if paginated.next_cursor:
312
- response["nextCursor"] = paginated.next_cursor
313
-
314
- await tool_ctx.info(
315
- f"Returning page with {len(formatted_entries)} entries"
316
- f"{' (more available)' if paginated.next_cursor else ' (end of results)'}"
317
- )
318
-
319
- return response
320
-
321
- except Exception as e:
322
- await tool_ctx.error(f"Error generating directory tree: {str(e)}")
323
- return {"error": f"Error generating directory tree: {str(e)}"}
324
-
325
- @override
326
- def register(self, mcp_server: FastMCP) -> None:
327
- """Register this paginated directory tree tool with the MCP server."""
328
- tool_self = self
329
-
330
- @mcp_server.tool(name=self.name, description=self.description)
331
- async def directory_tree_paginated(
332
- path: DirectoryPath,
333
- depth: Depth = 3,
334
- include_filtered: IncludeFiltered = False,
335
- page_size: PageSize = 100,
336
- cursor: Cursor = None,
337
- ctx: MCPContext = None,
338
- ) -> Dict[str, Any]:
339
- return await tool_self.call(
340
- ctx,
341
- path=path,
342
- depth=depth,
343
- include_filtered=include_filtered,
344
- page_size=page_size,
345
- cursor=cursor,
346
- )
347
-
348
-
349
- # Create the tool instance
350
- directory_tree_paginated_tool = DirectoryTreePaginatedTool()