hanzo-mcp 0.1.21__py3-none-any.whl → 0.1.25__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.
- hanzo_mcp/__init__.py +1 -1
- hanzo_mcp/cli.py +3 -3
- hanzo_mcp/server.py +3 -3
- hanzo_mcp/tools/common/__init__.py +1 -1
- hanzo_mcp/tools/common/context.py +2 -2
- hanzo_mcp/tools/common/permissions.py +120 -60
- hanzo_mcp/tools/common/validation.py +1 -1
- hanzo_mcp/tools/filesystem/__init__.py +1 -1
- hanzo_mcp/tools/filesystem/file_operations.py +2 -2
- hanzo_mcp/tools/jupyter/__init__.py +1 -1
- hanzo_mcp/tools/jupyter/notebook_operations.py +1 -1
- hanzo_mcp/tools/project/__init__.py +1 -1
- hanzo_mcp/tools/project/analysis.py +5 -5
- hanzo_mcp/tools/shell/__init__.py +1 -1
- hanzo_mcp/tools/shell/command_executor.py +10 -10
- {hanzo_mcp-0.1.21.dist-info → hanzo_mcp-0.1.25.dist-info}/METADATA +2 -2
- hanzo_mcp-0.1.25.dist-info/RECORD +24 -0
- {hanzo_mcp-0.1.21.dist-info → hanzo_mcp-0.1.25.dist-info}/WHEEL +1 -1
- hanzo_mcp-0.1.25.dist-info/zip-safe +1 -0
- hanzo_mcp-0.1.21.dist-info/RECORD +0 -23
- {hanzo_mcp-0.1.21.dist-info → hanzo_mcp-0.1.25.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.1.21.dist-info → hanzo_mcp-0.1.25.dist-info}/licenses/LICENSE +0 -0
- {hanzo_mcp-0.1.21.dist-info → hanzo_mcp-0.1.25.dist-info}/top_level.txt +0 -0
hanzo_mcp/__init__.py
CHANGED
hanzo_mcp/cli.py
CHANGED
|
@@ -7,11 +7,11 @@ import sys
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any, cast
|
|
9
9
|
|
|
10
|
-
from hanzo_mcp.server import
|
|
10
|
+
from hanzo_mcp.server import HanzoMCPServer
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def main() -> None:
|
|
14
|
-
"""Run the CLI for the Hanzo
|
|
14
|
+
"""Run the CLI for the Hanzo MCP server."""
|
|
15
15
|
parser = argparse.ArgumentParser(
|
|
16
16
|
description="MCP server for accessing Hanzo APIs and Platform capabilities"
|
|
17
17
|
)
|
|
@@ -70,7 +70,7 @@ def main() -> None:
|
|
|
70
70
|
allowed_paths.append(project_dir)
|
|
71
71
|
|
|
72
72
|
# Run the server
|
|
73
|
-
server =
|
|
73
|
+
server = HanzoMCPServer(name=name, allowed_paths=allowed_paths)
|
|
74
74
|
# Transport will be automatically cast to Literal['stdio', 'sse'] by the server
|
|
75
75
|
server.run(transport=transport)
|
|
76
76
|
|
hanzo_mcp/server.py
CHANGED
|
@@ -12,7 +12,7 @@ from hanzo_mcp.tools.shell.command_executor import CommandExecutor
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
@final
|
|
15
|
-
class
|
|
15
|
+
class HanzoMCPServer:
|
|
16
16
|
"""MCP server for accessing Hanzo APIs and Platform capabilities."""
|
|
17
17
|
|
|
18
18
|
def __init__(
|
|
@@ -21,7 +21,7 @@ class HanzoDevServer:
|
|
|
21
21
|
allowed_paths: list[str] | None = None,
|
|
22
22
|
mcp_instance: FastMCP | None = None,
|
|
23
23
|
):
|
|
24
|
-
"""Initialize the Hanzo
|
|
24
|
+
"""Initialize the Hanzo server.
|
|
25
25
|
|
|
26
26
|
Args:
|
|
27
27
|
name: The name of the server
|
|
@@ -117,7 +117,7 @@ def main():
|
|
|
117
117
|
allowed_paths: list[str] | None = args.allowed_paths
|
|
118
118
|
|
|
119
119
|
# Create and run the server
|
|
120
|
-
server =
|
|
120
|
+
server = HanzoMCPServer(name=name, allowed_paths=allowed_paths)
|
|
121
121
|
server.run(transport=transport, allowed_paths=allowed_paths or [])
|
|
122
122
|
|
|
123
123
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"""Common utilities for Hanzo
|
|
1
|
+
"""Common utilities for Hanzo MCP tools."""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Enhanced Context for Hanzo
|
|
1
|
+
"""Enhanced Context for Hanzo MCP tools.
|
|
2
2
|
|
|
3
3
|
This module provides an enhanced Context class that wraps the MCP Context
|
|
4
4
|
and adds additional functionality specific to Claude Code tools.
|
|
@@ -17,7 +17,7 @@ from mcp.server.lowlevel.helper_types import ReadResourceContents
|
|
|
17
17
|
|
|
18
18
|
@final
|
|
19
19
|
class ToolContext:
|
|
20
|
-
"""Enhanced context for Hanzo
|
|
20
|
+
"""Enhanced context for Hanzo MCP tools.
|
|
21
21
|
|
|
22
22
|
This class wraps the MCP Context and adds additional functionality
|
|
23
23
|
for tracking tool execution, progress reporting, and resource access.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Permission system for the Hanzo
|
|
1
|
+
"""Permission system for the Hanzo MCP server."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
@@ -11,29 +11,65 @@ T = TypeVar("T")
|
|
|
11
11
|
P = TypeVar("P")
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
def normalize_path(path: str) -> Path:
|
|
15
|
+
"""Normalize a path with proper user directory expansion.
|
|
16
|
+
|
|
17
|
+
This utility function handles path normalization with proper handling of
|
|
18
|
+
tilde (~) for home directory expansion and ensures consistent path handling
|
|
19
|
+
across the application.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
path: The path to normalize (can include ~ for home directory)
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
A normalized Path object with user directories expanded and resolved to
|
|
26
|
+
its absolute canonical form.
|
|
27
|
+
"""
|
|
28
|
+
# Expand the user directory, handling the tilde (~) if present.
|
|
29
|
+
expanded_path = os.path.expanduser(path)
|
|
30
|
+
# Resolve the expanded path to its absolute form.
|
|
31
|
+
resolved_path = Path(expanded_path).resolve()
|
|
32
|
+
return resolved_path
|
|
33
|
+
|
|
34
|
+
|
|
14
35
|
@final
|
|
15
36
|
class PermissionManager:
|
|
16
|
-
"""Manages permissions for file and command operations.
|
|
37
|
+
"""Manages permissions for file and command operations.
|
|
38
|
+
|
|
39
|
+
This class is responsible for tracking allowed file system paths as well as
|
|
40
|
+
paths and patterns that should be excluded from permitted operations.
|
|
41
|
+
"""
|
|
17
42
|
|
|
18
43
|
def __init__(self) -> None:
|
|
19
|
-
"""Initialize the permission manager.
|
|
20
|
-
|
|
44
|
+
"""Initialize the permission manager with default allowed and excluded paths.
|
|
45
|
+
|
|
46
|
+
Allowed paths are those where operations (read, write, execute, etc.) are permitted,
|
|
47
|
+
while excluded paths and patterns represent paths and file patterns that are sensitive
|
|
48
|
+
and should be disallowed.
|
|
49
|
+
"""
|
|
50
|
+
# Allowed paths: operations are permitted on these paths.
|
|
21
51
|
self.allowed_paths: set[Path] = set(
|
|
22
52
|
[Path("/tmp").resolve(), Path("/var").resolve()]
|
|
23
53
|
)
|
|
24
54
|
|
|
25
|
-
# Excluded paths
|
|
55
|
+
# Excluded paths: specific paths that are explicitly disallowed.
|
|
26
56
|
self.excluded_paths: set[Path] = set()
|
|
57
|
+
|
|
58
|
+
# Excluded patterns: patterns for sensitive directories and file names.
|
|
27
59
|
self.excluded_patterns: list[str] = []
|
|
28
60
|
|
|
29
|
-
#
|
|
61
|
+
# Add default exclusions for sensitive files and directories.
|
|
30
62
|
self._add_default_exclusions()
|
|
31
63
|
|
|
32
64
|
def _add_default_exclusions(self) -> None:
|
|
33
|
-
"""Add default exclusions for sensitive files and directories.
|
|
34
|
-
|
|
65
|
+
"""Add default exclusions for sensitive files and directories.
|
|
66
|
+
|
|
67
|
+
This method populates the excluded_patterns list with common sensitive
|
|
68
|
+
directories (e.g., .ssh, .gnupg) and file patterns (e.g., *.key, *.log)
|
|
69
|
+
that should be excluded from allowed operations.
|
|
70
|
+
"""
|
|
71
|
+
# Sensitive directories (Note: .git is allowed by default)
|
|
35
72
|
sensitive_dirs: list[str] = [
|
|
36
|
-
# ".git" is now allowed by default
|
|
37
73
|
".ssh",
|
|
38
74
|
".gnupg",
|
|
39
75
|
".config",
|
|
@@ -64,59 +100,64 @@ class PermissionManager:
|
|
|
64
100
|
self.excluded_patterns.extend(sensitive_patterns)
|
|
65
101
|
|
|
66
102
|
def add_allowed_path(self, path: str) -> None:
|
|
67
|
-
"""Add a path to the allowed paths.
|
|
103
|
+
"""Add a new path to the allowed paths.
|
|
68
104
|
|
|
69
105
|
Args:
|
|
70
|
-
path: The path to
|
|
106
|
+
path: The file system path to add to the allowed list.
|
|
71
107
|
"""
|
|
72
|
-
resolved_path: Path =
|
|
108
|
+
resolved_path: Path = normalize_path(path)
|
|
73
109
|
self.allowed_paths.add(resolved_path)
|
|
74
110
|
|
|
75
111
|
def remove_allowed_path(self, path: str) -> None:
|
|
76
112
|
"""Remove a path from the allowed paths.
|
|
77
113
|
|
|
78
114
|
Args:
|
|
79
|
-
path: The path to remove
|
|
115
|
+
path: The file system path to remove from the allowed list.
|
|
80
116
|
"""
|
|
81
|
-
resolved_path: Path =
|
|
117
|
+
resolved_path: Path = normalize_path(path)
|
|
82
118
|
if resolved_path in self.allowed_paths:
|
|
83
119
|
self.allowed_paths.remove(resolved_path)
|
|
84
120
|
|
|
85
121
|
def exclude_path(self, path: str) -> None:
|
|
86
|
-
"""
|
|
122
|
+
"""Add a path to the exclusion list.
|
|
87
123
|
|
|
88
124
|
Args:
|
|
89
|
-
path: The path to exclude
|
|
125
|
+
path: The file system path to explicitly exclude from operations.
|
|
90
126
|
"""
|
|
91
|
-
resolved_path: Path =
|
|
127
|
+
resolved_path: Path = normalize_path(path)
|
|
92
128
|
self.excluded_paths.add(resolved_path)
|
|
93
129
|
|
|
94
130
|
def add_exclusion_pattern(self, pattern: str) -> None:
|
|
95
|
-
"""Add
|
|
131
|
+
"""Add a new exclusion pattern.
|
|
96
132
|
|
|
97
133
|
Args:
|
|
98
|
-
pattern:
|
|
134
|
+
pattern: A string pattern that matches file or directory names to exclude.
|
|
99
135
|
"""
|
|
100
136
|
self.excluded_patterns.append(pattern)
|
|
101
137
|
|
|
102
138
|
def is_path_allowed(self, path: str) -> bool:
|
|
103
|
-
"""
|
|
139
|
+
"""Determine if a given path is allowed for operations.
|
|
140
|
+
|
|
141
|
+
The method normalizes the input path and then checks it against the list
|
|
142
|
+
of excluded paths and patterns. If the path is not excluded and is a
|
|
143
|
+
subpath of one of the allowed base paths, the method returns True.
|
|
104
144
|
|
|
105
145
|
Args:
|
|
106
|
-
path: The path to check
|
|
146
|
+
path: The file system path to check.
|
|
107
147
|
|
|
108
148
|
Returns:
|
|
109
|
-
True if the path is allowed, False otherwise
|
|
149
|
+
True if the path is allowed for operations, False otherwise.
|
|
110
150
|
"""
|
|
111
|
-
resolved_path: Path =
|
|
151
|
+
resolved_path: Path = normalize_path(path)
|
|
112
152
|
|
|
113
|
-
#
|
|
153
|
+
# First, check if the path matches any excluded paths or patterns.
|
|
114
154
|
if self._is_path_excluded(resolved_path):
|
|
115
155
|
return False
|
|
116
156
|
|
|
117
|
-
# Check if the path is within any allowed path
|
|
157
|
+
# Check if the normalized path is within any allowed path.
|
|
118
158
|
for allowed_path in self.allowed_paths:
|
|
119
159
|
try:
|
|
160
|
+
# relative_to will succeed if resolved_path is a subpath of allowed_path.
|
|
120
161
|
resolved_path.relative_to(allowed_path)
|
|
121
162
|
return True
|
|
122
163
|
except ValueError:
|
|
@@ -125,63 +166,74 @@ class PermissionManager:
|
|
|
125
166
|
return False
|
|
126
167
|
|
|
127
168
|
def _is_path_excluded(self, path: Path) -> bool:
|
|
128
|
-
"""
|
|
169
|
+
"""Determine if a normalized path should be excluded.
|
|
170
|
+
|
|
171
|
+
The method checks two conditions:
|
|
172
|
+
1. If the path exactly matches an entry in the excluded_paths set.
|
|
173
|
+
2. If the path string contains any of the excluded patterns, either as a
|
|
174
|
+
suffix for wildcard patterns (e.g., "*.log") or as an exact match
|
|
175
|
+
within any of the path's components.
|
|
129
176
|
|
|
130
177
|
Args:
|
|
131
|
-
path: The path to check
|
|
178
|
+
path: The normalized path to check.
|
|
132
179
|
|
|
133
180
|
Returns:
|
|
134
|
-
True if the path is excluded, False otherwise
|
|
181
|
+
True if the path is excluded, False otherwise.
|
|
135
182
|
"""
|
|
136
|
-
|
|
137
|
-
# Check exact excluded paths
|
|
183
|
+
# Direct match: Check if the path is in the explicitly excluded paths set.
|
|
138
184
|
if path in self.excluded_paths:
|
|
139
185
|
return True
|
|
140
186
|
|
|
141
|
-
#
|
|
187
|
+
# Convert the path to a string for pattern matching.
|
|
142
188
|
path_str: str = str(path)
|
|
143
189
|
|
|
144
|
-
#
|
|
190
|
+
# Split the path into its individual components (directories and file name).
|
|
145
191
|
path_parts = path_str.split(os.sep)
|
|
146
192
|
|
|
193
|
+
# Iterate over each exclusion pattern to see if it matches.
|
|
147
194
|
for pattern in self.excluded_patterns:
|
|
148
|
-
#
|
|
195
|
+
# If the pattern starts with a wildcard, perform a suffix match.
|
|
149
196
|
if pattern.startswith("*"):
|
|
150
197
|
if path_str.endswith(pattern[1:]):
|
|
151
198
|
return True
|
|
152
199
|
else:
|
|
153
|
-
# For non-wildcard patterns, check if any path component matches
|
|
200
|
+
# For non-wildcard patterns, check if any path component exactly matches the pattern.
|
|
154
201
|
if pattern in path_parts:
|
|
155
202
|
return True
|
|
156
203
|
|
|
157
204
|
return False
|
|
158
205
|
|
|
159
206
|
def to_json(self) -> str:
|
|
160
|
-
"""
|
|
207
|
+
"""Serialize the permission manager's configuration to a JSON string.
|
|
208
|
+
|
|
209
|
+
The JSON representation includes the allowed paths, excluded paths, and
|
|
210
|
+
excluded patterns, which can be used to restore the configuration later.
|
|
161
211
|
|
|
162
212
|
Returns:
|
|
163
|
-
A JSON string
|
|
213
|
+
A JSON string representing the current state of the permission manager.
|
|
164
214
|
"""
|
|
165
215
|
data: dict[str, Any] = {
|
|
166
216
|
"allowed_paths": [str(p) for p in self.allowed_paths],
|
|
167
217
|
"excluded_paths": [str(p) for p in self.excluded_paths],
|
|
168
218
|
"excluded_patterns": self.excluded_patterns,
|
|
169
219
|
}
|
|
170
|
-
|
|
171
220
|
return json.dumps(data)
|
|
172
221
|
|
|
173
222
|
@classmethod
|
|
174
223
|
def from_json(cls, json_str: str) -> "PermissionManager":
|
|
175
|
-
"""Create a
|
|
224
|
+
"""Create a PermissionManager instance from a JSON string.
|
|
225
|
+
|
|
226
|
+
The JSON string should represent a configuration with allowed paths,
|
|
227
|
+
excluded paths, and exclusion patterns. This method rehydrates the state
|
|
228
|
+
accordingly.
|
|
176
229
|
|
|
177
230
|
Args:
|
|
178
|
-
json_str: The JSON string
|
|
231
|
+
json_str: The JSON string containing the permission manager configuration.
|
|
179
232
|
|
|
180
233
|
Returns:
|
|
181
|
-
A new PermissionManager instance
|
|
234
|
+
A new PermissionManager instance with configuration loaded from the JSON string.
|
|
182
235
|
"""
|
|
183
236
|
data: dict[str, Any] = json.loads(json_str)
|
|
184
|
-
|
|
185
237
|
manager = cls()
|
|
186
238
|
|
|
187
239
|
for path in data.get("allowed_paths", []):
|
|
@@ -191,12 +243,16 @@ class PermissionManager:
|
|
|
191
243
|
manager.exclude_path(path)
|
|
192
244
|
|
|
193
245
|
manager.excluded_patterns = data.get("excluded_patterns", [])
|
|
194
|
-
|
|
195
246
|
return manager
|
|
196
247
|
|
|
197
248
|
|
|
198
249
|
class PermissibleOperation:
|
|
199
|
-
"""A decorator for operations that require permission.
|
|
250
|
+
"""A decorator for operations that require permission checks.
|
|
251
|
+
|
|
252
|
+
This decorator uses a PermissionManager instance to enforce that a given
|
|
253
|
+
operation (e.g., read, write, execute) is permitted on a provided file system
|
|
254
|
+
path before allowing the decorated function to execute.
|
|
255
|
+
"""
|
|
200
256
|
|
|
201
257
|
def __init__(
|
|
202
258
|
self,
|
|
@@ -204,50 +260,54 @@ class PermissibleOperation:
|
|
|
204
260
|
operation: str,
|
|
205
261
|
get_path_fn: Callable[[list[Any], dict[str, Any]], str] | None = None,
|
|
206
262
|
) -> None:
|
|
207
|
-
"""Initialize the
|
|
263
|
+
"""Initialize the PermissibleOperation decorator.
|
|
208
264
|
|
|
209
265
|
Args:
|
|
210
|
-
permission_manager: The permission
|
|
211
|
-
operation:
|
|
212
|
-
get_path_fn: Optional function to extract the path from
|
|
266
|
+
permission_manager: The PermissionManager instance used for permission checks.
|
|
267
|
+
operation: A string representing the operation type (e.g., 'read', 'write').
|
|
268
|
+
get_path_fn: Optional function to extract the file system path from the function's
|
|
269
|
+
arguments. If not provided, defaults to using the first positional argument
|
|
270
|
+
or the first value from keyword arguments.
|
|
213
271
|
"""
|
|
214
272
|
self.permission_manager: PermissionManager = permission_manager
|
|
215
273
|
self.operation: str = operation
|
|
216
|
-
self.get_path_fn: Callable[[list[Any], dict[str, Any]], str] | None =
|
|
217
|
-
get_path_fn
|
|
218
|
-
)
|
|
274
|
+
self.get_path_fn: Callable[[list[Any], dict[str, Any]], str] | None = get_path_fn
|
|
219
275
|
|
|
220
276
|
def __call__(
|
|
221
277
|
self, func: Callable[..., Awaitable[T]]
|
|
222
278
|
) -> Callable[..., Awaitable[T]]:
|
|
223
|
-
"""Decorate the function.
|
|
279
|
+
"""Decorate the function to enforce permission checks before execution.
|
|
280
|
+
|
|
281
|
+
This method wraps the original asynchronous function, extracting a file system path
|
|
282
|
+
from its arguments and using the PermissionManager to verify if the specified operation
|
|
283
|
+
is allowed on that path. If permission is denied, a PermissionError is raised.
|
|
224
284
|
|
|
225
285
|
Args:
|
|
226
|
-
func: The function to decorate
|
|
286
|
+
func: The asynchronous function to decorate.
|
|
227
287
|
|
|
228
288
|
Returns:
|
|
229
|
-
|
|
289
|
+
An asynchronous function that includes permission checks prior to calling the original function.
|
|
230
290
|
"""
|
|
231
|
-
|
|
232
291
|
async def wrapper(*args: Any, **kwargs: Any) -> T:
|
|
233
|
-
# Extract the path
|
|
292
|
+
# Extract the file system path using the provided get_path_fn if available.
|
|
234
293
|
if self.get_path_fn:
|
|
235
|
-
# Pass args as a list and kwargs as a dict to the path function
|
|
236
294
|
path = self.get_path_fn(list(args), kwargs)
|
|
237
295
|
else:
|
|
238
|
-
# Default
|
|
296
|
+
# Default extraction: use the first positional argument if available,
|
|
297
|
+
# otherwise use the first keyword argument value.
|
|
239
298
|
path = args[0] if args else next(iter(kwargs.values()), None)
|
|
240
299
|
|
|
300
|
+
# Ensure that the extracted path is a string.
|
|
241
301
|
if not isinstance(path, str):
|
|
242
|
-
raise ValueError(f"Invalid path type: {type(path)}")
|
|
302
|
+
raise ValueError(f"Invalid path type: {type(path)}. Expected a string.")
|
|
243
303
|
|
|
244
|
-
# Check
|
|
304
|
+
# Check if the operation is allowed on the specified path.
|
|
245
305
|
if not self.permission_manager.is_path_allowed(path):
|
|
246
306
|
raise PermissionError(
|
|
247
307
|
f"Operation '{self.operation}' not allowed for path: {path}"
|
|
248
308
|
)
|
|
249
309
|
|
|
250
|
-
#
|
|
310
|
+
# Execute the original function if the permission check passes.
|
|
251
311
|
return await func(*args, **kwargs)
|
|
252
312
|
|
|
253
313
|
return wrapper
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Filesystem operations tools for Hanzo
|
|
1
|
+
"""Filesystem operations tools for Hanzo MCP.
|
|
2
2
|
|
|
3
3
|
This module provides comprehensive tools for interacting with the filesystem,
|
|
4
4
|
including reading, writing, editing files, directory operations, and searching.
|
|
@@ -20,7 +20,7 @@ from hanzo_mcp.tools.common.validation import validate_path_parameter
|
|
|
20
20
|
|
|
21
21
|
@final
|
|
22
22
|
class FileOperations:
|
|
23
|
-
"""File and filesystem operations tools for Hanzo
|
|
23
|
+
"""File and filesystem operations tools for Hanzo MCP."""
|
|
24
24
|
|
|
25
25
|
def __init__(
|
|
26
26
|
self, document_context: DocumentContext, permission_manager: PermissionManager
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Jupyter notebook operations tools for Hanzo
|
|
1
|
+
"""Jupyter notebook operations tools for Hanzo MCP.
|
|
2
2
|
|
|
3
3
|
This module provides tools for reading and editing Jupyter notebook (.ipynb) files.
|
|
4
4
|
It supports reading notebook cells with their outputs and modifying notebook contents.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"""Project analysis and management tools for Hanzo
|
|
1
|
+
"""Project analysis and management tools for Hanzo MCP."""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Project analysis tools for Hanzo
|
|
1
|
+
"""Project analysis tools for Hanzo MCP.
|
|
2
2
|
|
|
3
3
|
This module provides tools for analyzing project structure and dependencies.
|
|
4
4
|
"""
|
|
@@ -84,7 +84,7 @@ print(json.dumps(result))
|
|
|
84
84
|
|
|
85
85
|
# Execute script
|
|
86
86
|
result = await self.command_executor.execute_script_from_file(
|
|
87
|
-
script=script, language="python", cwd=project_dir, timeout=
|
|
87
|
+
script=script, language="python", cwd=project_dir, timeout=600.0
|
|
88
88
|
)
|
|
89
89
|
code, stdout, stderr = result.return_code, result.stdout, result.stderr
|
|
90
90
|
|
|
@@ -204,7 +204,7 @@ try {
|
|
|
204
204
|
|
|
205
205
|
# Execute script
|
|
206
206
|
result = await self.command_executor.execute_script_from_file(
|
|
207
|
-
script=script, language="javascript", cwd=project_dir, timeout=
|
|
207
|
+
script=script, language="javascript", cwd=project_dir, timeout=600.0
|
|
208
208
|
)
|
|
209
209
|
code, stdout, stderr = result.return_code, result.stdout, result.stderr
|
|
210
210
|
|
|
@@ -286,7 +286,7 @@ print(json.dumps(result))
|
|
|
286
286
|
|
|
287
287
|
# Execute script
|
|
288
288
|
result = await self.command_executor.execute_script_from_file(
|
|
289
|
-
script=script, language="python", cwd=project_dir, timeout=
|
|
289
|
+
script=script, language="python", cwd=project_dir, timeout=600.0
|
|
290
290
|
)
|
|
291
291
|
code, stdout, stderr = result.return_code, result.stdout, result.stderr
|
|
292
292
|
|
|
@@ -795,7 +795,7 @@ class ProjectManager:
|
|
|
795
795
|
|
|
796
796
|
@final
|
|
797
797
|
class ProjectAnalysis:
|
|
798
|
-
"""Project analysis tools for Hanzo
|
|
798
|
+
"""Project analysis tools for Hanzo MCP."""
|
|
799
799
|
|
|
800
800
|
def __init__(
|
|
801
801
|
self,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"""Shell and command execution tools for Hanzo
|
|
1
|
+
"""Shell and command execution tools for Hanzo MCP."""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Command executor tools for Hanzo
|
|
1
|
+
"""Command executor tools for Hanzo MCP.
|
|
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.
|
|
@@ -86,7 +86,7 @@ class CommandResult:
|
|
|
86
86
|
|
|
87
87
|
@final
|
|
88
88
|
class CommandExecutor:
|
|
89
|
-
"""Command executor tools for Hanzo
|
|
89
|
+
"""Command executor tools for Hanzo MCP.
|
|
90
90
|
|
|
91
91
|
This class provides tools for executing shell commands and scripts with
|
|
92
92
|
comprehensive error handling, permissions checking, and progress tracking.
|
|
@@ -193,7 +193,7 @@ class CommandExecutor:
|
|
|
193
193
|
command: str,
|
|
194
194
|
cwd: str | None = None,
|
|
195
195
|
env: dict[str, str] | None = None,
|
|
196
|
-
timeout: float | None =
|
|
196
|
+
timeout: float | None = 600.0,
|
|
197
197
|
use_login_shell: bool = True,
|
|
198
198
|
) -> CommandResult:
|
|
199
199
|
"""Execute a shell command with safety checks.
|
|
@@ -320,7 +320,7 @@ class CommandExecutor:
|
|
|
320
320
|
interpreter: str = "bash",
|
|
321
321
|
cwd: str | None = None,
|
|
322
322
|
env: dict[str, str] | None = None,
|
|
323
|
-
timeout: float | None =
|
|
323
|
+
timeout: float | None = 600.0,
|
|
324
324
|
use_login_shell: bool = True,
|
|
325
325
|
) -> CommandResult:
|
|
326
326
|
"""Execute a script with the specified interpreter.
|
|
@@ -368,7 +368,7 @@ class CommandExecutor:
|
|
|
368
368
|
script: str,
|
|
369
369
|
cwd: str | None = None,
|
|
370
370
|
env: dict[str, str] | None = None,
|
|
371
|
-
timeout: float | None =
|
|
371
|
+
timeout: float | None = 600.0,
|
|
372
372
|
use_login_shell: bool = True,
|
|
373
373
|
) -> CommandResult:
|
|
374
374
|
"""Execute a script by passing it to stdin of the interpreter.
|
|
@@ -458,7 +458,7 @@ class CommandExecutor:
|
|
|
458
458
|
script: str,
|
|
459
459
|
cwd: str | None = None,
|
|
460
460
|
env: dict[str, str] | None = None,
|
|
461
|
-
timeout: float | None =
|
|
461
|
+
timeout: float | None = 600.0,
|
|
462
462
|
) -> CommandResult:
|
|
463
463
|
"""Special handler for Fish shell scripts.
|
|
464
464
|
|
|
@@ -533,7 +533,7 @@ class CommandExecutor:
|
|
|
533
533
|
language: str,
|
|
534
534
|
cwd: str | None = None,
|
|
535
535
|
env: dict[str, str] | None = None,
|
|
536
|
-
timeout: float | None =
|
|
536
|
+
timeout: float | None = 600.0,
|
|
537
537
|
args: list[str] | None = None,
|
|
538
538
|
use_login_shell: bool = True,
|
|
539
539
|
) -> CommandResult:
|
|
@@ -773,7 +773,7 @@ class CommandExecutor:
|
|
|
773
773
|
|
|
774
774
|
# Execute the command
|
|
775
775
|
result: CommandResult = await self.execute_command(
|
|
776
|
-
command, cwd=cwd, timeout=
|
|
776
|
+
command, cwd=cwd, timeout=600.0, use_login_shell=use_login_shell
|
|
777
777
|
)
|
|
778
778
|
|
|
779
779
|
# Report result
|
|
@@ -869,7 +869,7 @@ class CommandExecutor:
|
|
|
869
869
|
script=script,
|
|
870
870
|
interpreter=interpreter,
|
|
871
871
|
cwd=cwd, # cwd is now a required parameter
|
|
872
|
-
timeout=
|
|
872
|
+
timeout=600.0,
|
|
873
873
|
use_login_shell=use_login_shell,
|
|
874
874
|
)
|
|
875
875
|
|
|
@@ -974,7 +974,7 @@ class CommandExecutor:
|
|
|
974
974
|
script=script,
|
|
975
975
|
language=language,
|
|
976
976
|
cwd=cwd, # cwd is now a required parameter
|
|
977
|
-
timeout=
|
|
977
|
+
timeout=600.0,
|
|
978
978
|
args=args,
|
|
979
979
|
use_login_shell=use_login_shell,
|
|
980
980
|
)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hanzo-mcp
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.25
|
|
4
4
|
Summary: MCP server for accessing Hanzo APIs and Platform capabilities
|
|
5
|
-
Author-email: Hanzo
|
|
5
|
+
Author-email: Hanzo <dev@hanzo.ai>
|
|
6
6
|
License: MIT
|
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
hanzo_mcp/__init__.py,sha256=MVDDvQWI8u1vdS9ynXjVvUoex3vbcRufg-NmZVPO1og,99
|
|
2
|
+
hanzo_mcp/cli.py,sha256=4hj3qRecA6tafsCeKSVDhT1TP4YNfZxWxeMQ8z8P4m0,4743
|
|
3
|
+
hanzo_mcp/server.py,sha256=Dk3IdFGAeu2qKZLeOlgE1rHjeCzRjiCkccDLsxXAXAg,4035
|
|
4
|
+
hanzo_mcp/tools/__init__.py,sha256=IsjWWWAIQW4e490k3RI2YLQ46ZvDfcttqZ0SCcC6aps,2507
|
|
5
|
+
hanzo_mcp/tools/common/__init__.py,sha256=p14VhL-SwjJxWKmAWB7Sze5ovJlNKVK_NAUplbuECTY,44
|
|
6
|
+
hanzo_mcp/tools/common/context.py,sha256=pv_oJ5aJM6YyOiKjAKU0LHZCQZQEvKRvh_9zOiQMSIw,12941
|
|
7
|
+
hanzo_mcp/tools/common/permissions.py,sha256=WL-cj2RTmjrwPlcwaQtOV5W-nZeKg2P8sboJHQ6b5fM,11710
|
|
8
|
+
hanzo_mcp/tools/common/thinking.py,sha256=0PRBTm8i8u0KBKfNaDasNSCn_R9kmFrAS3retEj_0J4,2630
|
|
9
|
+
hanzo_mcp/tools/common/validation.py,sha256=gB3uM_cbPZsH4Ez0hnTgIcdP-AUlHZU02aRmZEpk_6I,3648
|
|
10
|
+
hanzo_mcp/tools/filesystem/__init__.py,sha256=_J-n7elOW4zgVpnIm8nMV4AupmYudTF9gdkn1S40RAI,299
|
|
11
|
+
hanzo_mcp/tools/filesystem/file_operations.py,sha256=9SY8A5GzcH8u_yMCzDvWFoWSRRBlJj-i3HfcPuk5md8,46174
|
|
12
|
+
hanzo_mcp/tools/jupyter/__init__.py,sha256=H8t37ams4utRgVl-7RFi1lQFSdTJP6DdpkCVo3qVifI,245
|
|
13
|
+
hanzo_mcp/tools/jupyter/notebook_operations.py,sha256=Vzu4anFoGKHcdGuIk20mtiZVTyKx9HIhe3HKYocq0w8,23335
|
|
14
|
+
hanzo_mcp/tools/project/__init__.py,sha256=4V60vR_ZP1eEuMtH-JR1ADi5sIKHbeh93fPu5ANPhQ4,59
|
|
15
|
+
hanzo_mcp/tools/project/analysis.py,sha256=P0plRYwY6trb6ZGkJEA1bPOpdEayRd1hEKwU2EBBuOI,30361
|
|
16
|
+
hanzo_mcp/tools/shell/__init__.py,sha256=m9dH7LhiDpYU1AD6lwKPGD0E_a7MId2rAb9sGoJNeLM,55
|
|
17
|
+
hanzo_mcp/tools/shell/command_executor.py,sha256=4iBf3FmSljG6QEOXUjrO_4isUv9aWCTQKfE08PbQLlk,37401
|
|
18
|
+
hanzo_mcp-0.1.25.dist-info/licenses/LICENSE,sha256=dvWmlLGUAkNE8EJVn-UQ-F08hxW5jtjUWNe51OaH7IE,1077
|
|
19
|
+
hanzo_mcp-0.1.25.dist-info/METADATA,sha256=IRoZBImDFuOQh9pHq_gYlrupLTnu9s55TiDTcI4QfSk,7090
|
|
20
|
+
hanzo_mcp-0.1.25.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
21
|
+
hanzo_mcp-0.1.25.dist-info/entry_points.txt,sha256=aRKOKXtuQr-idSr-yH4efnRl2v8te94AcgN3ysqqSYs,49
|
|
22
|
+
hanzo_mcp-0.1.25.dist-info/top_level.txt,sha256=eGFANatA0MHWiVlpS56fTYRIShtibrSom1uXI6XU0GU,10
|
|
23
|
+
hanzo_mcp-0.1.25.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
24
|
+
hanzo_mcp-0.1.25.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
hanzo_mcp/__init__.py,sha256=b9ZjldZaFEU7nk4qZ6WCjl0fChLTeK18USOW84f7DXQ,98
|
|
2
|
-
hanzo_mcp/cli.py,sha256=vDB-5trIp-tfKwRXosWVZGBNTZAo_B7wTCoF-NVaLKc,4747
|
|
3
|
-
hanzo_mcp/server.py,sha256=p7-0B99gSfC5ieyOGt7xJ233ddCw1FY9dZDujaHarLU,4039
|
|
4
|
-
hanzo_mcp/tools/__init__.py,sha256=IsjWWWAIQW4e490k3RI2YLQ46ZvDfcttqZ0SCcC6aps,2507
|
|
5
|
-
hanzo_mcp/tools/common/__init__.py,sha256=mUlTy1Py8zV-DBEhkds-DoB2zHOxDZnbnOo3WFHP7ro,48
|
|
6
|
-
hanzo_mcp/tools/common/context.py,sha256=BuuuHDQqzmO8LaWPcdgj8Md4FHT2gGuWIo8mN7fMIOY,12949
|
|
7
|
-
hanzo_mcp/tools/common/permissions.py,sha256=HHH3MM-4dTufJ0HYv6M5yDJHJJBGjcXVnUi4lCWmfRI,7388
|
|
8
|
-
hanzo_mcp/tools/common/thinking.py,sha256=0PRBTm8i8u0KBKfNaDasNSCn_R9kmFrAS3retEj_0J4,2630
|
|
9
|
-
hanzo_mcp/tools/common/validation.py,sha256=S8zj38jjAXSB4bmZAydXDCsh_j6hHGEs71SgK-oeeYI,3652
|
|
10
|
-
hanzo_mcp/tools/filesystem/__init__.py,sha256=IBrOsd_8yDo8RIuujB4rNQmr-JmXuddxyhOv-0PUeig,303
|
|
11
|
-
hanzo_mcp/tools/filesystem/file_operations.py,sha256=6LeSoemvaz-oIP0K7GL_vySgA-i8QqN0tI9O_HalSIQ,46182
|
|
12
|
-
hanzo_mcp/tools/jupyter/__init__.py,sha256=XuRoN_02X6ChW_OVGoPIydkQTOlvMtL5hPWRzGW3LVU,249
|
|
13
|
-
hanzo_mcp/tools/jupyter/notebook_operations.py,sha256=AzZXyrgxR55KU09s3B1D50wAdsozHWQZFMCFXsnoe3A,23339
|
|
14
|
-
hanzo_mcp/tools/project/__init__.py,sha256=el-n7xVnHgk6wXqVhFtFCoEfdq11aDAo9DucIJdXBVw,63
|
|
15
|
-
hanzo_mcp/tools/project/analysis.py,sha256=eQ1WgeFNf_d9g_LWdo1f3x5-c4PLzRXK2_j-JN8wM9w,30366
|
|
16
|
-
hanzo_mcp/tools/shell/__init__.py,sha256=myuuFc03I1xGq3VxmLddkSlvvaQIddA3WoIKds8ABFo,59
|
|
17
|
-
hanzo_mcp/tools/shell/command_executor.py,sha256=HyhAwG-aLw13f0Z-K4sCAWqt7qRWEiixnv8tmTTyJW8,37401
|
|
18
|
-
hanzo_mcp-0.1.21.dist-info/licenses/LICENSE,sha256=dvWmlLGUAkNE8EJVn-UQ-F08hxW5jtjUWNe51OaH7IE,1077
|
|
19
|
-
hanzo_mcp-0.1.21.dist-info/METADATA,sha256=34AG2iCwxvRc2SXiGT8jqCgjH6Q8eiXM4YhfAE6OMSY,7094
|
|
20
|
-
hanzo_mcp-0.1.21.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
|
21
|
-
hanzo_mcp-0.1.21.dist-info/entry_points.txt,sha256=aRKOKXtuQr-idSr-yH4efnRl2v8te94AcgN3ysqqSYs,49
|
|
22
|
-
hanzo_mcp-0.1.21.dist-info/top_level.txt,sha256=eGFANatA0MHWiVlpS56fTYRIShtibrSom1uXI6XU0GU,10
|
|
23
|
-
hanzo_mcp-0.1.21.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|