hanzo-mcp 0.3.4__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 +123 -160
  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 +120 -98
  14. hanzo_mcp/tools/__init__.py +107 -31
  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 -41
  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.4.dist-info → hanzo_mcp-0.5.0.dist-info}/METADATA +35 -3
  59. hanzo_mcp-0.5.0.dist-info/RECORD +63 -0
  60. {hanzo_mcp-0.3.4.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 -198
  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 -882
  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.4.dist-info/RECORD +0 -53
  85. {hanzo_mcp-0.3.4.dist-info → hanzo_mcp-0.5.0.dist-info}/entry_points.txt +0 -0
  86. {hanzo_mcp-0.3.4.dist-info → hanzo_mcp-0.5.0.dist-info}/licenses/LICENSE +0 -0
  87. {hanzo_mcp-0.3.4.dist-info → hanzo_mcp-0.5.0.dist-info}/top_level.txt +0 -0
hanzo_mcp/server.py CHANGED
@@ -1,117 +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
- host: str = "0.0.0.0",
38
- port: int = 3001,
38
+ disable_search_tools: bool = False,
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,
39
43
  ):
40
- """Initialize the Hanzo server.
44
+ """Initialize the Hanzo MCP server.
41
45
 
42
46
  Args:
43
47
  name: The name of the server
44
48
  allowed_paths: list of paths that the server is allowed to access
45
- 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)
46
51
  mcp_instance: Optional FastMCP instance for testing
47
52
  agent_model: Optional model name for agent tool in LiteLLM format
48
53
  agent_max_tokens: Optional maximum tokens for agent responses
49
54
  agent_api_key: Optional API key for the LLM provider
55
+ agent_base_url: Optional base URL for the LLM provider API endpoint
50
56
  agent_max_iterations: Maximum number of iterations for agent (default: 10)
51
57
  agent_max_tool_uses: Maximum number of total tool uses for agent (default: 30)
52
58
  enable_agent_tool: Whether to enable the agent tool (default: False)
53
- disable_write_tools: Whether to disable write/edit tools (default: False)
54
- host: Host to bind to for SSE transport (default: '0.0.0.0')
55
- port: Port to use for SSE transport (default: 3001)
59
+ command_timeout: Default timeout for command execution in seconds (default: 120.0)
60
+ disable_write_tools: Whether to disable write tools (default: False)
61
+ disable_search_tools: Whether to disable search tools (default: False)
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)
56
66
  """
57
67
  self.mcp = mcp_instance if mcp_instance is not None else FastMCP(name)
58
68
 
59
- # Initialize context, permissions, and command executor
60
- self.document_context = DocumentContext()
69
+ # Initialize permissions and command executor
61
70
  self.permission_manager = PermissionManager()
62
71
 
63
- # Initialize command executor
64
- self.command_executor = CommandExecutor(
65
- permission_manager=self.permission_manager,
66
- verbose=False, # Set to True for debugging
67
- )
68
-
69
- # If project_dir is specified, set it as initial working directory for all sessions
72
+ # Handle project_dir parameter
70
73
  if project_dir:
71
- initial_session_id = name # Use server name as default session ID
72
- self.command_executor.set_working_dir(initial_session_id, project_dir)
73
-
74
- # Initialize project analyzer
75
- self.project_analyzer = ProjectAnalyzer(self.command_executor)
76
-
77
- # Initialize project manager
78
- self.project_manager = ProjectManager(
79
- self.document_context, self.permission_manager, self.project_analyzer
80
- )
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)
81
82
 
82
83
  # Add allowed paths
83
84
  if allowed_paths:
84
85
  for path in allowed_paths:
85
86
  self.permission_manager.add_allowed_path(path)
86
- 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 []
87
97
 
88
98
  # Store agent options
89
99
  self.agent_model = agent_model
90
100
  self.agent_max_tokens = agent_max_tokens
91
101
  self.agent_api_key = agent_api_key
102
+ self.agent_base_url = agent_base_url
92
103
  self.agent_max_iterations = agent_max_iterations
93
104
  self.agent_max_tool_uses = agent_max_tool_uses
94
105
  self.enable_agent_tool = enable_agent_tool
95
- self.disable_write_tools = disable_write_tools
106
+ self.command_timeout = command_timeout
96
107
 
97
- # Store network options
98
- self.host = host
99
- 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
100
120
 
101
121
  # Register all tools
102
122
  register_all_tools(
103
123
  mcp_server=self.mcp,
104
- document_context=self.document_context,
105
124
  permission_manager=self.permission_manager,
106
125
  agent_model=self.agent_model,
107
126
  agent_max_tokens=self.agent_max_tokens,
108
127
  agent_api_key=self.agent_api_key,
128
+ agent_base_url=self.agent_base_url,
109
129
  agent_max_iterations=self.agent_max_iterations,
110
130
  agent_max_tool_uses=self.agent_max_tool_uses,
111
131
  enable_agent_tool=self.enable_agent_tool,
112
132
  disable_write_tools=self.disable_write_tools,
133
+ disable_search_tools=self.disable_search_tools,
134
+ enabled_tools=final_enabled_tools,
113
135
  )
114
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
+
115
187
  def run(self, transport: str = "stdio", allowed_paths: list[str] | None = None):
116
188
  """Run the MCP server.
117
189
 
@@ -123,60 +195,10 @@ Includes improved error handling and debugging for tool execution.
123
195
  allowed_paths_list = allowed_paths or []
124
196
  for path in allowed_paths_list:
125
197
  self.permission_manager.add_allowed_path(path)
126
- self.document_context.add_allowed_path(path)
127
198
 
128
- # If using SSE, set the port and host in the environment variables
129
- if transport == "sse":
130
- import os
131
- # Set environment variables for FastMCP settings
132
- os.environ["FASTMCP_PORT"] = str(self.port)
133
- os.environ["FASTMCP_HOST"] = self.host
134
- print(f"Starting SSE server on {self.host}:{self.port}")
199
+ # Set up cleanup handlers before running
200
+ self._setup_cleanup_handlers()
135
201
 
136
202
  # Run the server
137
203
  transport_type = cast(Literal["stdio", "sse"], transport)
138
204
  self.mcp.run(transport=transport_type)
139
-
140
-
141
- def main():
142
- """Run the Hanzo MCP server."""
143
- import argparse
144
-
145
- parser = argparse.ArgumentParser(
146
- description="MCP server implementing Hanzo capabilities"
147
- )
148
-
149
- _ = parser.add_argument(
150
- "--name",
151
- default="claude-code",
152
- help="Name of the MCP server (default: claude-code)",
153
- )
154
-
155
- _ = parser.add_argument(
156
- "--transport",
157
- choices=["stdio", "sse"],
158
- default="stdio",
159
- help="Transport protocol to use (default: stdio)",
160
- )
161
-
162
- _ = parser.add_argument(
163
- "--allow-path",
164
- action="append",
165
- dest="allowed_paths",
166
- help="Add an allowed path (can be specified multiple times)",
167
- )
168
-
169
- args = parser.parse_args()
170
-
171
- # Type annotations for args to avoid Any warnings
172
- name: str = args.name
173
- transport: str = args.transport
174
- allowed_paths: list[str] | None = args.allowed_paths
175
-
176
- # Create and run the server
177
- server = HanzoServer(name=name, allowed_paths=allowed_paths)
178
- server.run(transport=transport, allowed_paths=allowed_paths or [])
179
-
180
-
181
- if __name__ == "__main__":
182
- main()
@@ -9,78 +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.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
+
17
18
  from hanzo_mcp.tools.common.permissions import PermissionManager
18
19
  from hanzo_mcp.tools.filesystem import register_filesystem_tools
19
20
  from hanzo_mcp.tools.jupyter import register_jupyter_tools
20
- from hanzo_mcp.tools.project import register_project_tools
21
21
  from hanzo_mcp.tools.shell import register_shell_tools
22
- 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
23
24
 
24
25
 
25
26
  def register_all_tools(
26
27
  mcp_server: FastMCP,
27
- document_context: DocumentContext,
28
28
  permission_manager: PermissionManager,
29
29
  agent_model: str | None = None,
30
30
  agent_max_tokens: int | None = None,
31
31
  agent_api_key: str | None = None,
32
+ agent_base_url: str | None = None,
32
33
  agent_max_iterations: int = 10,
33
34
  agent_max_tool_uses: int = 30,
34
35
  enable_agent_tool: bool = False,
35
36
  disable_write_tools: bool = False,
37
+ disable_search_tools: bool = False,
38
+ enabled_tools: dict[str, bool] | None = None,
39
+ vector_config: dict | None = None,
36
40
  ) -> None:
37
41
  """Register all Hanzo tools with the MCP server.
38
42
 
39
43
  Args:
40
44
  mcp_server: The FastMCP server instance
41
- document_context: Document context for tracking file contents
42
45
  permission_manager: Permission manager for access control
43
46
  agent_model: Optional model name for agent tool in LiteLLM format
44
47
  agent_max_tokens: Optional maximum tokens for agent responses
45
48
  agent_api_key: Optional API key for the LLM provider
49
+ agent_base_url: Optional base URL for the LLM provider API endpoint
46
50
  agent_max_iterations: Maximum number of iterations for agent (default: 10)
47
51
  agent_max_tool_uses: Maximum number of total tool uses for agent (default: 30)
48
52
  enable_agent_tool: Whether to enable the agent tool (default: False)
49
- disable_write_tools: Whether to disable write/edit tools (default: False)
53
+ disable_write_tools: Whether to disable write tools (default: False)
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)
50
57
  """
51
- # Register all filesystem tools
52
- register_filesystem_tools(mcp_server, document_context, permission_manager, disable_write_tools)
53
-
54
- # Register all jupyter tools
55
- register_jupyter_tools(mcp_server, document_context, permission_manager, disable_write_tools)
56
-
57
- # Register shell tools
58
- 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
59
69
 
60
- # Register project analysis tools
61
- 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(
62
83
  mcp_server,
63
84
  permission_manager,
64
- document_context,
65
- CommandExecutor(permission_manager)
85
+ enabled_tools=filesystem_enabled,
66
86
  )
87
+ for tool in filesystem_tools:
88
+ all_tools[tool.name] = tool
67
89
 
68
- # Register agent tools only if enabled
69
- if enable_agent_tool:
70
- register_agent_tools(
71
- mcp_server,
72
- 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,
73
112
  permission_manager,
74
- CommandExecutor(permission_manager),
75
113
  agent_model=agent_model,
76
114
  agent_max_tokens=agent_max_tokens,
77
115
  agent_api_key=agent_api_key,
116
+ agent_base_url=agent_base_url,
78
117
  agent_max_iterations=agent_max_iterations,
79
- agent_max_tool_uses=agent_max_tool_uses
118
+ agent_max_tool_uses=agent_max_tool_uses,
80
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
+ }
81
128
 
82
- # Initialize and register thinking tool
83
- 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
+ }
84
145
 
85
- # Register version tool
86
- 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