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.

Files changed (118) hide show
  1. hanzo_mcp/__init__.py +1 -1
  2. hanzo_mcp/cli.py +32 -0
  3. hanzo_mcp/dev_server.py +246 -0
  4. hanzo_mcp/prompts/__init__.py +1 -1
  5. hanzo_mcp/prompts/project_system.py +43 -7
  6. hanzo_mcp/server.py +5 -1
  7. hanzo_mcp/tools/__init__.py +168 -6
  8. hanzo_mcp/tools/agent/__init__.py +1 -1
  9. hanzo_mcp/tools/agent/agent.py +401 -0
  10. hanzo_mcp/tools/agent/agent_tool.py +3 -4
  11. hanzo_mcp/tools/common/__init__.py +1 -1
  12. hanzo_mcp/tools/common/base.py +9 -4
  13. hanzo_mcp/tools/common/batch_tool.py +3 -5
  14. hanzo_mcp/tools/common/config_tool.py +1 -1
  15. hanzo_mcp/tools/common/context.py +1 -1
  16. hanzo_mcp/tools/common/palette.py +344 -0
  17. hanzo_mcp/tools/common/palette_loader.py +108 -0
  18. hanzo_mcp/tools/common/stats.py +261 -0
  19. hanzo_mcp/tools/common/thinking_tool.py +3 -5
  20. hanzo_mcp/tools/common/tool_disable.py +144 -0
  21. hanzo_mcp/tools/common/tool_enable.py +182 -0
  22. hanzo_mcp/tools/common/tool_list.py +260 -0
  23. hanzo_mcp/tools/config/__init__.py +10 -0
  24. hanzo_mcp/tools/config/config_tool.py +212 -0
  25. hanzo_mcp/tools/config/index_config.py +176 -0
  26. hanzo_mcp/tools/config/palette_tool.py +166 -0
  27. hanzo_mcp/tools/database/__init__.py +71 -0
  28. hanzo_mcp/tools/database/database_manager.py +246 -0
  29. hanzo_mcp/tools/database/graph.py +482 -0
  30. hanzo_mcp/tools/database/graph_add.py +257 -0
  31. hanzo_mcp/tools/database/graph_query.py +536 -0
  32. hanzo_mcp/tools/database/graph_remove.py +267 -0
  33. hanzo_mcp/tools/database/graph_search.py +348 -0
  34. hanzo_mcp/tools/database/graph_stats.py +345 -0
  35. hanzo_mcp/tools/database/sql.py +411 -0
  36. hanzo_mcp/tools/database/sql_query.py +229 -0
  37. hanzo_mcp/tools/database/sql_search.py +296 -0
  38. hanzo_mcp/tools/database/sql_stats.py +254 -0
  39. hanzo_mcp/tools/editor/__init__.py +11 -0
  40. hanzo_mcp/tools/editor/neovim_command.py +272 -0
  41. hanzo_mcp/tools/editor/neovim_edit.py +290 -0
  42. hanzo_mcp/tools/editor/neovim_session.py +356 -0
  43. hanzo_mcp/tools/filesystem/__init__.py +52 -13
  44. hanzo_mcp/tools/filesystem/base.py +1 -1
  45. hanzo_mcp/tools/filesystem/batch_search.py +812 -0
  46. hanzo_mcp/tools/filesystem/content_replace.py +3 -5
  47. hanzo_mcp/tools/filesystem/diff.py +193 -0
  48. hanzo_mcp/tools/filesystem/directory_tree.py +3 -5
  49. hanzo_mcp/tools/filesystem/edit.py +3 -5
  50. hanzo_mcp/tools/filesystem/find.py +443 -0
  51. hanzo_mcp/tools/filesystem/find_files.py +348 -0
  52. hanzo_mcp/tools/filesystem/git_search.py +505 -0
  53. hanzo_mcp/tools/filesystem/grep.py +2 -2
  54. hanzo_mcp/tools/filesystem/multi_edit.py +3 -5
  55. hanzo_mcp/tools/filesystem/read.py +17 -5
  56. hanzo_mcp/tools/filesystem/{grep_ast_tool.py → symbols.py} +17 -27
  57. hanzo_mcp/tools/filesystem/symbols_unified.py +376 -0
  58. hanzo_mcp/tools/filesystem/tree.py +268 -0
  59. hanzo_mcp/tools/filesystem/unified_search.py +465 -443
  60. hanzo_mcp/tools/filesystem/unix_aliases.py +99 -0
  61. hanzo_mcp/tools/filesystem/watch.py +174 -0
  62. hanzo_mcp/tools/filesystem/write.py +3 -5
  63. hanzo_mcp/tools/jupyter/__init__.py +9 -12
  64. hanzo_mcp/tools/jupyter/base.py +1 -1
  65. hanzo_mcp/tools/jupyter/jupyter.py +326 -0
  66. hanzo_mcp/tools/jupyter/notebook_edit.py +3 -4
  67. hanzo_mcp/tools/jupyter/notebook_read.py +3 -5
  68. hanzo_mcp/tools/llm/__init__.py +31 -0
  69. hanzo_mcp/tools/llm/consensus_tool.py +351 -0
  70. hanzo_mcp/tools/llm/llm_manage.py +413 -0
  71. hanzo_mcp/tools/llm/llm_tool.py +346 -0
  72. hanzo_mcp/tools/llm/llm_unified.py +851 -0
  73. hanzo_mcp/tools/llm/provider_tools.py +412 -0
  74. hanzo_mcp/tools/mcp/__init__.py +15 -0
  75. hanzo_mcp/tools/mcp/mcp_add.py +263 -0
  76. hanzo_mcp/tools/mcp/mcp_remove.py +127 -0
  77. hanzo_mcp/tools/mcp/mcp_stats.py +165 -0
  78. hanzo_mcp/tools/mcp/mcp_unified.py +503 -0
  79. hanzo_mcp/tools/shell/__init__.py +21 -23
  80. hanzo_mcp/tools/shell/base.py +1 -1
  81. hanzo_mcp/tools/shell/base_process.py +303 -0
  82. hanzo_mcp/tools/shell/bash_unified.py +134 -0
  83. hanzo_mcp/tools/shell/logs.py +265 -0
  84. hanzo_mcp/tools/shell/npx.py +194 -0
  85. hanzo_mcp/tools/shell/npx_background.py +254 -0
  86. hanzo_mcp/tools/shell/npx_unified.py +101 -0
  87. hanzo_mcp/tools/shell/open.py +107 -0
  88. hanzo_mcp/tools/shell/pkill.py +262 -0
  89. hanzo_mcp/tools/shell/process_unified.py +131 -0
  90. hanzo_mcp/tools/shell/processes.py +279 -0
  91. hanzo_mcp/tools/shell/run_background.py +326 -0
  92. hanzo_mcp/tools/shell/run_command.py +3 -4
  93. hanzo_mcp/tools/shell/run_command_windows.py +3 -4
  94. hanzo_mcp/tools/shell/uvx.py +187 -0
  95. hanzo_mcp/tools/shell/uvx_background.py +249 -0
  96. hanzo_mcp/tools/shell/uvx_unified.py +101 -0
  97. hanzo_mcp/tools/todo/__init__.py +1 -1
  98. hanzo_mcp/tools/todo/base.py +1 -1
  99. hanzo_mcp/tools/todo/todo.py +265 -0
  100. hanzo_mcp/tools/todo/todo_read.py +3 -5
  101. hanzo_mcp/tools/todo/todo_write.py +3 -5
  102. hanzo_mcp/tools/vector/__init__.py +6 -1
  103. hanzo_mcp/tools/vector/git_ingester.py +3 -0
  104. hanzo_mcp/tools/vector/index_tool.py +358 -0
  105. hanzo_mcp/tools/vector/infinity_store.py +98 -0
  106. hanzo_mcp/tools/vector/project_manager.py +27 -5
  107. hanzo_mcp/tools/vector/vector.py +311 -0
  108. hanzo_mcp/tools/vector/vector_index.py +1 -1
  109. hanzo_mcp/tools/vector/vector_search.py +12 -7
  110. hanzo_mcp-0.6.1.dist-info/METADATA +336 -0
  111. hanzo_mcp-0.6.1.dist-info/RECORD +134 -0
  112. hanzo_mcp-0.6.1.dist-info/entry_points.txt +3 -0
  113. hanzo_mcp-0.5.1.dist-info/METADATA +0 -276
  114. hanzo_mcp-0.5.1.dist-info/RECORD +0 -68
  115. hanzo_mcp-0.5.1.dist-info/entry_points.txt +0 -2
  116. {hanzo_mcp-0.5.1.dist-info → hanzo_mcp-0.6.1.dist-info}/WHEEL +0 -0
  117. {hanzo_mcp-0.5.1.dist-info → hanzo_mcp-0.6.1.dist-info}/licenses/LICENSE +0 -0
  118. {hanzo_mcp-0.5.1.dist-info → hanzo_mcp-0.6.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,257 @@
1
+ """Graph add tool for adding nodes and edges to the graph database."""
2
+
3
+ import json
4
+ from typing import Annotated, Optional, TypedDict, Unpack, final, override
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.context import create_tool_context
11
+ from hanzo_mcp.tools.common.permissions import PermissionManager
12
+ from hanzo_mcp.tools.database.database_manager import DatabaseManager
13
+
14
+
15
+ NodeId = Annotated[
16
+ Optional[str],
17
+ Field(
18
+ description="Node ID to add (required for nodes)",
19
+ default=None,
20
+ ),
21
+ ]
22
+
23
+ NodeType = Annotated[
24
+ Optional[str],
25
+ Field(
26
+ description="Node type (e.g., 'file', 'function', 'class')",
27
+ default=None,
28
+ ),
29
+ ]
30
+
31
+ Properties = Annotated[
32
+ Optional[dict],
33
+ Field(
34
+ description="Properties as JSON object",
35
+ default=None,
36
+ ),
37
+ ]
38
+
39
+ Source = Annotated[
40
+ Optional[str],
41
+ Field(
42
+ description="Source node ID (required for edges)",
43
+ default=None,
44
+ ),
45
+ ]
46
+
47
+ Target = Annotated[
48
+ Optional[str],
49
+ Field(
50
+ description="Target node ID (required for edges)",
51
+ default=None,
52
+ ),
53
+ ]
54
+
55
+ Relationship = Annotated[
56
+ Optional[str],
57
+ Field(
58
+ description="Edge relationship type (e.g., 'imports', 'calls', 'inherits')",
59
+ default=None,
60
+ ),
61
+ ]
62
+
63
+ Weight = Annotated[
64
+ float,
65
+ Field(
66
+ description="Edge weight (default 1.0)",
67
+ default=1.0,
68
+ ),
69
+ ]
70
+
71
+ ProjectPath = Annotated[
72
+ Optional[str],
73
+ Field(
74
+ description="Project path (defaults to current directory)",
75
+ default=None,
76
+ ),
77
+ ]
78
+
79
+
80
+ class GraphAddParams(TypedDict, total=False):
81
+ """Parameters for graph add tool."""
82
+
83
+ node_id: Optional[str]
84
+ node_type: Optional[str]
85
+ properties: Optional[dict]
86
+ source: Optional[str]
87
+ target: Optional[str]
88
+ relationship: Optional[str]
89
+ weight: float
90
+ project_path: Optional[str]
91
+
92
+
93
+ @final
94
+ class GraphAddTool(BaseTool):
95
+ """Tool for adding nodes and edges to graph database."""
96
+
97
+ def __init__(self, permission_manager: PermissionManager, db_manager: DatabaseManager):
98
+ """Initialize the graph add tool.
99
+
100
+ Args:
101
+ permission_manager: Permission manager for access control
102
+ db_manager: Database manager instance
103
+ """
104
+ self.permission_manager = permission_manager
105
+ self.db_manager = db_manager
106
+
107
+ @property
108
+ @override
109
+ def name(self) -> str:
110
+ """Get the tool name."""
111
+ return "graph_add"
112
+
113
+ @property
114
+ @override
115
+ def description(self) -> str:
116
+ """Get the tool description."""
117
+ return """Add nodes and edges to the project's graph database.
118
+
119
+ To add a node:
120
+ - Provide node_id and node_type
121
+ - Optionally add properties as JSON
122
+
123
+ To add an edge:
124
+ - Provide source, target, and relationship
125
+ - Optionally add weight and properties
126
+
127
+ Common node types:
128
+ - file, function, class, module, variable
129
+
130
+ Common relationships:
131
+ - imports, calls, inherits, contains, references, depends_on
132
+
133
+ Examples:
134
+ - graph_add --node-id "main.py" --node-type "file" --properties '{"size": 1024}'
135
+ - graph_add --node-id "MyClass" --node-type "class" --properties '{"file": "main.py"}'
136
+ - graph_add --source "main.py" --target "utils.py" --relationship "imports"
137
+ - graph_add --source "func1" --target "func2" --relationship "calls" --weight 5.0
138
+ """
139
+
140
+ @override
141
+ async def call(
142
+ self,
143
+ ctx: MCPContext,
144
+ **params: Unpack[GraphAddParams],
145
+ ) -> str:
146
+ """Add nodes or edges to graph.
147
+
148
+ Args:
149
+ ctx: MCP context
150
+ **params: Tool parameters
151
+
152
+ Returns:
153
+ Result of add operation
154
+ """
155
+ tool_ctx = create_tool_context(ctx)
156
+ await tool_ctx.set_tool_info(self.name)
157
+
158
+ # Extract parameters
159
+ node_id = params.get("node_id")
160
+ node_type = params.get("node_type")
161
+ properties = params.get("properties", {})
162
+ source = params.get("source")
163
+ target = params.get("target")
164
+ relationship = params.get("relationship")
165
+ weight = params.get("weight", 1.0)
166
+ project_path = params.get("project_path")
167
+
168
+ # Determine if adding node or edge
169
+ is_node = node_id is not None
170
+ is_edge = source is not None and target is not None
171
+
172
+ if not is_node and not is_edge:
173
+ return "Error: Must provide either (node_id and node_type) for a node, or (source, target, relationship) for an edge"
174
+
175
+ if is_node and is_edge:
176
+ return "Error: Cannot add both node and edge in one operation"
177
+
178
+ # Get project database
179
+ try:
180
+ if project_path:
181
+ project_db = self.db_manager.get_project_db(project_path)
182
+ else:
183
+ import os
184
+ project_db = self.db_manager.get_project_for_path(os.getcwd())
185
+
186
+ if not project_db:
187
+ return "Error: Could not find project database"
188
+
189
+ except PermissionError as e:
190
+ return str(e)
191
+ except Exception as e:
192
+ return f"Error accessing project database: {str(e)}"
193
+
194
+ # Get graph connection
195
+ graph_conn = project_db.get_graph_connection()
196
+
197
+ try:
198
+ if is_node:
199
+ # Add node
200
+ if not node_type:
201
+ return "Error: node_type is required when adding a node"
202
+
203
+ await tool_ctx.info(f"Adding node: {node_id} (type: {node_type})")
204
+
205
+ # Serialize properties
206
+ properties_json = json.dumps(properties) if properties else None
207
+
208
+ # Insert or update node
209
+ graph_conn.execute("""
210
+ INSERT OR REPLACE INTO nodes (id, type, properties)
211
+ VALUES (?, ?, ?)
212
+ """, (node_id, node_type, properties_json))
213
+
214
+ graph_conn.commit()
215
+
216
+ return f"Successfully added node '{node_id}' of type '{node_type}'"
217
+
218
+ else:
219
+ # Add edge
220
+ if not relationship:
221
+ return "Error: relationship is required when adding an edge"
222
+
223
+ await tool_ctx.info(f"Adding edge: {source} --[{relationship}]--> {target}")
224
+
225
+ # Check if nodes exist
226
+ cursor = graph_conn.cursor()
227
+ cursor.execute("SELECT id FROM nodes WHERE id IN (?, ?)", (source, target))
228
+ existing = [row[0] for row in cursor.fetchall()]
229
+
230
+ if source not in existing:
231
+ return f"Error: Source node '{source}' does not exist"
232
+ if target not in existing:
233
+ return f"Error: Target node '{target}' does not exist"
234
+
235
+ # Serialize properties
236
+ properties_json = json.dumps(properties) if properties else None
237
+
238
+ # Insert or update edge
239
+ graph_conn.execute("""
240
+ INSERT OR REPLACE INTO edges (source, target, relationship, weight, properties)
241
+ VALUES (?, ?, ?, ?, ?)
242
+ """, (source, target, relationship, weight, properties_json))
243
+
244
+ graph_conn.commit()
245
+
246
+ # Save to disk
247
+ project_db._save_graph_to_disk()
248
+
249
+ return f"Successfully added edge: {source} --[{relationship}]--> {target} (weight: {weight})"
250
+
251
+ except Exception as e:
252
+ await tool_ctx.error(f"Failed to add to graph: {str(e)}")
253
+ return f"Error adding to graph: {str(e)}"
254
+
255
+ def register(self, mcp_server) -> None:
256
+ """Register this tool with the MCP server."""
257
+ pass