hanzo-mcp 0.6.10__py3-none-any.whl → 0.6.13__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 (78) hide show
  1. hanzo_mcp/__init__.py +11 -2
  2. hanzo_mcp/cli.py +69 -19
  3. hanzo_mcp/cli_enhanced.py +15 -12
  4. hanzo_mcp/cli_plugin.py +91 -0
  5. hanzo_mcp/config/__init__.py +1 -1
  6. hanzo_mcp/config/settings.py +75 -8
  7. hanzo_mcp/config/tool_config.py +2 -2
  8. hanzo_mcp/dev_server.py +20 -15
  9. hanzo_mcp/prompts/project_system.py +1 -1
  10. hanzo_mcp/server.py +18 -4
  11. hanzo_mcp/server_enhanced.py +69 -0
  12. hanzo_mcp/tools/__init__.py +78 -30
  13. hanzo_mcp/tools/agent/__init__.py +1 -1
  14. hanzo_mcp/tools/agent/agent_tool.py +2 -2
  15. hanzo_mcp/tools/common/__init__.py +15 -1
  16. hanzo_mcp/tools/common/base.py +4 -4
  17. hanzo_mcp/tools/common/batch_tool.py +1 -1
  18. hanzo_mcp/tools/common/config_tool.py +2 -2
  19. hanzo_mcp/tools/common/context.py +2 -2
  20. hanzo_mcp/tools/common/context_fix.py +26 -0
  21. hanzo_mcp/tools/common/critic_tool.py +196 -0
  22. hanzo_mcp/tools/common/decorators.py +208 -0
  23. hanzo_mcp/tools/common/enhanced_base.py +106 -0
  24. hanzo_mcp/tools/common/mode.py +116 -0
  25. hanzo_mcp/tools/common/mode_loader.py +105 -0
  26. hanzo_mcp/tools/common/permissions.py +1 -1
  27. hanzo_mcp/tools/common/personality.py +936 -0
  28. hanzo_mcp/tools/common/plugin_loader.py +287 -0
  29. hanzo_mcp/tools/common/stats.py +4 -4
  30. hanzo_mcp/tools/common/tool_list.py +1 -1
  31. hanzo_mcp/tools/common/validation.py +1 -1
  32. hanzo_mcp/tools/config/__init__.py +3 -1
  33. hanzo_mcp/tools/config/config_tool.py +1 -1
  34. hanzo_mcp/tools/config/mode_tool.py +209 -0
  35. hanzo_mcp/tools/database/__init__.py +1 -1
  36. hanzo_mcp/tools/editor/__init__.py +1 -1
  37. hanzo_mcp/tools/filesystem/__init__.py +19 -14
  38. hanzo_mcp/tools/filesystem/batch_search.py +3 -3
  39. hanzo_mcp/tools/filesystem/diff.py +2 -2
  40. hanzo_mcp/tools/filesystem/rules_tool.py +235 -0
  41. hanzo_mcp/tools/filesystem/{unified_search.py → search_tool.py} +12 -12
  42. hanzo_mcp/tools/filesystem/{symbols_unified.py → symbols_tool.py} +104 -5
  43. hanzo_mcp/tools/filesystem/watch.py +3 -2
  44. hanzo_mcp/tools/jupyter/__init__.py +2 -2
  45. hanzo_mcp/tools/jupyter/jupyter.py +1 -1
  46. hanzo_mcp/tools/llm/__init__.py +3 -3
  47. hanzo_mcp/tools/llm/llm_tool.py +648 -143
  48. hanzo_mcp/tools/mcp/__init__.py +2 -2
  49. hanzo_mcp/tools/mcp/{mcp_unified.py → mcp_tool.py} +3 -3
  50. hanzo_mcp/tools/shell/__init__.py +6 -6
  51. hanzo_mcp/tools/shell/base_process.py +4 -2
  52. hanzo_mcp/tools/shell/bash_session_executor.py +8 -5
  53. hanzo_mcp/tools/shell/{bash_unified.py → bash_tool.py} +1 -1
  54. hanzo_mcp/tools/shell/command_executor.py +8 -6
  55. hanzo_mcp/tools/shell/{npx_unified.py → npx_tool.py} +1 -1
  56. hanzo_mcp/tools/shell/open.py +2 -2
  57. hanzo_mcp/tools/shell/{process_unified.py → process_tool.py} +1 -1
  58. hanzo_mcp/tools/shell/run_command_windows.py +1 -1
  59. hanzo_mcp/tools/shell/uvx.py +47 -2
  60. hanzo_mcp/tools/shell/uvx_background.py +47 -2
  61. hanzo_mcp/tools/shell/{uvx_unified.py → uvx_tool.py} +1 -1
  62. hanzo_mcp/tools/todo/__init__.py +14 -19
  63. hanzo_mcp/tools/todo/todo.py +22 -1
  64. hanzo_mcp/tools/vector/__init__.py +7 -3
  65. hanzo_mcp/tools/vector/ast_analyzer.py +12 -4
  66. hanzo_mcp/tools/vector/infinity_store.py +11 -5
  67. hanzo_mcp/tools/vector/project_manager.py +4 -2
  68. hanzo_mcp-0.6.13.dist-info/METADATA +359 -0
  69. {hanzo_mcp-0.6.10.dist-info → hanzo_mcp-0.6.13.dist-info}/RECORD +73 -65
  70. {hanzo_mcp-0.6.10.dist-info → hanzo_mcp-0.6.13.dist-info}/entry_points.txt +1 -0
  71. hanzo_mcp/tools/common/palette.py +0 -344
  72. hanzo_mcp/tools/common/palette_loader.py +0 -108
  73. hanzo_mcp/tools/config/palette_tool.py +0 -179
  74. hanzo_mcp/tools/llm/llm_unified.py +0 -851
  75. hanzo_mcp-0.6.10.dist-info/METADATA +0 -339
  76. {hanzo_mcp-0.6.10.dist-info → hanzo_mcp-0.6.13.dist-info}/WHEEL +0 -0
  77. {hanzo_mcp-0.6.10.dist-info → hanzo_mcp-0.6.13.dist-info}/licenses/LICENSE +0 -0
  78. {hanzo_mcp-0.6.10.dist-info → hanzo_mcp-0.6.13.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  """MCP management tools."""
2
2
 
3
- from hanzo_mcp.tools.mcp.mcp_unified import UnifiedMCPTool
3
+ from hanzo_mcp.tools.mcp.mcp_tool import MCPTool
4
4
 
5
5
  # Legacy imports
6
6
  from hanzo_mcp.tools.mcp.mcp_add import McpAddTool
@@ -8,7 +8,7 @@ from hanzo_mcp.tools.mcp.mcp_remove import McpRemoveTool
8
8
  from hanzo_mcp.tools.mcp.mcp_stats import McpStatsTool
9
9
 
10
10
  __all__ = [
11
- "UnifiedMCPTool",
11
+ "MCPTool",
12
12
  "McpAddTool",
13
13
  "McpRemoveTool",
14
14
  "McpStatsTool",
@@ -74,7 +74,7 @@ ConfigValue = Annotated[
74
74
  AutoStart = Annotated[
75
75
  bool,
76
76
  Field(
77
- description="Auto-start server when Hanzo MCP starts",
77
+ description="Auto-start server when Hanzo AI starts",
78
78
  default=True,
79
79
  ),
80
80
  ]
@@ -93,8 +93,8 @@ class MCPParams(TypedDict, total=False):
93
93
 
94
94
 
95
95
  @final
96
- class UnifiedMCPTool(BaseTool):
97
- """Unified tool for managing MCP servers."""
96
+ class MCPTool(BaseTool):
97
+ """Tool for managing MCP servers."""
98
98
 
99
99
  # Config file
100
100
  CONFIG_FILE = Path.home() / ".hanzo" / "mcp" / "servers.json"
@@ -1,4 +1,4 @@
1
- """Shell tools package for Hanzo MCP.
1
+ """Shell tools package for Hanzo AI.
2
2
 
3
3
  This package provides tools for executing shell commands and scripts.
4
4
  """
@@ -8,11 +8,11 @@ from mcp.server import FastMCP
8
8
  from hanzo_mcp.tools.common.base import BaseTool, ToolRegistry
9
9
  from hanzo_mcp.tools.common.permissions import PermissionManager
10
10
 
11
- # Import unified tools
12
- from hanzo_mcp.tools.shell.bash_unified import bash_tool
13
- from hanzo_mcp.tools.shell.npx_unified import npx_tool
14
- from hanzo_mcp.tools.shell.uvx_unified import uvx_tool
15
- from hanzo_mcp.tools.shell.process_unified import process_tool
11
+ # Import tools
12
+ from hanzo_mcp.tools.shell.bash_tool import bash_tool
13
+ from hanzo_mcp.tools.shell.npx_tool import npx_tool
14
+ from hanzo_mcp.tools.shell.uvx_tool import uvx_tool
15
+ from hanzo_mcp.tools.shell.process_tool import process_tool
16
16
  from hanzo_mcp.tools.shell.open import open_tool
17
17
 
18
18
  # Export all tool classes
@@ -130,7 +130,8 @@ class BaseProcessTool(BaseTool):
130
130
  """
131
131
  # Check permissions if manager is available
132
132
  if self.permission_manager and cwd:
133
- self.permission_manager.check_permission(cwd)
133
+ if not self.permission_manager.is_path_allowed(str(cwd)):
134
+ raise PermissionError(f"Access denied to path: {cwd}")
134
135
 
135
136
  # Get command arguments
136
137
  cmd_args = self.get_command_args(command, **kwargs)
@@ -179,7 +180,8 @@ class BaseProcessTool(BaseTool):
179
180
  """
180
181
  # Check permissions if manager is available
181
182
  if self.permission_manager and cwd:
182
- self.permission_manager.check_permission(cwd)
183
+ if not self.permission_manager.is_path_allowed(str(cwd)):
184
+ raise PermissionError(f"Access denied to path: {cwd}")
183
185
 
184
186
  # Generate process ID and log file
185
187
  process_id = f"{self.get_tool_name()}_{uuid.uuid4().hex[:8]}"
@@ -1,10 +1,11 @@
1
- """Bash session executor for Hanzo MCP.
1
+ """Bash session executor for Hanzo AI.
2
2
 
3
3
  This module provides a BashSessionExecutor class that replaces the old CommandExecutor
4
4
  implementation with the new BashSession-based approach for better persistent execution.
5
5
  """
6
6
 
7
7
  import asyncio
8
+ import logging
8
9
  import os
9
10
  import shlex
10
11
  import subprocess
@@ -64,16 +65,18 @@ class BashSessionExecutor:
64
65
  if data is not None:
65
66
  try:
66
67
  import json
67
-
68
+ logger = logging.getLogger(__name__)
68
69
  if isinstance(data, (dict, list)):
69
70
  data_str = json.dumps(data)
70
71
  else:
71
72
  data_str = str(data)
72
- print(f"DEBUG: {message}: {data_str}")
73
+ logger.debug(f"{message}: {data_str}")
73
74
  except Exception:
74
- print(f"DEBUG: {message}: {data}")
75
+ logger = logging.getLogger(__name__)
76
+ logger.debug(f"{message}: {data}")
75
77
  else:
76
- print(f"DEBUG: {message}")
78
+ logger = logging.getLogger(__name__)
79
+ logger.debug(f"{message}")
77
80
 
78
81
  def allow_command(self, command: str) -> None:
79
82
  """Allow a specific command that might otherwise be excluded.
@@ -27,7 +27,7 @@ class BashTool(BaseScriptTool):
27
27
  action: str = "run",
28
28
  cwd: Optional[str] = None,
29
29
  env: Optional[dict[str, str]] = None,
30
- timeout: Optional[int] = None,
30
+ timeout: Optional[int] = None
31
31
  ) -> str:
32
32
  return await tool_self.run(
33
33
  ctx,
@@ -1,4 +1,4 @@
1
- """Command executor tools for Hanzo MCP.
1
+ """Command executor tools for Hanzo AI.
2
2
 
3
3
  This module provides tools for executing shell commands and scripts with
4
4
  comprehensive error handling, permissions checking, and progress tracking.
@@ -22,7 +22,7 @@ from hanzo_mcp.tools.shell.base import CommandResult
22
22
 
23
23
  @final
24
24
  class CommandExecutor:
25
- """Command executor tools for Hanzo MCP.
25
+ """Command executor tools for Hanzo AI.
26
26
 
27
27
  This class provides tools for executing shell commands and scripts with
28
28
  comprehensive error handling, permissions checking, and progress tracking.
@@ -183,16 +183,18 @@ class CommandExecutor:
183
183
  if data is not None:
184
184
  try:
185
185
  import json
186
-
186
+ logger = logging.getLogger(__name__)
187
187
  if isinstance(data, (dict, list)):
188
188
  data_str = json.dumps(data)
189
189
  else:
190
190
  data_str = str(data)
191
- print(f"DEBUG: {message}: {data_str}", file=sys.stderr)
191
+ logger.debug(f"{message}: {data_str}")
192
192
  except Exception:
193
- print(f"DEBUG: {message}: {data}", file=sys.stderr)
193
+ logger = logging.getLogger(__name__)
194
+ logger.debug(f"{message}: {data}")
194
195
  else:
195
- print(f"DEBUG: {message}", file=sys.stderr)
196
+ logger = logging.getLogger(__name__)
197
+ logger.debug(f"{message}")
196
198
 
197
199
  def is_command_allowed(self, command: str) -> bool:
198
200
  """Check if a command is allowed based on exclusion lists.
@@ -99,7 +99,7 @@ npx --action background json-server db.json"""
99
99
  args: str = "",
100
100
  action: str = "run",
101
101
  cwd: Optional[str] = None,
102
- yes: bool = True,
102
+ yes: bool = True
103
103
  ) -> str:
104
104
  return await tool_self.run(
105
105
  ctx,
@@ -24,8 +24,8 @@ class OpenTool(BaseTool):
24
24
 
25
25
  @server.tool(name=self.name, description=self.description)
26
26
  async def open(
27
- ctx: MCPContext,
28
- path: str
27
+ path: str,
28
+ ctx: MCPContext
29
29
  ) -> str:
30
30
  return await tool_self.run(ctx, path)
31
31
 
@@ -128,7 +128,7 @@ process --action logs --id bash_ghi789 --lines 50"""
128
128
  action: str = "list",
129
129
  id: Optional[str] = None,
130
130
  signal_type: str = "TERM",
131
- lines: int = 100,
131
+ lines: int = 100
132
132
  ) -> str:
133
133
  return await tool_self.run(
134
134
  ctx,
@@ -123,7 +123,7 @@ Important notes:
123
123
  git commit -m \"$(cat <<'EOF'
124
124
  Commit message here.
125
125
 
126
- 🤖 Generated with [Hanzo MCP](https://github.com/SDGLBL/hanzo-mcp)
126
+ 🤖 Generated with [Hanzo AI](https://github.com/SDGLBL/hanzo-mcp)
127
127
 
128
128
  EOF
129
129
  )\"
@@ -129,11 +129,56 @@ For long-running servers, use uvx_background instead.
129
129
 
130
130
  # Check if uvx is available
131
131
  if not shutil.which("uvx"):
132
- return """Error: uvx is not installed. Install it with:
132
+ await tool_ctx.info("uvx not found, attempting to install...")
133
+
134
+ # Try to auto-install uvx
135
+ install_cmd = "curl -LsSf https://astral.sh/uv/install.sh | sh"
136
+
137
+ try:
138
+ # Run installation
139
+ install_result = subprocess.run(
140
+ install_cmd,
141
+ shell=True,
142
+ capture_output=True,
143
+ text=True,
144
+ timeout=60
145
+ )
146
+
147
+ if install_result.returncode == 0:
148
+ await tool_ctx.info("uvx installed successfully!")
149
+
150
+ # Add to PATH for current session
151
+ import os
152
+ home = os.path.expanduser("~")
153
+ os.environ["PATH"] = f"{home}/.cargo/bin:{os.environ.get('PATH', '')}"
154
+
155
+ # Check again
156
+ if not shutil.which("uvx"):
157
+ return """Error: uvx installed but not found in PATH.
158
+ Please add ~/.cargo/bin to your PATH and restart your shell.
159
+
160
+ Add to ~/.zshrc or ~/.bashrc:
161
+ export PATH="$HOME/.cargo/bin:$PATH"
162
+ """
163
+ else:
164
+ return f"""Error: Failed to install uvx automatically.
165
+
166
+ Install manually with:
133
167
  curl -LsSf https://astral.sh/uv/install.sh | sh
134
168
 
135
169
  Or on macOS:
136
- brew install uv"""
170
+ brew install uv
171
+
172
+ Error details: {install_result.stderr}"""
173
+
174
+ except subprocess.TimeoutExpired:
175
+ return """Error: Installation timed out. Install uvx manually with:
176
+ curl -LsSf https://astral.sh/uv/install.sh | sh"""
177
+ except Exception as e:
178
+ return f"""Error: Failed to auto-install uvx: {str(e)}
179
+
180
+ Install manually with:
181
+ curl -LsSf https://astral.sh/uv/install.sh | sh"""
137
182
 
138
183
  # Build command
139
184
  cmd = ["uvx"]
@@ -150,11 +150,56 @@ Use 'processes' to list running processes and 'pkill' to stop them.
150
150
 
151
151
  # Check if uvx is available
152
152
  if not shutil.which("uvx"):
153
- return """Error: uvx is not installed. Install it with:
153
+ await tool_ctx.info("uvx not found, attempting to install...")
154
+
155
+ # Try to auto-install uvx
156
+ install_cmd = "curl -LsSf https://astral.sh/uv/install.sh | sh"
157
+
158
+ try:
159
+ # Run installation
160
+ install_result = subprocess.run(
161
+ install_cmd,
162
+ shell=True,
163
+ capture_output=True,
164
+ text=True,
165
+ timeout=60
166
+ )
167
+
168
+ if install_result.returncode == 0:
169
+ await tool_ctx.info("uvx installed successfully!")
170
+
171
+ # Add to PATH for current session
172
+ import os
173
+ home = os.path.expanduser("~")
174
+ os.environ["PATH"] = f"{home}/.cargo/bin:{os.environ.get('PATH', '')}"
175
+
176
+ # Check again
177
+ if not shutil.which("uvx"):
178
+ return """Error: uvx installed but not found in PATH.
179
+ Please add ~/.cargo/bin to your PATH and restart your shell.
180
+
181
+ Add to ~/.zshrc or ~/.bashrc:
182
+ export PATH="$HOME/.cargo/bin:$PATH"
183
+ """
184
+ else:
185
+ return f"""Error: Failed to install uvx automatically.
186
+
187
+ Install manually with:
154
188
  curl -LsSf https://astral.sh/uv/install.sh | sh
155
189
 
156
190
  Or on macOS:
157
- brew install uv"""
191
+ brew install uv
192
+
193
+ Error details: {install_result.stderr}"""
194
+
195
+ except subprocess.TimeoutExpired:
196
+ return """Error: Installation timed out. Install uvx manually with:
197
+ curl -LsSf https://astral.sh/uv/install.sh | sh"""
198
+ except Exception as e:
199
+ return f"""Error: Failed to auto-install uvx: {str(e)}
200
+
201
+ Install manually with:
202
+ curl -LsSf https://astral.sh/uv/install.sh | sh"""
158
203
 
159
204
  # Build command
160
205
  cmd = ["uvx"]
@@ -99,7 +99,7 @@ uvx --action background jupyter lab --port 8888"""
99
99
  args: str = "",
100
100
  action: str = "run",
101
101
  cwd: Optional[str] = None,
102
- python: Optional[str] = None,
102
+ python: Optional[str] = None
103
103
  ) -> str:
104
104
  return await tool_self.run(
105
105
  ctx,
@@ -1,19 +1,17 @@
1
- """Todo tools package for Hanzo MCP.
1
+ """Todo tools package for Hanzo AI.
2
2
 
3
- This package provides tools for managing todo lists across different Claude Desktop sessions,
4
- using in-memory storage to maintain separate task lists for each conversation.
3
+ This package provides a unified todo management tool for organizing tasks
4
+ within Claude Desktop sessions.
5
5
  """
6
6
 
7
7
  from mcp.server import FastMCP
8
8
 
9
9
  from hanzo_mcp.tools.common.base import BaseTool, ToolRegistry
10
- from hanzo_mcp.tools.todo.todo_read import TodoReadTool
11
- from hanzo_mcp.tools.todo.todo_write import TodoWriteTool
10
+ from hanzo_mcp.tools.todo.todo import TodoTool
12
11
 
13
12
  # Export all tool classes
14
13
  __all__ = [
15
- "TodoReadTool",
16
- "TodoWriteTool",
14
+ "TodoTool",
17
15
  "get_todo_tools",
18
16
  "register_todo_tools",
19
17
  ]
@@ -26,8 +24,7 @@ def get_todo_tools() -> list[BaseTool]:
26
24
  List of todo tool instances
27
25
  """
28
26
  return [
29
- TodoReadTool(),
30
- TodoWriteTool(),
27
+ TodoTool(),
31
28
  ]
32
29
 
33
30
 
@@ -44,23 +41,21 @@ def register_todo_tools(
44
41
  Returns:
45
42
  List of registered tools
46
43
  """
47
- # Define tool mapping
44
+ # Define tool mapping - single unified todo tool
48
45
  tool_classes = {
49
- "todo_read": TodoReadTool,
50
- "todo_write": TodoWriteTool,
46
+ "todo": TodoTool,
51
47
  }
52
-
48
+
53
49
  tools = []
54
-
50
+
55
51
  if enabled_tools:
56
52
  # Use individual tool configuration
57
- for tool_name, enabled in enabled_tools.items():
58
- if enabled and tool_name in tool_classes:
59
- tool_class = tool_classes[tool_name]
60
- tools.append(tool_class())
53
+ # Support both old names and new name for backward compatibility
54
+ if enabled_tools.get("todo", True) or enabled_tools.get("todo_read", True) or enabled_tools.get("todo_write", True):
55
+ tools.append(TodoTool())
61
56
  else:
62
57
  # Use all tools (backward compatibility)
63
58
  tools = get_todo_tools()
64
-
59
+
65
60
  ToolRegistry.register_tools(mcp_server, tools)
66
61
  return tools
@@ -260,6 +260,27 @@ todo --filter in_progress
260
260
  self.write_todos([])
261
261
  return f"Cleared all {count} todo(s)"
262
262
 
263
+ @override
263
264
  def register(self, mcp_server) -> None:
264
265
  """Register this tool with the MCP server."""
265
- pass
266
+ tool_self = self # Create a reference to self for use in the closure
267
+
268
+ @mcp_server.tool(name=self.name, description=self.description)
269
+ async def todo(
270
+ action: Action = "list",
271
+ content: Content = None,
272
+ id: TodoId = None,
273
+ status: Status = None,
274
+ priority: Priority = None,
275
+ filter: Filter = None,
276
+ ctx: MCPContext = None,
277
+ ) -> str:
278
+ return await tool_self.call(
279
+ ctx,
280
+ action=action,
281
+ content=content,
282
+ id=id,
283
+ status=status,
284
+ priority=priority,
285
+ filter=filter,
286
+ )
@@ -1,4 +1,4 @@
1
- """Vector database tools for Hanzo MCP.
1
+ """Vector database tools for Hanzo AI.
2
2
 
3
3
  This package provides tools for working with local vector databases for semantic search,
4
4
  document indexing, and retrieval-augmented generation (RAG) workflows.
@@ -62,7 +62,9 @@ try:
62
62
  # Auto-detect projects from search paths for new manager
63
63
  if search_paths:
64
64
  detected_projects = project_manager.detect_projects(search_paths)
65
- print(f"Detected {len(detected_projects)} projects with LLM.md files")
65
+ import logging
66
+ logger = logging.getLogger(__name__)
67
+ logger.info(f"Detected {len(detected_projects)} projects with LLM.md files")
66
68
 
67
69
  # Register individual tools if enabled
68
70
  if tool_enabled.get("index", True):
@@ -85,7 +87,9 @@ except ImportError:
85
87
 
86
88
  def register_vector_tools(*args, **kwargs) -> list[BaseTool]:
87
89
  """Vector tools not available - missing dependencies."""
88
- print("Warning: Vector tools not available. Install infinity-embedded: pip install infinity-embedded")
90
+ import logging
91
+ logger = logging.getLogger(__name__)
92
+ logger.warning("Vector tools not available. Install infinity-embedded: pip install infinity-embedded")
89
93
  return []
90
94
 
91
95
 
@@ -94,7 +94,9 @@ class ASTAnalyzer:
94
94
  # Python parser
95
95
  self.parsers['python'] = tree_sitter.Language(tspython.language())
96
96
  except Exception as e:
97
- print(f"Warning: Could not initialize Python parser: {e}")
97
+ import logging
98
+ logger = logging.getLogger(__name__)
99
+ logger.warning(f"Could not initialize Python parser: {e}")
98
100
 
99
101
  def analyze_file(self, file_path: str) -> Optional[FileAST]:
100
102
  """Analyze a file and extract AST information and symbols.
@@ -127,7 +129,9 @@ class ASTAnalyzer:
127
129
  return self._analyze_generic_file(file_path, content, file_hash, language)
128
130
 
129
131
  except Exception as e:
130
- print(f"Error analyzing file {file_path}: {e}")
132
+ import logging
133
+ logger = logging.getLogger(__name__)
134
+ logger.error(f"Error analyzing file {file_path}: {e}")
131
135
  return None
132
136
 
133
137
  def _detect_language(self, path: Path) -> Optional[str]:
@@ -194,9 +198,13 @@ class ASTAnalyzer:
194
198
  ast_nodes = self._extract_tree_sitter_nodes(ts_tree.root_node, content)
195
199
 
196
200
  except SyntaxError as e:
197
- print(f"Syntax error in {file_path}: {e}")
201
+ import logging
202
+ logger = logging.getLogger(__name__)
203
+ logger.error(f"Syntax error in {file_path}: {e}")
198
204
  except Exception as e:
199
- print(f"Error parsing Python file {file_path}: {e}")
205
+ import logging
206
+ logger = logging.getLogger(__name__)
207
+ logger.error(f"Error parsing Python file {file_path}: {e}")
200
208
 
201
209
  return FileAST(
202
210
  file_path=file_path,
@@ -1,4 +1,4 @@
1
- """Infinity vector database integration for Hanzo MCP."""
1
+ """Infinity vector database integration for Hanzo AI."""
2
2
 
3
3
  import json
4
4
  import hashlib
@@ -45,7 +45,7 @@ class SymbolSearchResult:
45
45
 
46
46
  @dataclass
47
47
  class UnifiedSearchResult:
48
- """Unified search result combining text, vector, and symbol search."""
48
+ """Search result combining text, vector, and symbol search."""
49
49
  type: str # 'document', 'symbol', 'reference'
50
50
  content: str
51
51
  file_path: str
@@ -528,7 +528,9 @@ class InfinityVectorStore:
528
528
  return file_ast
529
529
 
530
530
  except Exception as e:
531
- print(f"Error searching AST nodes: {e}")
531
+ import logging
532
+ logger = logging.getLogger(__name__)
533
+ logger.error(f"Error searching AST nodes: {e}")
532
534
  return None
533
535
 
534
536
  def get_file_references(self, file_path: str) -> List[Dict[str, Any]]:
@@ -555,7 +557,9 @@ class InfinityVectorStore:
555
557
  return references
556
558
 
557
559
  except Exception as e:
558
- print(f"Error getting file references: {e}")
560
+ import logging
561
+ logger = logging.getLogger(__name__)
562
+ logger.error(f"Error getting file references: {e}")
559
563
  return []
560
564
 
561
565
  def search(
@@ -803,7 +807,9 @@ class InfinityVectorStore:
803
807
 
804
808
  return True
805
809
  except Exception as e:
806
- print(f"Error clearing vector store: {e}")
810
+ import logging
811
+ logger = logging.getLogger(__name__)
812
+ logger.error(f"Error clearing vector store: {e}")
807
813
  return False
808
814
 
809
815
  async def index_document(
@@ -1,4 +1,4 @@
1
- """Project-aware vector database management for Hanzo MCP."""
1
+ """Project-aware vector database management for Hanzo AI."""
2
2
 
3
3
  import os
4
4
  from pathlib import Path
@@ -294,7 +294,9 @@ class ProjectVectorManager:
294
294
  project_name = project_names[i]
295
295
  if isinstance(result, Exception):
296
296
  # Log error but continue
297
- print(f"Error searching project {project_name}: {result}")
297
+ import logging
298
+ logger = logging.getLogger(__name__)
299
+ logger.error(f"Error searching project {project_name}: {result}")
298
300
  combined_results[project_name] = []
299
301
  else:
300
302
  combined_results[project_name] = result