hanzo-mcp 0.3.8__py3-none-any.whl → 0.5.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 (87) hide show
  1. hanzo_mcp/__init__.py +1 -1
  2. hanzo_mcp/cli.py +118 -170
  3. hanzo_mcp/cli_enhanced.py +438 -0
  4. hanzo_mcp/config/__init__.py +19 -0
  5. hanzo_mcp/config/settings.py +388 -0
  6. hanzo_mcp/config/tool_config.py +197 -0
  7. hanzo_mcp/prompts/__init__.py +117 -0
  8. hanzo_mcp/prompts/compact_conversation.py +77 -0
  9. hanzo_mcp/prompts/create_release.py +38 -0
  10. hanzo_mcp/prompts/project_system.py +120 -0
  11. hanzo_mcp/prompts/project_todo_reminder.py +111 -0
  12. hanzo_mcp/prompts/utils.py +286 -0
  13. hanzo_mcp/server.py +117 -99
  14. hanzo_mcp/tools/__init__.py +105 -32
  15. hanzo_mcp/tools/agent/__init__.py +8 -11
  16. hanzo_mcp/tools/agent/agent_tool.py +290 -224
  17. hanzo_mcp/tools/agent/prompt.py +16 -13
  18. hanzo_mcp/tools/agent/tool_adapter.py +9 -9
  19. hanzo_mcp/tools/common/__init__.py +17 -16
  20. hanzo_mcp/tools/common/base.py +79 -110
  21. hanzo_mcp/tools/common/batch_tool.py +330 -0
  22. hanzo_mcp/tools/common/context.py +26 -292
  23. hanzo_mcp/tools/common/permissions.py +12 -12
  24. hanzo_mcp/tools/common/thinking_tool.py +153 -0
  25. hanzo_mcp/tools/common/validation.py +1 -63
  26. hanzo_mcp/tools/filesystem/__init__.py +88 -57
  27. hanzo_mcp/tools/filesystem/base.py +32 -24
  28. hanzo_mcp/tools/filesystem/content_replace.py +114 -107
  29. hanzo_mcp/tools/filesystem/directory_tree.py +129 -105
  30. hanzo_mcp/tools/filesystem/edit.py +279 -0
  31. hanzo_mcp/tools/filesystem/grep.py +458 -0
  32. hanzo_mcp/tools/filesystem/grep_ast_tool.py +250 -0
  33. hanzo_mcp/tools/filesystem/multi_edit.py +362 -0
  34. hanzo_mcp/tools/filesystem/read.py +255 -0
  35. hanzo_mcp/tools/filesystem/write.py +156 -0
  36. hanzo_mcp/tools/jupyter/__init__.py +41 -29
  37. hanzo_mcp/tools/jupyter/base.py +66 -57
  38. hanzo_mcp/tools/jupyter/{edit_notebook.py → notebook_edit.py} +162 -139
  39. hanzo_mcp/tools/jupyter/notebook_read.py +152 -0
  40. hanzo_mcp/tools/shell/__init__.py +29 -20
  41. hanzo_mcp/tools/shell/base.py +87 -45
  42. hanzo_mcp/tools/shell/bash_session.py +731 -0
  43. hanzo_mcp/tools/shell/bash_session_executor.py +295 -0
  44. hanzo_mcp/tools/shell/command_executor.py +435 -384
  45. hanzo_mcp/tools/shell/run_command.py +284 -131
  46. hanzo_mcp/tools/shell/run_command_windows.py +328 -0
  47. hanzo_mcp/tools/shell/session_manager.py +196 -0
  48. hanzo_mcp/tools/shell/session_storage.py +325 -0
  49. hanzo_mcp/tools/todo/__init__.py +66 -0
  50. hanzo_mcp/tools/todo/base.py +319 -0
  51. hanzo_mcp/tools/todo/todo_read.py +148 -0
  52. hanzo_mcp/tools/todo/todo_write.py +378 -0
  53. hanzo_mcp/tools/vector/__init__.py +95 -0
  54. hanzo_mcp/tools/vector/infinity_store.py +365 -0
  55. hanzo_mcp/tools/vector/project_manager.py +361 -0
  56. hanzo_mcp/tools/vector/vector_index.py +115 -0
  57. hanzo_mcp/tools/vector/vector_search.py +215 -0
  58. {hanzo_mcp-0.3.8.dist-info → hanzo_mcp-0.5.0.dist-info}/METADATA +33 -1
  59. hanzo_mcp-0.5.0.dist-info/RECORD +63 -0
  60. {hanzo_mcp-0.3.8.dist-info → hanzo_mcp-0.5.0.dist-info}/WHEEL +1 -1
  61. hanzo_mcp/tools/agent/base_provider.py +0 -73
  62. hanzo_mcp/tools/agent/litellm_provider.py +0 -45
  63. hanzo_mcp/tools/agent/lmstudio_agent.py +0 -385
  64. hanzo_mcp/tools/agent/lmstudio_provider.py +0 -219
  65. hanzo_mcp/tools/agent/provider_registry.py +0 -120
  66. hanzo_mcp/tools/common/error_handling.py +0 -86
  67. hanzo_mcp/tools/common/logging_config.py +0 -115
  68. hanzo_mcp/tools/common/session.py +0 -91
  69. hanzo_mcp/tools/common/think_tool.py +0 -123
  70. hanzo_mcp/tools/common/version_tool.py +0 -120
  71. hanzo_mcp/tools/filesystem/edit_file.py +0 -287
  72. hanzo_mcp/tools/filesystem/get_file_info.py +0 -170
  73. hanzo_mcp/tools/filesystem/read_files.py +0 -199
  74. hanzo_mcp/tools/filesystem/search_content.py +0 -275
  75. hanzo_mcp/tools/filesystem/write_file.py +0 -162
  76. hanzo_mcp/tools/jupyter/notebook_operations.py +0 -514
  77. hanzo_mcp/tools/jupyter/read_notebook.py +0 -165
  78. hanzo_mcp/tools/project/__init__.py +0 -64
  79. hanzo_mcp/tools/project/analysis.py +0 -886
  80. hanzo_mcp/tools/project/base.py +0 -66
  81. hanzo_mcp/tools/project/project_analyze.py +0 -173
  82. hanzo_mcp/tools/shell/run_script.py +0 -215
  83. hanzo_mcp/tools/shell/script_tool.py +0 -244
  84. hanzo_mcp-0.3.8.dist-info/RECORD +0 -53
  85. {hanzo_mcp-0.3.8.dist-info → hanzo_mcp-0.5.0.dist-info}/entry_points.txt +0 -0
  86. {hanzo_mcp-0.3.8.dist-info → hanzo_mcp-0.5.0.dist-info}/licenses/LICENSE +0 -0
  87. {hanzo_mcp-0.3.8.dist-info → hanzo_mcp-0.5.0.dist-info}/top_level.txt +0 -0
hanzo_mcp/server.py CHANGED
@@ -1,121 +1,189 @@
1
- """MCP server implementing Hanzo capabilities.
2
-
3
- Includes improved error handling and debugging for tool execution.
4
- """
1
+ """MCP server implementing Hanzo capabilities."""
5
2
 
3
+ import atexit
4
+ import signal
5
+ import threading
6
+ import time
6
7
  from typing import Literal, cast, final
7
8
 
8
- from mcp.server.fastmcp import FastMCP
9
+ from fastmcp import FastMCP
9
10
 
11
+ from hanzo_mcp.prompts import register_all_prompts
10
12
  from hanzo_mcp.tools import register_all_tools
11
- from hanzo_mcp.tools.common.context import DocumentContext
13
+
12
14
  from hanzo_mcp.tools.common.permissions import PermissionManager
13
- from hanzo_mcp.tools.project.analysis import ProjectAnalyzer, ProjectManager
14
- from hanzo_mcp.tools.shell.command_executor import CommandExecutor
15
+ from hanzo_mcp.tools.shell.session_storage import SessionStorage
15
16
 
16
17
 
17
18
  @final
18
- class HanzoServer:
19
- """MCP server implementing Hanzo capabilities.
20
-
21
- Includes improved error handling and debugging for tool execution.
22
- """
19
+ class HanzoMCPServer:
20
+ """MCP server implementing Hanzo capabilities."""
23
21
 
24
22
  def __init__(
25
23
  self,
26
- name: str = "claude-code",
24
+ name: str = "hanzo",
27
25
  allowed_paths: list[str] | None = None,
26
+ project_paths: list[str] | None = None,
28
27
  project_dir: str | None = None,
29
28
  mcp_instance: FastMCP | None = None,
30
29
  agent_model: str | None = None,
31
30
  agent_max_tokens: int | None = None,
32
31
  agent_api_key: str | None = None,
32
+ agent_base_url: str | None = None,
33
33
  agent_max_iterations: int = 10,
34
34
  agent_max_tool_uses: int = 30,
35
35
  enable_agent_tool: bool = False,
36
+ command_timeout: float = 120.0,
36
37
  disable_write_tools: bool = False,
37
38
  disable_search_tools: bool = False,
38
- host: str = "0.0.0.0",
39
- port: int = 3001,
39
+ host: str = "127.0.0.1",
40
+ port: int = 3000,
41
+ enabled_tools: dict[str, bool] | None = None,
42
+ disabled_tools: list[str] | None = None,
40
43
  ):
41
- """Initialize the Hanzo server.
44
+ """Initialize the Hanzo MCP server.
42
45
 
43
46
  Args:
44
47
  name: The name of the server
45
48
  allowed_paths: list of paths that the server is allowed to access
46
- project_dir: Optional project directory to use as initial working directory
49
+ project_paths: list of project paths to generate prompts for
50
+ project_dir: single project directory (added to allowed_paths and project_paths)
47
51
  mcp_instance: Optional FastMCP instance for testing
48
52
  agent_model: Optional model name for agent tool in LiteLLM format
49
53
  agent_max_tokens: Optional maximum tokens for agent responses
50
54
  agent_api_key: Optional API key for the LLM provider
55
+ agent_base_url: Optional base URL for the LLM provider API endpoint
51
56
  agent_max_iterations: Maximum number of iterations for agent (default: 10)
52
57
  agent_max_tool_uses: Maximum number of total tool uses for agent (default: 30)
53
58
  enable_agent_tool: Whether to enable the agent tool (default: False)
54
- disable_write_tools: Whether to disable write/edit tools (default: False)
59
+ command_timeout: Default timeout for command execution in seconds (default: 120.0)
60
+ disable_write_tools: Whether to disable write tools (default: False)
55
61
  disable_search_tools: Whether to disable search tools (default: False)
56
- host: Host to bind to for SSE transport (default: '0.0.0.0')
57
- port: Port to use for SSE transport (default: 3001)
62
+ host: Host for SSE server (default: 127.0.0.1)
63
+ port: Port for SSE server (default: 3000)
64
+ enabled_tools: Dictionary of individual tool enable states (default: None)
65
+ disabled_tools: List of tool names to disable (default: None)
58
66
  """
59
67
  self.mcp = mcp_instance if mcp_instance is not None else FastMCP(name)
60
68
 
61
- # Initialize context, permissions, and command executor
62
- self.document_context = DocumentContext()
69
+ # Initialize permissions and command executor
63
70
  self.permission_manager = PermissionManager()
64
71
 
65
- # Initialize command executor
66
- self.command_executor = CommandExecutor(
67
- permission_manager=self.permission_manager,
68
- verbose=False, # Set to True for debugging
69
- )
70
-
71
- # If project_dir is specified, set it as initial working directory for all sessions
72
+ # Handle project_dir parameter
72
73
  if project_dir:
73
- initial_session_id = name # Use server name as default session ID
74
- self.command_executor.set_working_dir(initial_session_id, project_dir)
75
-
76
- # Initialize project analyzer
77
- self.project_analyzer = ProjectAnalyzer(self.command_executor)
78
-
79
- # Initialize project manager
80
- self.project_manager = ProjectManager(
81
- self.document_context, self.permission_manager, self.project_analyzer
82
- )
74
+ if allowed_paths is None:
75
+ allowed_paths = []
76
+ if project_dir not in allowed_paths:
77
+ allowed_paths.append(project_dir)
78
+ if project_paths is None:
79
+ project_paths = []
80
+ if project_dir not in project_paths:
81
+ project_paths.append(project_dir)
83
82
 
84
83
  # Add allowed paths
85
84
  if allowed_paths:
86
85
  for path in allowed_paths:
87
86
  self.permission_manager.add_allowed_path(path)
88
- self.document_context.add_allowed_path(path)
87
+
88
+ # Store paths and options
89
+ self.project_paths = project_paths
90
+ self.project_dir = project_dir
91
+ self.disable_write_tools = disable_write_tools
92
+ self.disable_search_tools = disable_search_tools
93
+ self.host = host
94
+ self.port = port
95
+ self.enabled_tools = enabled_tools or {}
96
+ self.disabled_tools = disabled_tools or []
89
97
 
90
98
  # Store agent options
91
99
  self.agent_model = agent_model
92
100
  self.agent_max_tokens = agent_max_tokens
93
101
  self.agent_api_key = agent_api_key
102
+ self.agent_base_url = agent_base_url
94
103
  self.agent_max_iterations = agent_max_iterations
95
104
  self.agent_max_tool_uses = agent_max_tool_uses
96
105
  self.enable_agent_tool = enable_agent_tool
97
- self.disable_write_tools = disable_write_tools
98
- self.disable_search_tools = disable_search_tools
106
+ self.command_timeout = command_timeout
99
107
 
100
- # Store network options
101
- self.host = host
102
- self.port = port
108
+ # Initialize cleanup tracking
109
+ self._cleanup_thread: threading.Thread | None = None
110
+ self._shutdown_event = threading.Event()
111
+ self._cleanup_registered = False
112
+
113
+ # Apply disabled_tools to enabled_tools
114
+ final_enabled_tools = self.enabled_tools.copy()
115
+ for tool_name in self.disabled_tools:
116
+ final_enabled_tools[tool_name] = False
117
+
118
+ # Store the final processed tool configuration
119
+ self.enabled_tools = final_enabled_tools
103
120
 
104
121
  # Register all tools
105
122
  register_all_tools(
106
123
  mcp_server=self.mcp,
107
- document_context=self.document_context,
108
124
  permission_manager=self.permission_manager,
109
125
  agent_model=self.agent_model,
110
126
  agent_max_tokens=self.agent_max_tokens,
111
127
  agent_api_key=self.agent_api_key,
128
+ agent_base_url=self.agent_base_url,
112
129
  agent_max_iterations=self.agent_max_iterations,
113
130
  agent_max_tool_uses=self.agent_max_tool_uses,
114
131
  enable_agent_tool=self.enable_agent_tool,
115
132
  disable_write_tools=self.disable_write_tools,
116
133
  disable_search_tools=self.disable_search_tools,
134
+ enabled_tools=final_enabled_tools,
117
135
  )
118
136
 
137
+ register_all_prompts(mcp_server=self.mcp, projects=self.project_paths)
138
+
139
+ def _setup_cleanup_handlers(self) -> None:
140
+ """Set up signal handlers and background cleanup thread."""
141
+ if self._cleanup_registered:
142
+ return
143
+
144
+ # Register cleanup on normal exit
145
+ atexit.register(self._cleanup_sessions)
146
+
147
+ # Register signal handlers for graceful shutdown
148
+ def signal_handler(signum, frame):
149
+ self._cleanup_sessions()
150
+ self._shutdown_event.set()
151
+
152
+ signal.signal(signal.SIGTERM, signal_handler)
153
+ signal.signal(signal.SIGINT, signal_handler)
154
+
155
+ # Start background cleanup thread for periodic cleanup
156
+ self._cleanup_thread = threading.Thread(
157
+ target=self._background_cleanup, daemon=True
158
+ )
159
+ self._cleanup_thread.start()
160
+
161
+ self._cleanup_registered = True
162
+
163
+ def _background_cleanup(self) -> None:
164
+ """Background thread for periodic session cleanup."""
165
+ while not self._shutdown_event.is_set():
166
+ try:
167
+ # Clean up expired sessions every 2 minutes
168
+ # Using shorter TTL of 5 minutes (300 seconds)
169
+ SessionStorage.cleanup_expired_sessions(max_age_seconds=300)
170
+
171
+ # Wait for 2 minutes or until shutdown
172
+ self._shutdown_event.wait(timeout=120)
173
+ except Exception:
174
+ # Ignore cleanup errors and continue
175
+ pass
176
+
177
+ def _cleanup_sessions(self) -> None:
178
+ """Clean up all active sessions."""
179
+ try:
180
+ cleared_count = SessionStorage.clear_all_sessions()
181
+ if cleared_count > 0:
182
+ print(f"Cleaned up {cleared_count} tmux sessions on shutdown")
183
+ except Exception:
184
+ # Ignore cleanup errors during shutdown
185
+ pass
186
+
119
187
  def run(self, transport: str = "stdio", allowed_paths: list[str] | None = None):
120
188
  """Run the MCP server.
121
189
 
@@ -127,60 +195,10 @@ Includes improved error handling and debugging for tool execution.
127
195
  allowed_paths_list = allowed_paths or []
128
196
  for path in allowed_paths_list:
129
197
  self.permission_manager.add_allowed_path(path)
130
- self.document_context.add_allowed_path(path)
131
198
 
132
- # If using SSE, set the port and host in the environment variables
133
- if transport == "sse":
134
- import os
135
- # Set environment variables for FastMCP settings
136
- os.environ["FASTMCP_PORT"] = str(self.port)
137
- os.environ["FASTMCP_HOST"] = self.host
138
- print(f"Starting SSE server on {self.host}:{self.port}")
199
+ # Set up cleanup handlers before running
200
+ self._setup_cleanup_handlers()
139
201
 
140
202
  # Run the server
141
203
  transport_type = cast(Literal["stdio", "sse"], transport)
142
204
  self.mcp.run(transport=transport_type)
143
-
144
-
145
- def main():
146
- """Run the Hanzo MCP server."""
147
- import argparse
148
-
149
- parser = argparse.ArgumentParser(
150
- description="MCP server implementing Hanzo capabilities"
151
- )
152
-
153
- _ = parser.add_argument(
154
- "--name",
155
- default="claude-code",
156
- help="Name of the MCP server (default: claude-code)",
157
- )
158
-
159
- _ = parser.add_argument(
160
- "--transport",
161
- choices=["stdio", "sse"],
162
- default="stdio",
163
- help="Transport protocol to use (default: stdio)",
164
- )
165
-
166
- _ = parser.add_argument(
167
- "--allow-path",
168
- action="append",
169
- dest="allowed_paths",
170
- help="Add an allowed path (can be specified multiple times)",
171
- )
172
-
173
- args = parser.parse_args()
174
-
175
- # Type annotations for args to avoid Any warnings
176
- name: str = args.name
177
- transport: str = args.transport
178
- allowed_paths: list[str] | None = args.allowed_paths
179
-
180
- # Create and run the server
181
- server = HanzoServer(name=name, allowed_paths=allowed_paths)
182
- server.run(transport=transport, allowed_paths=allowed_paths or [])
183
-
184
-
185
- if __name__ == "__main__":
186
- main()
@@ -9,81 +9,154 @@ space for structured thinking. It also includes an "agent" tool that enables Cla
9
9
  to delegate tasks to sub-agents for concurrent execution and specialized processing.
10
10
  """
11
11
 
12
- from mcp.server.fastmcp import FastMCP
12
+ from fastmcp import FastMCP
13
13
 
14
14
  from hanzo_mcp.tools.agent import register_agent_tools
15
- from hanzo_mcp.tools.common import register_think_tool, register_version_tool
16
- from hanzo_mcp.tools.common.base import ToolRegistry # Added this import
17
- from hanzo_mcp.tools.common.context import DocumentContext
15
+ from hanzo_mcp.tools.common import register_batch_tool, register_thinking_tool
16
+ from hanzo_mcp.tools.common.base import BaseTool
17
+
18
18
  from hanzo_mcp.tools.common.permissions import PermissionManager
19
19
  from hanzo_mcp.tools.filesystem import register_filesystem_tools
20
20
  from hanzo_mcp.tools.jupyter import register_jupyter_tools
21
- from hanzo_mcp.tools.project import register_project_tools
22
21
  from hanzo_mcp.tools.shell import register_shell_tools
23
- from hanzo_mcp.tools.shell.command_executor import CommandExecutor
22
+ from hanzo_mcp.tools.todo import register_todo_tools
23
+ from hanzo_mcp.tools.vector import register_vector_tools
24
24
 
25
25
 
26
26
  def register_all_tools(
27
27
  mcp_server: FastMCP,
28
- document_context: DocumentContext,
29
28
  permission_manager: PermissionManager,
30
29
  agent_model: str | None = None,
31
30
  agent_max_tokens: int | None = None,
32
31
  agent_api_key: str | None = None,
32
+ agent_base_url: str | None = None,
33
33
  agent_max_iterations: int = 10,
34
34
  agent_max_tool_uses: int = 30,
35
35
  enable_agent_tool: bool = False,
36
36
  disable_write_tools: bool = False,
37
37
  disable_search_tools: bool = False,
38
+ enabled_tools: dict[str, bool] | None = None,
39
+ vector_config: dict | None = None,
38
40
  ) -> None:
39
41
  """Register all Hanzo tools with the MCP server.
40
42
 
41
43
  Args:
42
44
  mcp_server: The FastMCP server instance
43
- document_context: Document context for tracking file contents
44
45
  permission_manager: Permission manager for access control
45
46
  agent_model: Optional model name for agent tool in LiteLLM format
46
47
  agent_max_tokens: Optional maximum tokens for agent responses
47
48
  agent_api_key: Optional API key for the LLM provider
49
+ agent_base_url: Optional base URL for the LLM provider API endpoint
48
50
  agent_max_iterations: Maximum number of iterations for agent (default: 10)
49
51
  agent_max_tool_uses: Maximum number of total tool uses for agent (default: 30)
50
52
  enable_agent_tool: Whether to enable the agent tool (default: False)
51
- disable_write_tools: Whether to disable write/edit tools (default: False)
53
+ disable_write_tools: Whether to disable write tools (default: False)
52
54
  disable_search_tools: Whether to disable search tools (default: False)
55
+ enabled_tools: Dictionary of individual tool enable/disable states (default: None)
56
+ vector_config: Vector store configuration (default: None)
53
57
  """
54
- # Register all filesystem tools
55
- register_filesystem_tools(mcp_server, document_context, permission_manager, disable_write_tools, disable_search_tools)
56
-
57
- # Register all jupyter tools
58
- register_jupyter_tools(mcp_server, document_context, permission_manager, disable_write_tools)
59
-
60
- # Register shell tools
61
- register_shell_tools(mcp_server, permission_manager)
58
+ # Dictionary to store all registered tools
59
+ all_tools: dict[str, BaseTool] = {}
60
+
61
+ # Use individual tool configuration if provided, otherwise fall back to category-level flags
62
+ tool_config = enabled_tools or {}
63
+
64
+ def is_tool_enabled(tool_name: str, category_enabled: bool = True) -> bool:
65
+ """Check if a specific tool should be enabled."""
66
+ if tool_name in tool_config:
67
+ return tool_config[tool_name]
68
+ return category_enabled
62
69
 
63
- # Register project analysis tools
64
- register_project_tools(
70
+ # Register filesystem tools with individual configuration
71
+ filesystem_enabled = {
72
+ "read": is_tool_enabled("read", True),
73
+ "write": is_tool_enabled("write", not disable_write_tools),
74
+ "edit": is_tool_enabled("edit", not disable_write_tools),
75
+ "multi_edit": is_tool_enabled("multi_edit", not disable_write_tools),
76
+ "directory_tree": is_tool_enabled("directory_tree", True),
77
+ "grep": is_tool_enabled("grep", not disable_search_tools),
78
+ "grep_ast": is_tool_enabled("grep_ast", not disable_search_tools),
79
+ "content_replace": is_tool_enabled("content_replace", not disable_write_tools),
80
+ }
81
+
82
+ filesystem_tools = register_filesystem_tools(
65
83
  mcp_server,
66
84
  permission_manager,
67
- document_context,
68
- CommandExecutor(permission_manager)
85
+ enabled_tools=filesystem_enabled,
69
86
  )
87
+ for tool in filesystem_tools:
88
+ all_tools[tool.name] = tool
70
89
 
71
- # Register agent tools only if enabled
72
- if enable_agent_tool:
73
- register_agent_tools(
74
- mcp_server,
75
- document_context,
90
+ # Register jupyter tools if enabled
91
+ jupyter_enabled = {
92
+ "notebook_read": is_tool_enabled("notebook_read", True),
93
+ "notebook_edit": is_tool_enabled("notebook_edit", True),
94
+ }
95
+
96
+ if any(jupyter_enabled.values()):
97
+ jupyter_tools = register_jupyter_tools(mcp_server, permission_manager, enabled_tools=jupyter_enabled)
98
+ for tool in jupyter_tools:
99
+ all_tools[tool.name] = tool
100
+
101
+ # Register shell tools if enabled
102
+ if is_tool_enabled("run_command", True):
103
+ shell_tools = register_shell_tools(mcp_server, permission_manager)
104
+ for tool in shell_tools:
105
+ all_tools[tool.name] = tool
106
+
107
+ # Register agent tools if enabled
108
+ agent_enabled = enable_agent_tool or is_tool_enabled("dispatch_agent", False)
109
+ if agent_enabled:
110
+ agent_tools = register_agent_tools(
111
+ mcp_server,
76
112
  permission_manager,
77
- CommandExecutor(permission_manager),
78
113
  agent_model=agent_model,
79
114
  agent_max_tokens=agent_max_tokens,
80
115
  agent_api_key=agent_api_key,
116
+ agent_base_url=agent_base_url,
81
117
  agent_max_iterations=agent_max_iterations,
82
- agent_max_tool_uses=agent_max_tool_uses
118
+ agent_max_tool_uses=agent_max_tool_uses,
83
119
  )
120
+ for tool in agent_tools:
121
+ all_tools[tool.name] = tool
122
+
123
+ # Register todo tools if enabled
124
+ todo_enabled = {
125
+ "todo_read": is_tool_enabled("todo_read", True),
126
+ "todo_write": is_tool_enabled("todo_write", True),
127
+ }
84
128
 
85
- # Initialize and register thinking tool
86
- register_think_tool(mcp_server)
129
+ if any(todo_enabled.values()):
130
+ todo_tools = register_todo_tools(mcp_server, enabled_tools=todo_enabled)
131
+ for tool in todo_tools:
132
+ all_tools[tool.name] = tool
133
+
134
+ # Register thinking tool if enabled
135
+ if is_tool_enabled("think", True):
136
+ thinking_tool = register_thinking_tool(mcp_server)
137
+ for tool in thinking_tool:
138
+ all_tools[tool.name] = tool
139
+
140
+ # Register vector tools if enabled
141
+ vector_enabled = {
142
+ "vector_index": is_tool_enabled("vector_index", False),
143
+ "vector_search": is_tool_enabled("vector_search", False),
144
+ }
87
145
 
88
- # Register version tool
89
- register_version_tool(mcp_server)
146
+ if any(vector_enabled.values()) and vector_config:
147
+ # Get allowed paths for project detection
148
+ search_paths = [str(path) for path in permission_manager.allowed_paths]
149
+
150
+ vector_tools = register_vector_tools(
151
+ mcp_server,
152
+ permission_manager,
153
+ vector_config=vector_config,
154
+ enabled_tools=vector_enabled,
155
+ search_paths=search_paths,
156
+ )
157
+ for tool in vector_tools:
158
+ all_tools[tool.name] = tool
159
+
160
+ # Register batch tool if enabled (batch tool is typically always enabled)
161
+ if is_tool_enabled("batch", True):
162
+ register_batch_tool(mcp_server, all_tools)
@@ -4,23 +4,21 @@ This module provides tools that allow Claude to delegate tasks to sub-agents,
4
4
  enabling concurrent execution of multiple operations and specialized processing.
5
5
  """
6
6
 
7
- from mcp.server.fastmcp import FastMCP
7
+ from fastmcp import FastMCP
8
8
 
9
9
  from hanzo_mcp.tools.agent.agent_tool import AgentTool
10
- from hanzo_mcp.tools.common.base import BaseTool, ToolRegistry
11
- from hanzo_mcp.tools.common.context import DocumentContext
10
+ from hanzo_mcp.tools.common.base import BaseTool, ToolRegistry
11
+
12
12
  from hanzo_mcp.tools.common.permissions import PermissionManager
13
- from hanzo_mcp.tools.shell.command_executor import CommandExecutor
14
13
 
15
14
 
16
15
  def register_agent_tools(
17
16
  mcp_server: FastMCP,
18
- document_context: DocumentContext,
19
17
  permission_manager: PermissionManager,
20
- command_executor: CommandExecutor,
21
18
  agent_model: str | None = None,
22
19
  agent_max_tokens: int | None = None,
23
20
  agent_api_key: str | None = None,
21
+ agent_base_url: str | None = None,
24
22
  agent_max_iterations: int = 10,
25
23
  agent_max_tool_uses: int = 30,
26
24
  ) -> list[BaseTool]:
@@ -28,12 +26,12 @@ def register_agent_tools(
28
26
 
29
27
  Args:
30
28
  mcp_server: The FastMCP server instance
31
- document_context: Document context for tracking file contents
29
+
32
30
  permission_manager: Permission manager for access control
33
- command_executor: Command executor for running shell commands
34
31
  agent_model: Optional model name for agent tool in LiteLLM format
35
32
  agent_max_tokens: Optional maximum tokens for agent responses
36
33
  agent_api_key: Optional API key for the LLM provider
34
+ agent_base_url: Optional base URL for the LLM provider API endpoint
37
35
  agent_max_iterations: Maximum number of iterations for agent (default: 10)
38
36
  agent_max_tool_uses: Maximum number of total tool uses for agent (default: 30)
39
37
 
@@ -42,14 +40,13 @@ def register_agent_tools(
42
40
  """
43
41
  # Create agent tool
44
42
  agent_tool = AgentTool(
45
- document_context=document_context,
46
43
  permission_manager=permission_manager,
47
- command_executor=command_executor,
48
44
  model=agent_model,
49
45
  api_key=agent_api_key,
46
+ base_url=agent_base_url,
50
47
  max_tokens=agent_max_tokens,
51
48
  max_iterations=agent_max_iterations,
52
- max_tool_uses=agent_max_tool_uses
49
+ max_tool_uses=agent_max_tool_uses,
53
50
  )
54
51
 
55
52
  # Register agent tool