hanzo-mcp 0.6.13__py3-none-any.whl → 0.7.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 (62) hide show
  1. hanzo_mcp/analytics/__init__.py +5 -0
  2. hanzo_mcp/analytics/posthog_analytics.py +364 -0
  3. hanzo_mcp/cli.py +3 -3
  4. hanzo_mcp/cli_enhanced.py +3 -3
  5. hanzo_mcp/config/settings.py +1 -1
  6. hanzo_mcp/config/tool_config.py +18 -4
  7. hanzo_mcp/server.py +34 -1
  8. hanzo_mcp/tools/__init__.py +65 -2
  9. hanzo_mcp/tools/agent/__init__.py +84 -3
  10. hanzo_mcp/tools/agent/agent_tool.py +102 -4
  11. hanzo_mcp/tools/agent/agent_tool_v2.py +459 -0
  12. hanzo_mcp/tools/agent/clarification_protocol.py +220 -0
  13. hanzo_mcp/tools/agent/clarification_tool.py +68 -0
  14. hanzo_mcp/tools/agent/claude_cli_tool.py +125 -0
  15. hanzo_mcp/tools/agent/claude_desktop_auth.py +508 -0
  16. hanzo_mcp/tools/agent/cli_agent_base.py +191 -0
  17. hanzo_mcp/tools/agent/code_auth.py +436 -0
  18. hanzo_mcp/tools/agent/code_auth_tool.py +194 -0
  19. hanzo_mcp/tools/agent/codex_cli_tool.py +123 -0
  20. hanzo_mcp/tools/agent/critic_tool.py +376 -0
  21. hanzo_mcp/tools/agent/gemini_cli_tool.py +128 -0
  22. hanzo_mcp/tools/agent/grok_cli_tool.py +128 -0
  23. hanzo_mcp/tools/agent/iching_tool.py +380 -0
  24. hanzo_mcp/tools/agent/network_tool.py +273 -0
  25. hanzo_mcp/tools/agent/prompt.py +62 -20
  26. hanzo_mcp/tools/agent/review_tool.py +433 -0
  27. hanzo_mcp/tools/agent/swarm_tool.py +535 -0
  28. hanzo_mcp/tools/agent/swarm_tool_v2.py +594 -0
  29. hanzo_mcp/tools/common/base.py +1 -0
  30. hanzo_mcp/tools/common/batch_tool.py +102 -10
  31. hanzo_mcp/tools/common/fastmcp_pagination.py +369 -0
  32. hanzo_mcp/tools/common/forgiving_edit.py +243 -0
  33. hanzo_mcp/tools/common/paginated_base.py +230 -0
  34. hanzo_mcp/tools/common/paginated_response.py +307 -0
  35. hanzo_mcp/tools/common/pagination.py +226 -0
  36. hanzo_mcp/tools/common/tool_list.py +3 -0
  37. hanzo_mcp/tools/common/truncate.py +101 -0
  38. hanzo_mcp/tools/filesystem/__init__.py +29 -0
  39. hanzo_mcp/tools/filesystem/ast_multi_edit.py +562 -0
  40. hanzo_mcp/tools/filesystem/directory_tree_paginated.py +338 -0
  41. hanzo_mcp/tools/lsp/__init__.py +5 -0
  42. hanzo_mcp/tools/lsp/lsp_tool.py +512 -0
  43. hanzo_mcp/tools/memory/__init__.py +76 -0
  44. hanzo_mcp/tools/memory/knowledge_tools.py +518 -0
  45. hanzo_mcp/tools/memory/memory_tools.py +456 -0
  46. hanzo_mcp/tools/search/__init__.py +6 -0
  47. hanzo_mcp/tools/search/find_tool.py +581 -0
  48. hanzo_mcp/tools/search/unified_search.py +953 -0
  49. hanzo_mcp/tools/shell/__init__.py +5 -0
  50. hanzo_mcp/tools/shell/auto_background.py +203 -0
  51. hanzo_mcp/tools/shell/base_process.py +53 -27
  52. hanzo_mcp/tools/shell/bash_tool.py +17 -33
  53. hanzo_mcp/tools/shell/npx_tool.py +15 -32
  54. hanzo_mcp/tools/shell/streaming_command.py +594 -0
  55. hanzo_mcp/tools/shell/uvx_tool.py +15 -32
  56. hanzo_mcp/types.py +23 -0
  57. {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/METADATA +228 -71
  58. {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/RECORD +61 -24
  59. hanzo_mcp-0.6.13.dist-info/licenses/LICENSE +0 -21
  60. {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/WHEEL +0 -0
  61. {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/entry_points.txt +0 -0
  62. {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,512 @@
1
+ """Language Server Protocol (LSP) tool for code intelligence.
2
+
3
+ This tool provides on-demand LSP configuration and installation for various
4
+ programming languages. It automatically installs language servers as needed
5
+ and provides code intelligence features like go-to-definition, find references,
6
+ rename symbol, and diagnostics.
7
+ """
8
+
9
+ import os
10
+ import subprocess
11
+ import json
12
+ import asyncio
13
+ import shutil
14
+ from typing import Dict, List, Any, Optional, Tuple
15
+ from pathlib import Path
16
+ from dataclasses import dataclass
17
+ import logging
18
+
19
+ from hanzo_mcp.tools.common.base import BaseTool
20
+ from hanzo_mcp.tools.common.decorators import with_context_normalization
21
+ from hanzo_mcp.types import MCPResourceDocument
22
+
23
+ # LSP server configurations
24
+ LSP_SERVERS = {
25
+ "go": {
26
+ "name": "gopls",
27
+ "install_cmd": ["go", "install", "golang.org/x/tools/gopls@latest"],
28
+ "check_cmd": ["gopls", "version"],
29
+ "start_cmd": ["gopls", "serve"],
30
+ "root_markers": ["go.mod", "go.sum"],
31
+ "file_extensions": [".go"],
32
+ "capabilities": ["definition", "references", "rename", "diagnostics", "hover", "completion"]
33
+ },
34
+ "python": {
35
+ "name": "pylsp",
36
+ "install_cmd": ["pip", "install", "python-lsp-server[all]"],
37
+ "check_cmd": ["pylsp", "--version"],
38
+ "start_cmd": ["pylsp"],
39
+ "root_markers": ["pyproject.toml", "setup.py", "requirements.txt"],
40
+ "file_extensions": [".py"],
41
+ "capabilities": ["definition", "references", "rename", "diagnostics", "hover", "completion"]
42
+ },
43
+ "typescript": {
44
+ "name": "typescript-language-server",
45
+ "install_cmd": ["npm", "install", "-g", "typescript", "typescript-language-server"],
46
+ "check_cmd": ["typescript-language-server", "--version"],
47
+ "start_cmd": ["typescript-language-server", "--stdio"],
48
+ "root_markers": ["tsconfig.json", "package.json"],
49
+ "file_extensions": [".ts", ".tsx", ".js", ".jsx"],
50
+ "capabilities": ["definition", "references", "rename", "diagnostics", "hover", "completion"]
51
+ },
52
+ "rust": {
53
+ "name": "rust-analyzer",
54
+ "install_cmd": ["rustup", "component", "add", "rust-analyzer"],
55
+ "check_cmd": ["rust-analyzer", "--version"],
56
+ "start_cmd": ["rust-analyzer"],
57
+ "root_markers": ["Cargo.toml"],
58
+ "file_extensions": [".rs"],
59
+ "capabilities": ["definition", "references", "rename", "diagnostics", "hover", "completion", "inlay_hints"]
60
+ },
61
+ "java": {
62
+ "name": "jdtls",
63
+ "install_cmd": ["brew", "install", "jdtls"], # Or manual download
64
+ "check_cmd": ["jdtls", "--version"],
65
+ "start_cmd": ["jdtls"],
66
+ "root_markers": ["pom.xml", "build.gradle", "build.gradle.kts"],
67
+ "file_extensions": [".java"],
68
+ "capabilities": ["definition", "references", "rename", "diagnostics", "hover", "completion"]
69
+ },
70
+ "cpp": {
71
+ "name": "clangd",
72
+ "install_cmd": ["brew", "install", "llvm"], # Or apt-get install clangd
73
+ "check_cmd": ["clangd", "--version"],
74
+ "start_cmd": ["clangd"],
75
+ "root_markers": ["compile_commands.json", "CMakeLists.txt"],
76
+ "file_extensions": [".cpp", ".cc", ".cxx", ".c", ".h", ".hpp"],
77
+ "capabilities": ["definition", "references", "rename", "diagnostics", "hover", "completion"]
78
+ },
79
+ "ruby": {
80
+ "name": "solargraph",
81
+ "install_cmd": ["gem", "install", "solargraph"],
82
+ "check_cmd": ["solargraph", "--version"],
83
+ "start_cmd": ["solargraph", "stdio"],
84
+ "root_markers": ["Gemfile", ".solargraph.yml"],
85
+ "file_extensions": [".rb"],
86
+ "capabilities": ["definition", "references", "diagnostics", "hover", "completion"]
87
+ },
88
+ "lua": {
89
+ "name": "lua-language-server",
90
+ "install_cmd": ["brew", "install", "lua-language-server"],
91
+ "check_cmd": ["lua-language-server", "--version"],
92
+ "start_cmd": ["lua-language-server"],
93
+ "root_markers": [".luarc.json"],
94
+ "file_extensions": [".lua"],
95
+ "capabilities": ["definition", "references", "rename", "diagnostics", "hover", "completion"]
96
+ }
97
+ }
98
+
99
+
100
+ @dataclass
101
+ class LSPServer:
102
+ """Represents an LSP server instance."""
103
+ language: str
104
+ process: Optional[asyncio.subprocess.Process]
105
+ config: Dict[str, Any]
106
+ root_uri: str
107
+ initialized: bool = False
108
+
109
+
110
+ class LSPTool(BaseTool):
111
+ """Language Server Protocol tool for code intelligence.
112
+
113
+ This tool automatically configures and manages LSP servers for various
114
+ programming languages. It installs language servers on-demand and provides
115
+ code intelligence features.
116
+
117
+ Features:
118
+ - Auto-installation of language servers
119
+ - Go-to-definition
120
+ - Find references
121
+ - Rename symbol
122
+ - Get diagnostics
123
+ - Hover information
124
+ - Code completion
125
+
126
+ Example usage:
127
+
128
+ 1. Find definition of a Go function:
129
+ lsp("definition", file="main.go", line=10, character=15)
130
+
131
+ 2. Find all references to a Python class:
132
+ lsp("references", file="models.py", line=25, character=10)
133
+
134
+ 3. Rename a TypeScript variable:
135
+ lsp("rename", file="app.ts", line=30, character=20, new_name="newVarName")
136
+
137
+ 4. Get diagnostics for a Rust file:
138
+ lsp("diagnostics", file="lib.rs")
139
+
140
+ The tool automatically detects the language based on file extension and
141
+ installs the appropriate language server if not already available.
142
+ """
143
+
144
+ name = "lsp"
145
+ description = """Language Server Protocol tool for code intelligence.
146
+
147
+ Actions:
148
+ - definition: Go to definition of symbol at position
149
+ - references: Find all references to symbol
150
+ - rename: Rename symbol across codebase
151
+ - diagnostics: Get errors and warnings for file
152
+ - hover: Get hover information at position
153
+ - completion: Get code completions at position
154
+ - status: Check LSP server status
155
+
156
+ The tool automatically installs language servers as needed.
157
+ Supported languages: Go, Python, TypeScript/JavaScript, Rust, Java, C/C++, Ruby, Lua
158
+ """
159
+
160
+ def __init__(self):
161
+ super().__init__()
162
+ self.servers: Dict[str, LSPServer] = {}
163
+ self.logger = logging.getLogger(__name__)
164
+
165
+ def _get_language_from_file(self, file_path: str) -> Optional[str]:
166
+ """Detect language from file extension."""
167
+ ext = Path(file_path).suffix.lower()
168
+
169
+ for lang, config in LSP_SERVERS.items():
170
+ if ext in config["file_extensions"]:
171
+ return lang
172
+
173
+ return None
174
+
175
+ def _find_project_root(self, file_path: str, language: str) -> str:
176
+ """Find project root based on language markers."""
177
+ markers = LSP_SERVERS[language]["root_markers"]
178
+ path = Path(file_path).resolve()
179
+
180
+ for parent in path.parents:
181
+ for marker in markers:
182
+ if (parent / marker).exists():
183
+ return str(parent)
184
+
185
+ return str(path.parent)
186
+
187
+ async def _check_lsp_installed(self, language: str) -> bool:
188
+ """Check if LSP server is installed."""
189
+ config = LSP_SERVERS.get(language)
190
+ if not config:
191
+ return False
192
+
193
+ try:
194
+ result = await asyncio.create_subprocess_exec(
195
+ *config["check_cmd"],
196
+ stdout=asyncio.subprocess.PIPE,
197
+ stderr=asyncio.subprocess.PIPE
198
+ )
199
+ await result.communicate()
200
+ return result.returncode == 0
201
+ except (FileNotFoundError, OSError):
202
+ return False
203
+
204
+ async def _install_lsp(self, language: str) -> bool:
205
+ """Install LSP server for language."""
206
+ config = LSP_SERVERS.get(language)
207
+ if not config:
208
+ return False
209
+
210
+ self.logger.info(f"Installing {config['name']} for {language}")
211
+
212
+ try:
213
+ # Check if installer is available
214
+ installer = config["install_cmd"][0]
215
+ if not shutil.which(installer):
216
+ self.logger.error(f"Installer {installer} not found")
217
+ return False
218
+
219
+ # Run installation command
220
+ result = await asyncio.create_subprocess_exec(
221
+ *config["install_cmd"],
222
+ stdout=asyncio.subprocess.PIPE,
223
+ stderr=asyncio.subprocess.PIPE
224
+ )
225
+
226
+ stdout, stderr = await result.communicate()
227
+
228
+ if result.returncode != 0:
229
+ self.logger.error(f"Installation failed: {stderr.decode()}")
230
+ return False
231
+
232
+ self.logger.info(f"Successfully installed {config['name']}")
233
+ return True
234
+
235
+ except Exception as e:
236
+ self.logger.error(f"Installation error: {e}")
237
+ return False
238
+
239
+ async def _ensure_lsp_running(self, language: str, root_uri: str) -> Optional[LSPServer]:
240
+ """Ensure LSP server is running for language."""
241
+ # Check if already running
242
+ server_key = f"{language}:{root_uri}"
243
+ if server_key in self.servers:
244
+ server = self.servers[server_key]
245
+ if server.process and server.process.returncode is None:
246
+ return server
247
+
248
+ # Check if installed
249
+ if not await self._check_lsp_installed(language):
250
+ # Try to install
251
+ if not await self._install_lsp(language):
252
+ return None
253
+
254
+ # Start LSP server
255
+ config = LSP_SERVERS[language]
256
+
257
+ try:
258
+ process = await asyncio.create_subprocess_exec(
259
+ *config["start_cmd"],
260
+ stdin=asyncio.subprocess.PIPE,
261
+ stdout=asyncio.subprocess.PIPE,
262
+ stderr=asyncio.subprocess.PIPE,
263
+ cwd=root_uri
264
+ )
265
+
266
+ server = LSPServer(
267
+ language=language,
268
+ process=process,
269
+ config=config,
270
+ root_uri=root_uri
271
+ )
272
+
273
+ # Initialize LSP
274
+ await self._initialize_lsp(server)
275
+
276
+ self.servers[server_key] = server
277
+ return server
278
+
279
+ except Exception as e:
280
+ self.logger.error(f"Failed to start LSP: {e}")
281
+ return None
282
+
283
+ async def _initialize_lsp(self, server: LSPServer):
284
+ """Send initialize request to LSP server."""
285
+ # This is a simplified initialization
286
+ # In a real implementation, you'd use the full LSP protocol
287
+ init_params = {
288
+ "processId": os.getpid(),
289
+ "rootUri": f"file://{server.root_uri}",
290
+ "capabilities": {
291
+ "textDocument": {
292
+ "definition": {"dynamicRegistration": True},
293
+ "references": {"dynamicRegistration": True},
294
+ "rename": {"dynamicRegistration": True}
295
+ }
296
+ }
297
+ }
298
+
299
+ # Send initialize request
300
+ request = {
301
+ "jsonrpc": "2.0",
302
+ "id": 1,
303
+ "method": "initialize",
304
+ "params": init_params
305
+ }
306
+
307
+ await self._send_request(server, request)
308
+ server.initialized = True
309
+
310
+ async def _send_request(self, server: LSPServer, request: Dict[str, Any]) -> Optional[Dict[str, Any]]:
311
+ """Send JSON-RPC request to LSP server."""
312
+ if not server.process or server.process.returncode is not None:
313
+ return None
314
+
315
+ try:
316
+ # Serialize request
317
+ request_str = json.dumps(request)
318
+ content_length = len(request_str.encode('utf-8'))
319
+
320
+ # Send LSP message
321
+ message = f"Content-Length: {content_length}\r\n\r\n{request_str}"
322
+ server.process.stdin.write(message.encode('utf-8'))
323
+ await server.process.stdin.drain()
324
+
325
+ # Read response (simplified - real implementation needs proper parsing)
326
+ # This is a placeholder - actual LSP requires parsing Content-Length headers
327
+ response_data = await server.process.stdout.readline()
328
+
329
+ if response_data:
330
+ return json.loads(response_data.decode('utf-8'))
331
+
332
+ except Exception as e:
333
+ self.logger.error(f"LSP communication error: {e}")
334
+
335
+ return None
336
+
337
+ async def run(self,
338
+ action: str,
339
+ file: str,
340
+ line: Optional[int] = None,
341
+ character: Optional[int] = None,
342
+ new_name: Optional[str] = None,
343
+ **kwargs) -> MCPResourceDocument:
344
+ """Execute LSP action.
345
+
346
+ Args:
347
+ action: LSP action (definition, references, rename, diagnostics, hover, completion, status)
348
+ file: File path to analyze
349
+ line: Line number (1-indexed)
350
+ character: Character position in line (0-indexed)
351
+ new_name: New name for rename action
352
+ """
353
+
354
+ # Validate action
355
+ valid_actions = ["definition", "references", "rename", "diagnostics", "hover", "completion", "status"]
356
+ if action not in valid_actions:
357
+ return MCPResourceDocument(data={
358
+ "error": f"Invalid action. Must be one of: {', '.join(valid_actions)}"
359
+ })
360
+
361
+ # Get language from file
362
+ language = self._get_language_from_file(file)
363
+ if not language:
364
+ return MCPResourceDocument(data={
365
+ "error": f"Unsupported file type: {file}",
366
+ "supported_languages": list(LSP_SERVERS.keys())
367
+ })
368
+
369
+ # Check LSP capabilities
370
+ capabilities = LSP_SERVERS[language]["capabilities"]
371
+ if action not in capabilities and action != "status":
372
+ return MCPResourceDocument(data={
373
+ "error": f"Action '{action}' not supported for {language}",
374
+ "supported_actions": capabilities
375
+ })
376
+
377
+ # Status check
378
+ if action == "status":
379
+ installed = await self._check_lsp_installed(language)
380
+ return MCPResourceDocument(data={
381
+ "language": language,
382
+ "lsp_server": LSP_SERVERS[language]["name"],
383
+ "installed": installed,
384
+ "capabilities": capabilities
385
+ })
386
+
387
+ # Find project root
388
+ root_uri = self._find_project_root(file, language)
389
+
390
+ # Ensure LSP is running
391
+ server = await self._ensure_lsp_running(language, root_uri)
392
+ if not server:
393
+ return MCPResourceDocument(data={
394
+ "error": f"Failed to start LSP server for {language}",
395
+ "install_command": " ".join(LSP_SERVERS[language]["install_cmd"])
396
+ })
397
+
398
+ # Execute action
399
+ result = await self._execute_lsp_action(server, action, file, line, character, new_name)
400
+
401
+ return MCPResourceDocument(data=result)
402
+
403
+ async def call(self, **kwargs) -> str:
404
+ """Tool interface for MCP - converts result to JSON string."""
405
+ result = await self.run(**kwargs)
406
+ return result.to_json_string()
407
+
408
+ def register(self, mcp_server) -> None:
409
+ """Register tool with MCP server."""
410
+ from mcp.server import FastMCP
411
+
412
+ @mcp_server.tool(name=self.name, description=self.description)
413
+ async def lsp_handler(
414
+ action: str,
415
+ file: str,
416
+ line: Optional[int] = None,
417
+ character: Optional[int] = None,
418
+ new_name: Optional[str] = None,
419
+ ) -> str:
420
+ """Execute LSP action."""
421
+ return await self.call(
422
+ action=action,
423
+ file=file,
424
+ line=line,
425
+ character=character,
426
+ new_name=new_name,
427
+ )
428
+
429
+ async def _execute_lsp_action(self,
430
+ server: LSPServer,
431
+ action: str,
432
+ file: str,
433
+ line: Optional[int],
434
+ character: Optional[int],
435
+ new_name: Optional[str]) -> Dict[str, Any]:
436
+ """Execute specific LSP action."""
437
+
438
+ # This is a simplified implementation
439
+ # Real implementation would use proper LSP protocol
440
+
441
+ if action == "definition":
442
+ # textDocument/definition request
443
+ return {
444
+ "action": "definition",
445
+ "file": file,
446
+ "position": {"line": line, "character": character},
447
+ "note": "LSP integration pending full implementation",
448
+ "fallback": "Use mcp__lsp__find_definition tool for now"
449
+ }
450
+
451
+ elif action == "references":
452
+ # textDocument/references request
453
+ return {
454
+ "action": "references",
455
+ "file": file,
456
+ "position": {"line": line, "character": character},
457
+ "note": "LSP integration pending full implementation",
458
+ "fallback": "Use mcp__lsp__find_references tool for now"
459
+ }
460
+
461
+ elif action == "rename":
462
+ # textDocument/rename request
463
+ return {
464
+ "action": "rename",
465
+ "file": file,
466
+ "position": {"line": line, "character": character},
467
+ "new_name": new_name,
468
+ "note": "LSP integration pending full implementation",
469
+ "fallback": "Use mcp__lsp__rename_symbol tool for now"
470
+ }
471
+
472
+ elif action == "diagnostics":
473
+ # textDocument/diagnostic request
474
+ return {
475
+ "action": "diagnostics",
476
+ "file": file,
477
+ "note": "LSP integration pending full implementation",
478
+ "fallback": "Use mcp__lsp__get_diagnostics tool for now"
479
+ }
480
+
481
+ elif action == "hover":
482
+ # textDocument/hover request
483
+ return {
484
+ "action": "hover",
485
+ "file": file,
486
+ "position": {"line": line, "character": character},
487
+ "note": "LSP integration pending full implementation"
488
+ }
489
+
490
+ elif action == "completion":
491
+ # textDocument/completion request
492
+ return {
493
+ "action": "completion",
494
+ "file": file,
495
+ "position": {"line": line, "character": character},
496
+ "note": "LSP integration pending full implementation"
497
+ }
498
+
499
+ return {"error": "Unknown action"}
500
+
501
+ async def cleanup(self):
502
+ """Clean up LSP servers."""
503
+ for server in self.servers.values():
504
+ if server.process and server.process.returncode is None:
505
+ server.process.terminate()
506
+ await server.process.wait()
507
+
508
+
509
+ # Tool registration
510
+ def create_lsp_tool():
511
+ """Factory function to create LSP tool."""
512
+ return LSPTool()
@@ -0,0 +1,76 @@
1
+ """Memory tools for MCP agents."""
2
+
3
+ from mcp.server import FastMCP
4
+
5
+ from hanzo_mcp.tools.memory.memory_tools import (
6
+ RecallMemoriesTool,
7
+ CreateMemoriesTool,
8
+ UpdateMemoriesTool,
9
+ DeleteMemoriesTool,
10
+ ManageMemoriesTool,
11
+ )
12
+ from hanzo_mcp.tools.memory.knowledge_tools import (
13
+ RecallFactsTool,
14
+ StoreFactsTool,
15
+ SummarizeToMemoryTool,
16
+ ManageKnowledgeBasesTool,
17
+ )
18
+ from hanzo_mcp.tools.common.base import BaseTool, ToolRegistry
19
+ from hanzo_mcp.tools.common.permissions import PermissionManager
20
+
21
+
22
+ def register_memory_tools(
23
+ mcp_server: FastMCP,
24
+ permission_manager: PermissionManager,
25
+ user_id: str = "default",
26
+ project_id: str = "default",
27
+ **memory_config
28
+ ) -> list[BaseTool]:
29
+ """Register memory tools with the MCP server.
30
+
31
+ Args:
32
+ mcp_server: The FastMCP server instance
33
+ permission_manager: Permission manager for access control
34
+ user_id: User ID for memory operations
35
+ project_id: Project ID for memory operations
36
+ **memory_config: Additional memory store configuration
37
+
38
+ Returns:
39
+ List of registered tools
40
+ """
41
+ # Create memory tools
42
+ recall_tool = RecallMemoriesTool(user_id=user_id, project_id=project_id, **memory_config)
43
+ create_tool = CreateMemoriesTool(user_id=user_id, project_id=project_id, **memory_config)
44
+ update_tool = UpdateMemoriesTool(user_id=user_id, project_id=project_id, **memory_config)
45
+ delete_tool = DeleteMemoriesTool(user_id=user_id, project_id=project_id, **memory_config)
46
+ manage_tool = ManageMemoriesTool(user_id=user_id, project_id=project_id, **memory_config)
47
+
48
+ # Create knowledge tools
49
+ recall_facts_tool = RecallFactsTool(user_id=user_id, project_id=project_id, **memory_config)
50
+ store_facts_tool = StoreFactsTool(user_id=user_id, project_id=project_id, **memory_config)
51
+ summarize_tool = SummarizeToMemoryTool(user_id=user_id, project_id=project_id, **memory_config)
52
+ manage_kb_tool = ManageKnowledgeBasesTool(user_id=user_id, project_id=project_id, **memory_config)
53
+
54
+ # Register tools
55
+ ToolRegistry.register_tool(mcp_server, recall_tool)
56
+ ToolRegistry.register_tool(mcp_server, create_tool)
57
+ ToolRegistry.register_tool(mcp_server, update_tool)
58
+ ToolRegistry.register_tool(mcp_server, delete_tool)
59
+ ToolRegistry.register_tool(mcp_server, manage_tool)
60
+ ToolRegistry.register_tool(mcp_server, recall_facts_tool)
61
+ ToolRegistry.register_tool(mcp_server, store_facts_tool)
62
+ ToolRegistry.register_tool(mcp_server, summarize_tool)
63
+ ToolRegistry.register_tool(mcp_server, manage_kb_tool)
64
+
65
+ # Return list of registered tools
66
+ return [
67
+ recall_tool,
68
+ create_tool,
69
+ update_tool,
70
+ delete_tool,
71
+ manage_tool,
72
+ recall_facts_tool,
73
+ store_facts_tool,
74
+ summarize_tool,
75
+ manage_kb_tool,
76
+ ]