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
@@ -3,21 +3,17 @@
3
3
  This package provides tools for executing shell commands and scripts.
4
4
  """
5
5
 
6
- from mcp.server.fastmcp import FastMCP
6
+ import shutil
7
+
8
+ from fastmcp import FastMCP
7
9
 
8
10
  from hanzo_mcp.tools.common.base import BaseTool, ToolRegistry
9
11
  from hanzo_mcp.tools.common.permissions import PermissionManager
12
+ from hanzo_mcp.tools.shell.bash_session_executor import BashSessionExecutor
10
13
  from hanzo_mcp.tools.shell.command_executor import CommandExecutor
11
- from hanzo_mcp.tools.shell.run_command import RunCommandTool
12
- from hanzo_mcp.tools.shell.run_script import RunScriptTool
13
- from hanzo_mcp.tools.shell.script_tool import ScriptTool
14
14
 
15
15
  # Export all tool classes
16
16
  __all__ = [
17
- "RunCommandTool",
18
- "RunScriptTool",
19
- "ScriptTool",
20
- "CommandExecutor",
21
17
  "get_shell_tools",
22
18
  "register_shell_tools",
23
19
  ]
@@ -27,32 +23,45 @@ def get_shell_tools(
27
23
  permission_manager: PermissionManager,
28
24
  ) -> list[BaseTool]:
29
25
  """Create instances of all shell tools.
30
-
26
+
31
27
  Args:
32
28
  permission_manager: Permission manager for access control
33
-
29
+
34
30
  Returns:
35
31
  List of shell tool instances
36
32
  """
37
- # Initialize the command executor
38
- command_executor = CommandExecutor(permission_manager)
39
-
40
- return [
41
- RunCommandTool(permission_manager, command_executor),
42
- RunScriptTool(permission_manager, command_executor),
43
- ScriptTool(permission_manager, command_executor),
44
- ]
33
+ # Detect tmux availability and choose appropriate implementation
34
+ if shutil.which("tmux") is not None:
35
+ # Use tmux-based implementation for interactive sessions
36
+ from hanzo_mcp.tools.shell.run_command import RunCommandTool
37
+
38
+ command_executor = BashSessionExecutor(permission_manager)
39
+ return [
40
+ RunCommandTool(permission_manager, command_executor),
41
+ ]
42
+ else:
43
+ # Use Windows-compatible implementation
44
+ from hanzo_mcp.tools.shell.run_command_windows import RunCommandTool
45
+
46
+ command_executor = CommandExecutor(permission_manager)
47
+ return [
48
+ RunCommandTool(permission_manager, command_executor),
49
+ ]
45
50
 
46
51
 
47
52
  def register_shell_tools(
48
53
  mcp_server: FastMCP,
49
54
  permission_manager: PermissionManager,
50
- ) -> None:
55
+ ) -> list[BaseTool]:
51
56
  """Register all shell tools with the MCP server.
52
-
57
+
53
58
  Args:
54
59
  mcp_server: The FastMCP server instance
55
60
  permission_manager: Permission manager for access control
61
+
62
+ Returns:
63
+ List of registered tools
56
64
  """
57
65
  tools = get_shell_tools(permission_manager)
58
66
  ToolRegistry.register_tools(mcp_server, tools)
67
+ return tools
@@ -5,19 +5,27 @@ including command execution, script running, and process management.
5
5
  """
6
6
 
7
7
  from abc import ABC, abstractmethod
8
- from typing import Any, final
9
- from typing_extensions import override
8
+ from enum import Enum
9
+ from typing import Any, Self, final
10
10
 
11
- from mcp.server.fastmcp import Context as MCPContext
12
- from mcp.server.fastmcp import FastMCP
11
+ from fastmcp import Context as MCPContext
13
12
 
14
13
  from hanzo_mcp.tools.common.base import BaseTool
15
14
  from hanzo_mcp.tools.common.permissions import PermissionManager
16
15
 
17
16
 
17
+ class BashCommandStatus(Enum):
18
+ """Status of bash command execution."""
19
+
20
+ CONTINUE = "continue"
21
+ COMPLETED = "completed"
22
+ NO_CHANGE_TIMEOUT = "no_change_timeout"
23
+ HARD_TIMEOUT = "hard_timeout"
24
+
25
+
18
26
  @final
19
27
  class CommandResult:
20
- """Represents the result of a command execution."""
28
+ """Represents the result of a command execution with rich metadata."""
21
29
 
22
30
  def __init__(
23
31
  self,
@@ -25,6 +33,9 @@ class CommandResult:
25
33
  stdout: str = "",
26
34
  stderr: str = "",
27
35
  error_message: str | None = None,
36
+ session_id: str | None = None,
37
+ status: BashCommandStatus = BashCommandStatus.COMPLETED,
38
+ command: str = "",
28
39
  ):
29
40
  """Initialize a command result.
30
41
 
@@ -33,11 +44,17 @@ class CommandResult:
33
44
  stdout: Standard output from the command
34
45
  stderr: Standard error from the command
35
46
  error_message: Optional error message for failure cases
47
+ session_id: Optional session ID used for the command execution
48
+ status: Command execution status
49
+ command: The original command that was executed
36
50
  """
37
51
  self.return_code: int = return_code
38
52
  self.stdout: str = stdout
39
53
  self.stderr: str = stderr
40
54
  self.error_message: str | None = error_message
55
+ self.session_id: str | None = session_id
56
+ self.status: BashCommandStatus = status
57
+ self.command: str = command
41
58
 
42
59
  @property
43
60
  def is_success(self) -> bool:
@@ -46,7 +63,41 @@ class CommandResult:
46
63
  Returns:
47
64
  True if the command succeeded, False otherwise
48
65
  """
49
- return self.return_code == 0
66
+ return (
67
+ self.return_code == 0
68
+ and self.status == BashCommandStatus.COMPLETED
69
+ and not self.error_message
70
+ )
71
+
72
+ @property
73
+ def is_running(self) -> bool:
74
+ """Check if the command is still running.
75
+
76
+ Returns:
77
+ True if the command is still running, False otherwise
78
+ """
79
+ return self.status in {
80
+ BashCommandStatus.CONTINUE,
81
+ BashCommandStatus.NO_CHANGE_TIMEOUT,
82
+ BashCommandStatus.HARD_TIMEOUT,
83
+ }
84
+
85
+ @property
86
+ def exit_code(self) -> int:
87
+ """Get the exit code (alias for return_code for compatibility)."""
88
+ return self.return_code
89
+
90
+ @property
91
+ def error(self) -> bool:
92
+ """Check if there was an error."""
93
+ return not self.is_success
94
+
95
+ @property
96
+ def message(self) -> str:
97
+ """Get a human-readable message about the command result."""
98
+ if self.error_message:
99
+ return f"Command `{self.command}` failed: {self.error_message}"
100
+ return f"Command `{self.command}` executed with exit code {self.return_code}."
50
101
 
51
102
  def format_output(self, include_exit_code: bool = True) -> str:
52
103
  """Format the command output as a string.
@@ -59,6 +110,14 @@ class CommandResult:
59
110
  """
60
111
  result_parts: list[str] = []
61
112
 
113
+ # Add session ID if present
114
+ if self.session_id:
115
+ result_parts.append(f"Session ID: {self.session_id}")
116
+
117
+ # Add command status
118
+ if self.status != BashCommandStatus.COMPLETED:
119
+ result_parts.append(f"Status: {self.status.value}")
120
+
62
121
  # Add error message if present
63
122
  if self.error_message:
64
123
  result_parts.append(f"Error: {self.error_message}")
@@ -78,71 +137,54 @@ class CommandResult:
78
137
  # Join with newlines
79
138
  return "\n\n".join(result_parts)
80
139
 
140
+ def to_agent_observation(self) -> str:
141
+ """Format the result for agent consumption."""
142
+ content = self.stdout
143
+
144
+ additional_info: list[str] = []
145
+ if self.session_id:
146
+ additional_info.append(f"[Session ID: {self.session_id}]")
147
+
148
+ if additional_info:
149
+ content += "\n" + "\n".join(additional_info)
150
+
151
+ return content
152
+
81
153
 
82
154
  class ShellBaseTool(BaseTool, ABC):
83
155
  """Base class for shell-related tools.
84
-
156
+
85
157
  Provides common functionality for executing commands and scripts,
86
158
  including permissions checking.
87
159
  """
88
-
160
+
89
161
  def __init__(self, permission_manager: PermissionManager) -> None:
90
162
  """Initialize the shell base tool.
91
-
163
+
92
164
  Args:
93
165
  permission_manager: Permission manager for access control
94
166
  """
95
167
  self.permission_manager: PermissionManager = permission_manager
96
-
168
+
97
169
  def is_path_allowed(self, path: str) -> bool:
98
170
  """Check if a path is allowed according to permission settings.
99
-
171
+
100
172
  Args:
101
173
  path: Path to check
102
-
174
+
103
175
  Returns:
104
176
  True if the path is allowed, False otherwise
105
177
  """
106
178
  return self.permission_manager.is_path_allowed(path)
107
-
179
+
108
180
  @abstractmethod
109
181
  async def prepare_tool_context(self, ctx: MCPContext) -> Any:
110
182
  """Create and prepare the tool context.
111
-
183
+
112
184
  Args:
113
185
  ctx: MCP context
114
-
186
+
115
187
  Returns:
116
188
  Prepared tool context
117
189
  """
118
190
  pass
119
-
120
- @override
121
- def register(self, mcp_server: FastMCP) -> None:
122
- """Register this shell tool with the MCP server.
123
-
124
- This provides a default implementation that derived classes should override
125
- with more specific parameter definitions. This implementation uses generic
126
- **kwargs which doesn't provide proper parameter definitions to MCP.
127
-
128
- Args:
129
- mcp_server: The FastMCP server instance
130
- """
131
- tool_self = self # Create a reference to self for use in the closure
132
-
133
- # Each derived class should override this with a more specific signature
134
- # that explicitly defines the parameters expected by the tool
135
- @mcp_server.tool(name=self.name, description=self.mcp_description)
136
- async def generic_wrapper(**kwargs: Any) -> str:
137
- """Generic wrapper for shell tool.
138
-
139
- This wrapper should be overridden by derived classes to provide
140
- explicit parameter definitions.
141
-
142
- Returns:
143
- Tool execution result
144
- """
145
- # Extract context from kwargs
146
- ctx = kwargs.pop("ctx")
147
- # Call the actual tool implementation
148
- return await tool_self.call(ctx, **kwargs)