hanzo-mcp 0.1.34__tar.gz → 0.1.36__tar.gz
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-0.1.34 → hanzo_mcp-0.1.36}/PKG-INFO +10 -5
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/README.md +9 -4
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/__init__.py +1 -1
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/cli.py +9 -11
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/server.py +9 -4
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/__init__.py +2 -2
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/common/__init__.py +5 -4
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/common/context.py +8 -6
- hanzo_mcp-0.1.36/hanzo_mcp/tools/common/path_utils.py +51 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/common/permissions.py +8 -6
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/common/version_tool.py +4 -18
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/filesystem/directory_tree.py +46 -7
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/shell/command_executor.py +6 -7
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp.egg-info/PKG-INFO +10 -5
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp.egg-info/SOURCES.txt +3 -1
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/pyproject.toml +1 -1
- hanzo_mcp-0.1.36/setup.py +51 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/LICENSE +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/agent/__init__.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/agent/agent_tool.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/agent/prompt.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/agent/tool_adapter.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/common/base.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/common/session.py +0 -0
- /hanzo_mcp-0.1.34/hanzo_mcp/tools/common/thinking_tool.py → /hanzo_mcp-0.1.36/hanzo_mcp/tools/common/think_tool.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/common/validation.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/filesystem/__init__.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/filesystem/base.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/filesystem/content_replace.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/filesystem/edit_file.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/filesystem/get_file_info.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/filesystem/read_files.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/filesystem/search_content.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/filesystem/write_file.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/jupyter/__init__.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/jupyter/base.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/jupyter/edit_notebook.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/jupyter/notebook_operations.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/jupyter/read_notebook.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/project/__init__.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/project/analysis.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/project/base.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/project/project_analyze.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/shell/__init__.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/shell/base.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/shell/run_command.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/shell/run_script.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp/tools/shell/script_tool.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp.egg-info/dependency_links.txt +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp.egg-info/entry_points.txt +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp.egg-info/requires.txt +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/hanzo_mcp.egg-info/top_level.txt +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/setup.cfg +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/tests/test_cli.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/tests/test_server.py +0 -0
- {hanzo_mcp-0.1.34 → hanzo_mcp-0.1.36}/tests/test_validation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hanzo-mcp
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.36
|
|
4
4
|
Summary: MCP implementation of Hanzo capabilities
|
|
5
5
|
Author-email: Hanzo Industries Inc <dev@hanzo.ai>
|
|
6
6
|
License: MIT
|
|
@@ -146,14 +146,19 @@ make bump-patch # Increment patch version (0.1.x → 0.1.x+1)
|
|
|
146
146
|
make bump-minor # Increment minor version (0.x.0 → 0.x+1.0)
|
|
147
147
|
make bump-major # Increment major version (x.0.0 → x+1.0.0)
|
|
148
148
|
|
|
149
|
+
# Manual version bumping (alternative to make commands)
|
|
150
|
+
python -m scripts.bump_version patch # Increment patch version
|
|
151
|
+
python -m scripts.bump_version minor # Increment minor version
|
|
152
|
+
python -m scripts.bump_version major # Increment major version
|
|
153
|
+
|
|
149
154
|
# Publishing (creates git tag and pushes it to GitHub)
|
|
150
155
|
make publish # Publish using configured credentials in .pypirc
|
|
151
156
|
PYPI_TOKEN=your_token make publish # Publish with token from environment variable
|
|
152
157
|
|
|
153
|
-
#
|
|
154
|
-
make
|
|
155
|
-
make
|
|
156
|
-
make
|
|
158
|
+
# Publishing (creates git tag, pushes to GitHub, and publishes to PyPI)
|
|
159
|
+
make patch # Bump patch version, build, publish, create git tag, and push
|
|
160
|
+
make minor # Bump minor version, build, publish, create git tag, and push
|
|
161
|
+
make major # Bump major version, build, publish, create git tag, and push
|
|
157
162
|
|
|
158
163
|
# Publish to Test PyPI
|
|
159
164
|
make publish-test
|
|
@@ -105,14 +105,19 @@ make bump-patch # Increment patch version (0.1.x → 0.1.x+1)
|
|
|
105
105
|
make bump-minor # Increment minor version (0.x.0 → 0.x+1.0)
|
|
106
106
|
make bump-major # Increment major version (x.0.0 → x+1.0.0)
|
|
107
107
|
|
|
108
|
+
# Manual version bumping (alternative to make commands)
|
|
109
|
+
python -m scripts.bump_version patch # Increment patch version
|
|
110
|
+
python -m scripts.bump_version minor # Increment minor version
|
|
111
|
+
python -m scripts.bump_version major # Increment major version
|
|
112
|
+
|
|
108
113
|
# Publishing (creates git tag and pushes it to GitHub)
|
|
109
114
|
make publish # Publish using configured credentials in .pypirc
|
|
110
115
|
PYPI_TOKEN=your_token make publish # Publish with token from environment variable
|
|
111
116
|
|
|
112
|
-
#
|
|
113
|
-
make
|
|
114
|
-
make
|
|
115
|
-
make
|
|
117
|
+
# Publishing (creates git tag, pushes to GitHub, and publishes to PyPI)
|
|
118
|
+
make patch # Bump patch version, build, publish, create git tag, and push
|
|
119
|
+
make minor # Bump minor version, build, publish, create git tag, and push
|
|
120
|
+
make major # Bump major version, build, publish, create git tag, and push
|
|
116
121
|
|
|
117
122
|
# Publish to Test PyPI
|
|
118
123
|
make publish-test
|
|
@@ -8,6 +8,7 @@ from pathlib import Path
|
|
|
8
8
|
from typing import Any, cast
|
|
9
9
|
|
|
10
10
|
from hanzo_mcp.server import HanzoServer
|
|
11
|
+
from hanzo_mcp.tools.common.path_utils import PathUtils
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def main() -> None:
|
|
@@ -113,21 +114,18 @@ def main() -> None:
|
|
|
113
114
|
# If no allowed paths are specified, use the user's home directory
|
|
114
115
|
if not allowed_paths:
|
|
115
116
|
allowed_paths = [str(Path.home())]
|
|
117
|
+
|
|
118
|
+
# Normalize all allowed paths
|
|
119
|
+
allowed_paths = [PathUtils.normalize_path(path) for path in allowed_paths]
|
|
116
120
|
|
|
117
|
-
# If project directory is specified,
|
|
118
|
-
if project_dir and project_dir not in allowed_paths:
|
|
119
|
-
allowed_paths.append(project_dir)
|
|
120
|
-
|
|
121
|
-
# Set project directory as initial working directory if provided
|
|
121
|
+
# If project directory is specified, normalize it and add to allowed paths
|
|
122
122
|
if project_dir:
|
|
123
|
-
|
|
124
|
-
project_dir
|
|
125
|
-
|
|
126
|
-
if not os.path.isabs(project_dir):
|
|
127
|
-
project_dir = os.path.abspath(project_dir)
|
|
123
|
+
project_dir = PathUtils.normalize_path(project_dir)
|
|
124
|
+
if project_dir not in allowed_paths:
|
|
125
|
+
allowed_paths.append(project_dir)
|
|
128
126
|
|
|
129
127
|
# If no specific project directory, use the first allowed path
|
|
130
|
-
|
|
128
|
+
if not project_dir and allowed_paths:
|
|
131
129
|
project_dir = allowed_paths[0]
|
|
132
130
|
|
|
133
131
|
# Run the server
|
|
@@ -6,6 +6,7 @@ from mcp.server.fastmcp import FastMCP
|
|
|
6
6
|
|
|
7
7
|
from hanzo_mcp.tools import register_all_tools
|
|
8
8
|
from hanzo_mcp.tools.common.context import DocumentContext
|
|
9
|
+
from hanzo_mcp.tools.common.path_utils import PathUtils
|
|
9
10
|
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
10
11
|
from hanzo_mcp.tools.project.analysis import ProjectAnalyzer, ProjectManager
|
|
11
12
|
from hanzo_mcp.tools.shell.command_executor import CommandExecutor
|
|
@@ -70,8 +71,10 @@ class HanzoServer:
|
|
|
70
71
|
# Add allowed paths
|
|
71
72
|
if allowed_paths:
|
|
72
73
|
for path in allowed_paths:
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
# Path should already be normalized from CLI, but normalize here for safety
|
|
75
|
+
normalized_path = PathUtils.normalize_path(path)
|
|
76
|
+
self.permission_manager.add_allowed_path(normalized_path)
|
|
77
|
+
self.document_context.add_allowed_path(normalized_path)
|
|
75
78
|
|
|
76
79
|
# Store agent options
|
|
77
80
|
self.agent_model = agent_model
|
|
@@ -104,8 +107,10 @@ class HanzoServer:
|
|
|
104
107
|
# Add allowed paths if provided
|
|
105
108
|
allowed_paths_list = allowed_paths or []
|
|
106
109
|
for path in allowed_paths_list:
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
# Normalize path before adding
|
|
111
|
+
normalized_path = PathUtils.normalize_path(path)
|
|
112
|
+
self.permission_manager.add_allowed_path(normalized_path)
|
|
113
|
+
self.document_context.add_allowed_path(normalized_path)
|
|
109
114
|
|
|
110
115
|
# Run the server
|
|
111
116
|
transport_type = cast(Literal["stdio", "sse"], transport)
|
|
@@ -12,7 +12,7 @@ to delegate tasks to sub-agents for concurrent execution and specialized process
|
|
|
12
12
|
from mcp.server.fastmcp import FastMCP
|
|
13
13
|
|
|
14
14
|
from hanzo_mcp.tools.agent import register_agent_tools
|
|
15
|
-
from hanzo_mcp.tools.common import
|
|
15
|
+
from hanzo_mcp.tools.common import register_think_tool, register_version_tool
|
|
16
16
|
from hanzo_mcp.tools.common.context import DocumentContext
|
|
17
17
|
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
18
18
|
from hanzo_mcp.tools.filesystem import register_filesystem_tools
|
|
@@ -78,7 +78,7 @@ def register_all_tools(
|
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
# Initialize and register thinking tool
|
|
81
|
-
|
|
81
|
+
register_think_tool(mcp_server)
|
|
82
82
|
|
|
83
83
|
# Register version tool
|
|
84
84
|
register_version_tool(mcp_server)
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
from mcp.server.fastmcp import FastMCP
|
|
4
4
|
|
|
5
5
|
from hanzo_mcp.tools.common.base import ToolRegistry
|
|
6
|
-
from hanzo_mcp.tools.common.
|
|
6
|
+
from hanzo_mcp.tools.common.path_utils import PathUtils
|
|
7
|
+
from hanzo_mcp.tools.common.think_tool import ThinkingTool
|
|
7
8
|
from hanzo_mcp.tools.common.version_tool import VersionTool
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
def
|
|
11
|
+
def register_think_tool(
|
|
11
12
|
mcp_server: FastMCP,
|
|
12
13
|
) -> None:
|
|
13
14
|
"""Register all thinking tools with the MCP server.
|
|
@@ -15,8 +16,8 @@ def register_thinking_tool(
|
|
|
15
16
|
Args:
|
|
16
17
|
mcp_server: The FastMCP server instance
|
|
17
18
|
"""
|
|
18
|
-
|
|
19
|
-
ToolRegistry.register_tool(mcp_server,
|
|
19
|
+
think_tool = ThinkingTool()
|
|
20
|
+
ToolRegistry.register_tool(mcp_server, think_tool)
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
def register_version_tool(
|
|
@@ -14,6 +14,8 @@ from typing import Any, ClassVar, final
|
|
|
14
14
|
from mcp.server.fastmcp import Context as MCPContext
|
|
15
15
|
from mcp.server.lowlevel.helper_types import ReadResourceContents
|
|
16
16
|
|
|
17
|
+
from hanzo_mcp.tools.common.path_utils import PathUtils
|
|
18
|
+
|
|
17
19
|
|
|
18
20
|
@final
|
|
19
21
|
class ToolContext:
|
|
@@ -179,9 +181,9 @@ class DocumentContext:
|
|
|
179
181
|
Args:
|
|
180
182
|
path: The path to allow
|
|
181
183
|
"""
|
|
182
|
-
#
|
|
183
|
-
|
|
184
|
-
resolved_path: Path = Path(
|
|
184
|
+
# Normalize path (expand user paths and make absolute)
|
|
185
|
+
normalized_path = PathUtils.normalize_path(path)
|
|
186
|
+
resolved_path: Path = Path(normalized_path).resolve()
|
|
185
187
|
self.allowed_paths.add(resolved_path)
|
|
186
188
|
|
|
187
189
|
def is_path_allowed(self, path: str) -> bool:
|
|
@@ -193,9 +195,9 @@ class DocumentContext:
|
|
|
193
195
|
Returns:
|
|
194
196
|
True if the path is allowed, False otherwise
|
|
195
197
|
"""
|
|
196
|
-
#
|
|
197
|
-
|
|
198
|
-
resolved_path: Path = Path(
|
|
198
|
+
# Normalize path (expand user paths and make absolute)
|
|
199
|
+
normalized_path = PathUtils.normalize_path(path)
|
|
200
|
+
resolved_path: Path = Path(normalized_path).resolve()
|
|
199
201
|
|
|
200
202
|
# Check if the path is within any allowed path
|
|
201
203
|
for allowed_path in self.allowed_paths:
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Path utilities for Hanzo MCP.
|
|
2
|
+
|
|
3
|
+
This module provides path normalization and validation utilities.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import final
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@final
|
|
12
|
+
class PathUtils:
|
|
13
|
+
"""Utilities for path handling."""
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def normalize_path(path: str) -> str:
|
|
17
|
+
"""Normalize a path by expanding user paths and making it absolute.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
path: The path to normalize
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
The normalized path
|
|
24
|
+
"""
|
|
25
|
+
# Expand user paths (e.g., ~/ or $HOME)
|
|
26
|
+
expanded_path = os.path.expanduser(path)
|
|
27
|
+
|
|
28
|
+
# Make the path absolute if it isn't already
|
|
29
|
+
if not os.path.isabs(expanded_path):
|
|
30
|
+
expanded_path = os.path.abspath(expanded_path)
|
|
31
|
+
|
|
32
|
+
# Normalize the path (resolve symlinks, etc.)
|
|
33
|
+
try:
|
|
34
|
+
normalized_path = os.path.normpath(expanded_path)
|
|
35
|
+
return normalized_path
|
|
36
|
+
except Exception:
|
|
37
|
+
# Return the expanded path if normalization fails
|
|
38
|
+
return expanded_path
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def is_dot_directory(path: Path) -> bool:
|
|
42
|
+
"""Check if a path is a dot directory (e.g., .git, .vscode).
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
path: The path to check
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
True if the path is a dot directory, False otherwise
|
|
49
|
+
"""
|
|
50
|
+
# Consider any directory starting with "." to be a dot directory
|
|
51
|
+
return path.is_dir() and path.name.startswith(".")
|
|
@@ -6,6 +6,8 @@ from collections.abc import Awaitable, Callable
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any, TypeVar, final
|
|
8
8
|
|
|
9
|
+
from hanzo_mcp.tools.common.path_utils import PathUtils
|
|
10
|
+
|
|
9
11
|
# Define type variables for better type annotations
|
|
10
12
|
T = TypeVar("T")
|
|
11
13
|
P = TypeVar("P")
|
|
@@ -69,9 +71,9 @@ class PermissionManager:
|
|
|
69
71
|
Args:
|
|
70
72
|
path: The path to allow
|
|
71
73
|
"""
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
resolved_path: Path = Path(
|
|
74
|
+
# Normalize path (expand user paths and make absolute)
|
|
75
|
+
normalized_path = PathUtils.normalize_path(path)
|
|
76
|
+
resolved_path: Path = Path(normalized_path).resolve()
|
|
75
77
|
self.allowed_paths.add(resolved_path)
|
|
76
78
|
|
|
77
79
|
def remove_allowed_path(self, path: str) -> None:
|
|
@@ -110,9 +112,9 @@ class PermissionManager:
|
|
|
110
112
|
Returns:
|
|
111
113
|
True if the path is allowed, False otherwise
|
|
112
114
|
"""
|
|
113
|
-
#
|
|
114
|
-
|
|
115
|
-
resolved_path: Path = Path(
|
|
115
|
+
# Normalize path (expand user paths and make absolute)
|
|
116
|
+
normalized_path = PathUtils.normalize_path(path)
|
|
117
|
+
resolved_path: Path = Path(normalized_path).resolve()
|
|
116
118
|
|
|
117
119
|
# Check exclusions first
|
|
118
120
|
if self._is_path_excluded(resolved_path):
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"""Version tool for displaying project version information."""
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import os
|
|
5
|
-
import tomllib
|
|
6
|
-
from typing import Any, Dict, TypedDict, cast, final, override
|
|
3
|
+
from typing import Any, Dict, TypedDict, final, override
|
|
7
4
|
|
|
8
5
|
from mcp.server.fastmcp import Context as MCPContext
|
|
9
6
|
from mcp.server.fastmcp import FastMCP
|
|
@@ -101,21 +98,10 @@ class VersionTool(BaseTool):
|
|
|
101
98
|
Returns:
|
|
102
99
|
A dictionary containing the package name and version
|
|
103
100
|
"""
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
except importlib.metadata.PackageNotFoundError:
|
|
107
|
-
# If package not installed, try to read from pyproject.toml
|
|
108
|
-
try:
|
|
109
|
-
root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
|
110
|
-
toml_path = os.path.join(root_dir, "pyproject.toml")
|
|
111
|
-
|
|
112
|
-
with open(toml_path, "rb") as f:
|
|
113
|
-
pyproject = tomllib.load(f)
|
|
114
|
-
version = cast(str, pyproject.get("project", {}).get("version", "unknown"))
|
|
115
|
-
except Exception:
|
|
116
|
-
version = "unknown"
|
|
101
|
+
# Directly use the __version__ from the hanzo_mcp package
|
|
102
|
+
from hanzo_mcp import __version__
|
|
117
103
|
|
|
118
|
-
return {"version":
|
|
104
|
+
return {"version": __version__, "package_name": "hanzo-mcp"}
|
|
119
105
|
|
|
120
106
|
@override
|
|
121
107
|
def register(self, mcp_server: FastMCP) -> None:
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
This module provides the DirectoryTreeTool for viewing file and directory structures.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import os
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Any, final, override
|
|
8
9
|
|
|
9
10
|
from mcp.server.fastmcp import Context as MCPContext
|
|
10
11
|
from mcp.server.fastmcp import FastMCP
|
|
11
12
|
|
|
13
|
+
from hanzo_mcp.tools.common.path_utils import PathUtils
|
|
12
14
|
from hanzo_mcp.tools.filesystem.base import FilesystemBaseTool
|
|
13
15
|
|
|
14
16
|
|
|
@@ -137,17 +139,47 @@ requested. Only works within allowed directories."""
|
|
|
137
139
|
if not is_dir:
|
|
138
140
|
return error_msg
|
|
139
141
|
|
|
140
|
-
# Define filtered directories
|
|
142
|
+
# Define filtered directories based on common patterns and .gitignore
|
|
141
143
|
FILTERED_DIRECTORIES = {
|
|
142
|
-
|
|
143
|
-
"
|
|
144
|
-
".
|
|
145
|
-
".ruff_cache",".
|
|
144
|
+
# Hidden/dot directories
|
|
145
|
+
".git", ".github", ".gitignore", ".hg", ".svn", ".venv", ".env",
|
|
146
|
+
".idea", ".vscode", ".vs", ".cache", ".config", ".local",
|
|
147
|
+
".pytest_cache", ".ruff_cache", ".mypy_cache", ".pytype",
|
|
148
|
+
".coverage", ".tox", ".nox", ".circleci", ".llm-context",
|
|
149
|
+
# Cache directories
|
|
150
|
+
"__pycache__", ".ipynb_checkpoints", "htmlcov", ".eggs",
|
|
151
|
+
# Build artifacts
|
|
152
|
+
"dist", "build", "target", "out", "site", "coverage",
|
|
153
|
+
# Dependency directories
|
|
154
|
+
"node_modules", "venv", "env", "ENV", "lib", "libs", "vendor",
|
|
155
|
+
"eggs", "sdist", "wheels", "share"
|
|
146
156
|
}
|
|
147
157
|
|
|
148
158
|
# Log filtering settings
|
|
149
159
|
await tool_ctx.info(f"Directory tree filtering: include_filtered={include_filtered}")
|
|
150
160
|
|
|
161
|
+
# Try to get additional patterns from .gitignore if it exists
|
|
162
|
+
gitignore_patterns = set()
|
|
163
|
+
gitignore_path = dir_path / ".gitignore"
|
|
164
|
+
if gitignore_path.exists() and gitignore_path.is_file():
|
|
165
|
+
try:
|
|
166
|
+
with open(gitignore_path, "r") as f:
|
|
167
|
+
for line in f:
|
|
168
|
+
line = line.strip()
|
|
169
|
+
if line and not line.startswith("#"):
|
|
170
|
+
# Strip trailing slashes for directory patterns
|
|
171
|
+
if line.endswith("/"):
|
|
172
|
+
line = line[:-1]
|
|
173
|
+
# Extract the actual pattern without path
|
|
174
|
+
pattern = line.split("/")[-1]
|
|
175
|
+
if pattern and "*" not in pattern and "?" not in pattern:
|
|
176
|
+
gitignore_patterns.add(pattern)
|
|
177
|
+
except Exception as e:
|
|
178
|
+
await tool_ctx.warning(f"Error reading .gitignore: {str(e)}")
|
|
179
|
+
|
|
180
|
+
# Add gitignore patterns to filtered directories
|
|
181
|
+
FILTERED_DIRECTORIES.update(gitignore_patterns)
|
|
182
|
+
|
|
151
183
|
# Check if a directory should be filtered
|
|
152
184
|
def should_filter(current_path: Path) -> bool:
|
|
153
185
|
# Don't filter if it's the explicitly requested path
|
|
@@ -155,8 +187,15 @@ requested. Only works within allowed directories."""
|
|
|
155
187
|
# Don't filter explicitly requested paths
|
|
156
188
|
return False
|
|
157
189
|
|
|
158
|
-
#
|
|
159
|
-
|
|
190
|
+
# First check standard filtered directories
|
|
191
|
+
if current_path.name in FILTERED_DIRECTORIES and not include_filtered:
|
|
192
|
+
return True
|
|
193
|
+
|
|
194
|
+
# Also filter hidden directories (dot directories) unless explicitly included
|
|
195
|
+
if PathUtils.is_dot_directory(current_path) and not include_filtered:
|
|
196
|
+
return True
|
|
197
|
+
|
|
198
|
+
return False
|
|
160
199
|
|
|
161
200
|
# Track stats for summary
|
|
162
201
|
stats = {
|
|
@@ -14,6 +14,8 @@ from collections.abc import Awaitable, Callable
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Dict, Optional, final
|
|
16
16
|
|
|
17
|
+
from hanzo_mcp.tools.common.path_utils import PathUtils
|
|
18
|
+
|
|
17
19
|
from mcp.server.fastmcp import Context as MCPContext
|
|
18
20
|
from mcp.server.fastmcp import FastMCP
|
|
19
21
|
|
|
@@ -134,8 +136,8 @@ class CommandExecutor:
|
|
|
134
136
|
path: The path to set as the current working directory
|
|
135
137
|
"""
|
|
136
138
|
session = self.get_session_manager(session_id)
|
|
137
|
-
|
|
138
|
-
session.set_working_dir(Path(
|
|
139
|
+
normalized_path = PathUtils.normalize_path(path)
|
|
140
|
+
session.set_working_dir(Path(normalized_path))
|
|
139
141
|
|
|
140
142
|
def get_working_dir(self, session_id: str) -> str:
|
|
141
143
|
"""Get the current working directory for the session.
|
|
@@ -249,11 +251,8 @@ class CommandExecutor:
|
|
|
249
251
|
session_cwd = self.get_working_dir(session_id)
|
|
250
252
|
target_dir = os.path.join(session_cwd, target_dir)
|
|
251
253
|
|
|
252
|
-
#
|
|
253
|
-
target_dir =
|
|
254
|
-
|
|
255
|
-
# Normalize path
|
|
256
|
-
target_dir = os.path.normpath(target_dir)
|
|
254
|
+
# Normalize path (expand user and make absolute)
|
|
255
|
+
target_dir = PathUtils.normalize_path(target_dir)
|
|
257
256
|
|
|
258
257
|
if os.path.isdir(target_dir):
|
|
259
258
|
self.set_working_dir(session_id, target_dir)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hanzo-mcp
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.36
|
|
4
4
|
Summary: MCP implementation of Hanzo capabilities
|
|
5
5
|
Author-email: Hanzo Industries Inc <dev@hanzo.ai>
|
|
6
6
|
License: MIT
|
|
@@ -146,14 +146,19 @@ make bump-patch # Increment patch version (0.1.x → 0.1.x+1)
|
|
|
146
146
|
make bump-minor # Increment minor version (0.x.0 → 0.x+1.0)
|
|
147
147
|
make bump-major # Increment major version (x.0.0 → x+1.0.0)
|
|
148
148
|
|
|
149
|
+
# Manual version bumping (alternative to make commands)
|
|
150
|
+
python -m scripts.bump_version patch # Increment patch version
|
|
151
|
+
python -m scripts.bump_version minor # Increment minor version
|
|
152
|
+
python -m scripts.bump_version major # Increment major version
|
|
153
|
+
|
|
149
154
|
# Publishing (creates git tag and pushes it to GitHub)
|
|
150
155
|
make publish # Publish using configured credentials in .pypirc
|
|
151
156
|
PYPI_TOKEN=your_token make publish # Publish with token from environment variable
|
|
152
157
|
|
|
153
|
-
#
|
|
154
|
-
make
|
|
155
|
-
make
|
|
156
|
-
make
|
|
158
|
+
# Publishing (creates git tag, pushes to GitHub, and publishes to PyPI)
|
|
159
|
+
make patch # Bump patch version, build, publish, create git tag, and push
|
|
160
|
+
make minor # Bump minor version, build, publish, create git tag, and push
|
|
161
|
+
make major # Bump major version, build, publish, create git tag, and push
|
|
157
162
|
|
|
158
163
|
# Publish to Test PyPI
|
|
159
164
|
make publish-test
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
LICENSE
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
|
+
setup.py
|
|
4
5
|
hanzo_mcp/__init__.py
|
|
5
6
|
hanzo_mcp/cli.py
|
|
6
7
|
hanzo_mcp/server.py
|
|
@@ -18,9 +19,10 @@ hanzo_mcp/tools/agent/tool_adapter.py
|
|
|
18
19
|
hanzo_mcp/tools/common/__init__.py
|
|
19
20
|
hanzo_mcp/tools/common/base.py
|
|
20
21
|
hanzo_mcp/tools/common/context.py
|
|
22
|
+
hanzo_mcp/tools/common/path_utils.py
|
|
21
23
|
hanzo_mcp/tools/common/permissions.py
|
|
22
24
|
hanzo_mcp/tools/common/session.py
|
|
23
|
-
hanzo_mcp/tools/common/
|
|
25
|
+
hanzo_mcp/tools/common/think_tool.py
|
|
24
26
|
hanzo_mcp/tools/common/validation.py
|
|
25
27
|
hanzo_mcp/tools/common/version_tool.py
|
|
26
28
|
hanzo_mcp/tools/filesystem/__init__.py
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Setup script for hanzo-mcp."""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from setuptools import setup
|
|
8
|
+
from setuptools.command.build_py import build_py
|
|
9
|
+
from setuptools.command.develop import develop
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UpdateVersionBuildPy(build_py):
|
|
13
|
+
"""Custom build_py command that updates version before building."""
|
|
14
|
+
|
|
15
|
+
def run(self):
|
|
16
|
+
"""Run the command."""
|
|
17
|
+
# Run the version update script before building
|
|
18
|
+
update_script = os.path.join('scripts', 'update_version.py')
|
|
19
|
+
if os.path.exists(update_script):
|
|
20
|
+
print("Running version update script...")
|
|
21
|
+
subprocess.check_call([sys.executable, update_script])
|
|
22
|
+
else:
|
|
23
|
+
print(f"Warning: Version update script not found at {update_script}")
|
|
24
|
+
|
|
25
|
+
# Continue with the regular build process
|
|
26
|
+
super().run()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class UpdateVersionDevelop(develop):
|
|
30
|
+
"""Custom develop command that updates version before installing in development mode."""
|
|
31
|
+
|
|
32
|
+
def run(self):
|
|
33
|
+
"""Run the command."""
|
|
34
|
+
# Run the version update script before installing
|
|
35
|
+
update_script = os.path.join('scripts', 'update_version.py')
|
|
36
|
+
if os.path.exists(update_script):
|
|
37
|
+
print("Running version update script...")
|
|
38
|
+
subprocess.check_call([sys.executable, update_script])
|
|
39
|
+
else:
|
|
40
|
+
print(f"Warning: Version update script not found at {update_script}")
|
|
41
|
+
|
|
42
|
+
# Continue with the regular develop process
|
|
43
|
+
super().run()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
setup(
|
|
47
|
+
cmdclass={
|
|
48
|
+
'build_py': UpdateVersionBuildPy,
|
|
49
|
+
'develop': UpdateVersionDevelop,
|
|
50
|
+
},
|
|
51
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|