hanzo-mcp 0.2.0__tar.gz → 0.3.1__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.2.0 → hanzo_mcp-0.3.1}/PKG-INFO +1 -1
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/__init__.py +1 -1
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/cli.py +110 -25
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/server.py +26 -4
- hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/base_provider.py +73 -0
- hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/litellm_provider.py +45 -0
- hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/lmstudio_agent.py +385 -0
- hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/lmstudio_provider.py +219 -0
- hanzo_mcp-0.3.1/hanzo_mcp/tools/agent/provider_registry.py +120 -0
- hanzo_mcp-0.3.1/hanzo_mcp/tools/common/error_handling.py +86 -0
- hanzo_mcp-0.3.1/hanzo_mcp/tools/common/logging_config.py +84 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/PKG-INFO +1 -1
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/SOURCES.txt +7 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/pyproject.toml +1 -1
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/LICENSE +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/README.md +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/__init__.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/agent/__init__.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/agent/agent_tool.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/agent/prompt.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/agent/tool_adapter.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/__init__.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/base.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/context.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/permissions.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/session.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/think_tool.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/validation.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/common/version_tool.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/__init__.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/base.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/content_replace.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/directory_tree.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/edit_file.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/get_file_info.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/read_files.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/search_content.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/filesystem/write_file.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/__init__.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/base.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/edit_notebook.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/notebook_operations.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/jupyter/read_notebook.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/project/__init__.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/project/analysis.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/project/base.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/project/project_analyze.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/__init__.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/base.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/command_executor.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/run_command.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/run_script.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp/tools/shell/script_tool.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/dependency_links.txt +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/entry_points.txt +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/requires.txt +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/hanzo_mcp.egg-info/top_level.txt +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/setup.cfg +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/setup.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/tests/test_cli.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/tests/test_server.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/tests/test_tools_registration.py +0 -0
- {hanzo_mcp-0.2.0 → hanzo_mcp-0.3.1}/tests/test_validation.py +0 -0
|
@@ -1,20 +1,42 @@
|
|
|
1
|
-
"""Command-line interface for the Hanzo MCP server.
|
|
1
|
+
"""Command-line interface for the Hanzo MCP server.
|
|
2
|
+
|
|
3
|
+
Includes logging configuration and enhanced error handling.
|
|
4
|
+
"""
|
|
2
5
|
|
|
3
6
|
import argparse
|
|
4
7
|
import json
|
|
8
|
+
import logging
|
|
5
9
|
import os
|
|
6
10
|
import sys
|
|
7
11
|
from pathlib import Path
|
|
8
12
|
from typing import Any, cast
|
|
9
13
|
|
|
14
|
+
from hanzo_mcp import __version__
|
|
15
|
+
from hanzo_mcp.tools.common.logging_config import setup_logging
|
|
16
|
+
|
|
10
17
|
from hanzo_mcp.server import HanzoServer
|
|
11
18
|
|
|
12
19
|
|
|
13
20
|
def main() -> None:
|
|
14
21
|
"""Run the CLI for the Hanzo MCP server."""
|
|
22
|
+
# Initialize logger
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
# Check if 'version' is the first argument
|
|
26
|
+
if len(sys.argv) > 1 and sys.argv[1] == 'version':
|
|
27
|
+
print(f"hanzo-mcp {__version__}")
|
|
28
|
+
return
|
|
29
|
+
|
|
15
30
|
parser = argparse.ArgumentParser(
|
|
16
31
|
description="MCP server implementing Hanzo capabilities"
|
|
17
32
|
)
|
|
33
|
+
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"--version",
|
|
36
|
+
action="version",
|
|
37
|
+
version=f"%(prog)s {__version__}",
|
|
38
|
+
help="Show the current version and exit"
|
|
39
|
+
)
|
|
18
40
|
|
|
19
41
|
_ = parser.add_argument(
|
|
20
42
|
"--transport",
|
|
@@ -23,6 +45,19 @@ def main() -> None:
|
|
|
23
45
|
help="Transport protocol to use (default: stdio)",
|
|
24
46
|
)
|
|
25
47
|
|
|
48
|
+
_ = parser.add_argument(
|
|
49
|
+
"--port",
|
|
50
|
+
type=int,
|
|
51
|
+
default=3001,
|
|
52
|
+
help="Port to use for SSE transport (default: 3001)",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
_ = parser.add_argument(
|
|
56
|
+
"--host",
|
|
57
|
+
default="0.0.0.0",
|
|
58
|
+
help="Host to bind to for SSE transport (default: 0.0.0.0)",
|
|
59
|
+
)
|
|
60
|
+
|
|
26
61
|
_ = parser.add_argument(
|
|
27
62
|
"--name",
|
|
28
63
|
default="claude-code",
|
|
@@ -39,26 +74,26 @@ def main() -> None:
|
|
|
39
74
|
_ = parser.add_argument(
|
|
40
75
|
"--project-dir", dest="project_dir", help="Set the project directory to analyze"
|
|
41
76
|
)
|
|
42
|
-
|
|
77
|
+
|
|
43
78
|
_ = parser.add_argument(
|
|
44
79
|
"--agent-model",
|
|
45
80
|
dest="agent_model",
|
|
46
81
|
help="Specify the model name in LiteLLM format (e.g., 'openai/gpt-4o', 'anthropic/claude-3-sonnet')"
|
|
47
82
|
)
|
|
48
|
-
|
|
83
|
+
|
|
49
84
|
_ = parser.add_argument(
|
|
50
85
|
"--agent-max-tokens",
|
|
51
86
|
dest="agent_max_tokens",
|
|
52
87
|
type=int,
|
|
53
88
|
help="Specify the maximum tokens for agent responses"
|
|
54
89
|
)
|
|
55
|
-
|
|
90
|
+
|
|
56
91
|
_ = parser.add_argument(
|
|
57
92
|
"--agent-api-key",
|
|
58
93
|
dest="agent_api_key",
|
|
59
94
|
help="Specify the API key for the LLM provider (for development/testing only)"
|
|
60
95
|
)
|
|
61
|
-
|
|
96
|
+
|
|
62
97
|
_ = parser.add_argument(
|
|
63
98
|
"--agent-max-iterations",
|
|
64
99
|
dest="agent_max_iterations",
|
|
@@ -66,7 +101,7 @@ def main() -> None:
|
|
|
66
101
|
default=10,
|
|
67
102
|
help="Maximum number of iterations for agent (default: 10)"
|
|
68
103
|
)
|
|
69
|
-
|
|
104
|
+
|
|
70
105
|
_ = parser.add_argument(
|
|
71
106
|
"--agent-max-tool-uses",
|
|
72
107
|
dest="agent_max_tool_uses",
|
|
@@ -74,7 +109,7 @@ def main() -> None:
|
|
|
74
109
|
default=30,
|
|
75
110
|
help="Maximum number of total tool uses for agent (default: 30)"
|
|
76
111
|
)
|
|
77
|
-
|
|
112
|
+
|
|
78
113
|
_ = parser.add_argument(
|
|
79
114
|
"--enable-agent-tool",
|
|
80
115
|
dest="enable_agent_tool",
|
|
@@ -82,7 +117,23 @@ def main() -> None:
|
|
|
82
117
|
default=False,
|
|
83
118
|
help="Enable the agent tool (disabled by default)"
|
|
84
119
|
)
|
|
85
|
-
|
|
120
|
+
|
|
121
|
+
_ = parser.add_argument(
|
|
122
|
+
"--log-level",
|
|
123
|
+
dest="log_level",
|
|
124
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
|
125
|
+
default="INFO",
|
|
126
|
+
help="Set the logging level (default: INFO)"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
_ = parser.add_argument(
|
|
130
|
+
"--disable-file-logging",
|
|
131
|
+
dest="disable_file_logging",
|
|
132
|
+
action="store_true",
|
|
133
|
+
default=False,
|
|
134
|
+
help="Disable logging to file (logs to console only)"
|
|
135
|
+
)
|
|
136
|
+
|
|
86
137
|
_ = parser.add_argument(
|
|
87
138
|
"--disable-write-tools",
|
|
88
139
|
dest="disable_write_tools",
|
|
@@ -103,6 +154,8 @@ def main() -> None:
|
|
|
103
154
|
name: str = cast(str, args.name)
|
|
104
155
|
install: bool = cast(bool, args.install)
|
|
105
156
|
transport: str = cast(str, args.transport)
|
|
157
|
+
port: int = cast(int, args.port)
|
|
158
|
+
host: str = cast(str, args.host)
|
|
106
159
|
project_dir: str | None = cast(str | None, args.project_dir)
|
|
107
160
|
agent_model: str | None = cast(str | None, args.agent_model)
|
|
108
161
|
agent_max_tokens: int | None = cast(int | None, args.agent_max_tokens)
|
|
@@ -111,17 +164,25 @@ def main() -> None:
|
|
|
111
164
|
agent_max_tool_uses: int = cast(int, args.agent_max_tool_uses)
|
|
112
165
|
enable_agent_tool: bool = cast(bool, args.enable_agent_tool)
|
|
113
166
|
disable_write_tools: bool = cast(bool, args.disable_write_tools)
|
|
167
|
+
log_level: str = cast(str, args.log_level)
|
|
168
|
+
disable_file_logging: bool = cast(bool, args.disable_file_logging)
|
|
114
169
|
allowed_paths: list[str] = (
|
|
115
170
|
cast(list[str], args.allowed_paths) if args.allowed_paths else []
|
|
116
171
|
)
|
|
117
172
|
|
|
173
|
+
# Setup logging
|
|
174
|
+
setup_logging(log_level=log_level, log_to_file=not disable_file_logging, testing="pytest" in sys.modules)
|
|
175
|
+
logger.debug(f"Hanzo MCP CLI started with arguments: {args}")
|
|
176
|
+
|
|
177
|
+
|
|
118
178
|
if install:
|
|
119
|
-
install_claude_desktop_config(name, allowed_paths,
|
|
179
|
+
install_claude_desktop_config(name, allowed_paths, host, port)
|
|
120
180
|
return
|
|
121
181
|
|
|
122
182
|
# If no allowed paths are specified, use the user's home directory
|
|
123
183
|
if not allowed_paths:
|
|
124
184
|
allowed_paths = [str(Path.home())]
|
|
185
|
+
logger.info(f"No allowed paths specified, using home directory: {allowed_paths[0]}")
|
|
125
186
|
|
|
126
187
|
# If project directory is specified, add it to allowed paths
|
|
127
188
|
if project_dir and project_dir not in allowed_paths:
|
|
@@ -140,25 +201,39 @@ def main() -> None:
|
|
|
140
201
|
project_dir = allowed_paths[0]
|
|
141
202
|
|
|
142
203
|
# Run the server
|
|
143
|
-
server
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
204
|
+
logger.info(f"Starting Hanzo MCP server with name: {name}")
|
|
205
|
+
logger.debug(f"Allowed paths: {allowed_paths}")
|
|
206
|
+
logger.debug(f"Project directory: {project_dir}")
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
server = HanzoServer(
|
|
210
|
+
name=name,
|
|
211
|
+
allowed_paths=allowed_paths,
|
|
212
|
+
project_dir=project_dir, # Pass project_dir for initial working directory
|
|
213
|
+
agent_model=agent_model,
|
|
214
|
+
agent_max_tokens=agent_max_tokens,
|
|
215
|
+
agent_api_key=agent_api_key,
|
|
216
|
+
agent_max_iterations=agent_max_iterations,
|
|
217
|
+
agent_max_tool_uses=agent_max_tool_uses,
|
|
218
|
+
enable_agent_tool=enable_agent_tool,
|
|
219
|
+
disable_write_tools=disable_write_tools,
|
|
220
|
+
host=host,
|
|
221
|
+
port=port
|
|
222
|
+
)
|
|
223
|
+
logger.info(f"Server initialized successfully, running with transport: {transport}")
|
|
224
|
+
# Transport will be automatically cast to Literal['stdio', 'sse'] by the server
|
|
225
|
+
server.run(transport=transport)
|
|
226
|
+
except Exception as e:
|
|
227
|
+
logger.error(f"Error starting server: {str(e)}")
|
|
228
|
+
logger.exception("Server startup failed with exception:")
|
|
229
|
+
# Re-raise the exception for proper error handling
|
|
230
|
+
raise
|
|
157
231
|
|
|
158
232
|
|
|
159
233
|
def install_claude_desktop_config(
|
|
160
234
|
name: str = "claude-code", allowed_paths: list[str] | None = None,
|
|
161
|
-
disable_write_tools: bool = False
|
|
235
|
+
disable_write_tools: bool = False,
|
|
236
|
+
host: str = "0.0.0.0", port: int = 3001
|
|
162
237
|
) -> None:
|
|
163
238
|
"""Install the server configuration in Claude Desktop.
|
|
164
239
|
|
|
@@ -168,6 +243,8 @@ def install_claude_desktop_config(
|
|
|
168
243
|
disable_write_tools: Whether to disable write/edit tools (file writing, editing, notebook editing)
|
|
169
244
|
to use IDE tools instead. Note: Shell commands can still modify files.
|
|
170
245
|
(default: False)
|
|
246
|
+
host: Host to bind to for SSE transport (default: '0.0.0.0')
|
|
247
|
+
port: Port to use for SSE transport (default: 3001)
|
|
171
248
|
"""
|
|
172
249
|
# Find the Claude Desktop config directory
|
|
173
250
|
home: Path = Path.home()
|
|
@@ -197,11 +274,19 @@ def install_claude_desktop_config(
|
|
|
197
274
|
else:
|
|
198
275
|
# Allow home directory by default
|
|
199
276
|
args.extend(["--allow-path", str(home)])
|
|
200
|
-
|
|
277
|
+
|
|
278
|
+
# Add host and port
|
|
279
|
+
args.extend(["--host", host])
|
|
280
|
+
args.extend(["--port", str(port)])
|
|
281
|
+
|
|
201
282
|
# Add disable_write_tools flag if specified
|
|
202
283
|
if disable_write_tools:
|
|
203
284
|
args.append("--disable-write-tools")
|
|
204
285
|
|
|
286
|
+
# Add host and port
|
|
287
|
+
args.extend(["--host", host])
|
|
288
|
+
args.extend(["--port", str(port)])
|
|
289
|
+
|
|
205
290
|
# Create config object
|
|
206
291
|
config: dict[str, Any] = {
|
|
207
292
|
"mcpServers": {name: {"command": str(script_path), "args": args}}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
"""MCP server implementing Hanzo capabilities.
|
|
1
|
+
"""MCP server implementing Hanzo capabilities.
|
|
2
|
+
|
|
3
|
+
Includes improved error handling and debugging for tool execution.
|
|
4
|
+
"""
|
|
2
5
|
|
|
3
6
|
from typing import Literal, cast, final
|
|
4
7
|
|
|
@@ -13,7 +16,10 @@ from hanzo_mcp.tools.shell.command_executor import CommandExecutor
|
|
|
13
16
|
|
|
14
17
|
@final
|
|
15
18
|
class HanzoServer:
|
|
16
|
-
"""MCP server implementing Hanzo capabilities.
|
|
19
|
+
"""MCP server implementing Hanzo capabilities.
|
|
20
|
+
|
|
21
|
+
Includes improved error handling and debugging for tool execution.
|
|
22
|
+
"""
|
|
17
23
|
|
|
18
24
|
def __init__(
|
|
19
25
|
self,
|
|
@@ -28,6 +34,8 @@ class HanzoServer:
|
|
|
28
34
|
agent_max_tool_uses: int = 30,
|
|
29
35
|
enable_agent_tool: bool = False,
|
|
30
36
|
disable_write_tools: bool = False,
|
|
37
|
+
host: str = "0.0.0.0",
|
|
38
|
+
port: int = 3001,
|
|
31
39
|
):
|
|
32
40
|
"""Initialize the Hanzo server.
|
|
33
41
|
|
|
@@ -43,6 +51,8 @@ class HanzoServer:
|
|
|
43
51
|
agent_max_tool_uses: Maximum number of total tool uses for agent (default: 30)
|
|
44
52
|
enable_agent_tool: Whether to enable the agent tool (default: False)
|
|
45
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)
|
|
46
56
|
"""
|
|
47
57
|
self.mcp = mcp_instance if mcp_instance is not None else FastMCP(name)
|
|
48
58
|
|
|
@@ -55,7 +65,7 @@ class HanzoServer:
|
|
|
55
65
|
permission_manager=self.permission_manager,
|
|
56
66
|
verbose=False, # Set to True for debugging
|
|
57
67
|
)
|
|
58
|
-
|
|
68
|
+
|
|
59
69
|
# If project_dir is specified, set it as initial working directory for all sessions
|
|
60
70
|
if project_dir:
|
|
61
71
|
initial_session_id = name # Use server name as default session ID
|
|
@@ -83,7 +93,11 @@ class HanzoServer:
|
|
|
83
93
|
self.agent_max_tool_uses = agent_max_tool_uses
|
|
84
94
|
self.enable_agent_tool = enable_agent_tool
|
|
85
95
|
self.disable_write_tools = disable_write_tools
|
|
86
|
-
|
|
96
|
+
|
|
97
|
+
# Store network options
|
|
98
|
+
self.host = host
|
|
99
|
+
self.port = port
|
|
100
|
+
|
|
87
101
|
# Register all tools
|
|
88
102
|
register_all_tools(
|
|
89
103
|
mcp_server=self.mcp,
|
|
@@ -111,6 +125,14 @@ class HanzoServer:
|
|
|
111
125
|
self.permission_manager.add_allowed_path(path)
|
|
112
126
|
self.document_context.add_allowed_path(path)
|
|
113
127
|
|
|
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}")
|
|
135
|
+
|
|
114
136
|
# Run the server
|
|
115
137
|
transport_type = cast(Literal["stdio", "sse"], transport)
|
|
116
138
|
self.mcp.run(transport=transport_type)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Base model provider for agent delegation.
|
|
2
|
+
|
|
3
|
+
Defines the interface for model providers.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseModelProvider(ABC):
|
|
14
|
+
"""Base class for model providers."""
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
async def initialize(self) -> None:
|
|
18
|
+
"""Initialize the provider."""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
async def load_model(self, model_name: str, identifier: Optional[str] = None) -> str:
|
|
23
|
+
"""Load a model.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
model_name: The name of the model to load
|
|
27
|
+
identifier: Optional identifier for the model instance
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
The identifier for the loaded model
|
|
31
|
+
"""
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
async def generate(
|
|
36
|
+
self,
|
|
37
|
+
model_id: str,
|
|
38
|
+
prompt: str,
|
|
39
|
+
system_prompt: Optional[str] = None,
|
|
40
|
+
max_tokens: int = 4096,
|
|
41
|
+
temperature: float = 0.7,
|
|
42
|
+
top_p: float = 0.95,
|
|
43
|
+
stop_sequences: Optional[List[str]] = None,
|
|
44
|
+
) -> Tuple[str, Dict[str, Any]]:
|
|
45
|
+
"""Generate a response from the model.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
model_id: The identifier of the model to use
|
|
49
|
+
prompt: The prompt to send to the model
|
|
50
|
+
system_prompt: Optional system prompt to send to the model
|
|
51
|
+
max_tokens: Maximum number of tokens to generate
|
|
52
|
+
temperature: Sampling temperature
|
|
53
|
+
top_p: Top-p sampling parameter
|
|
54
|
+
stop_sequences: Optional list of strings that will stop generation
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
A tuple of (generated text, metadata)
|
|
58
|
+
"""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
async def unload_model(self, model_id: str) -> None:
|
|
63
|
+
"""Unload a model.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
model_id: The identifier of the model to unload
|
|
67
|
+
"""
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
@abstractmethod
|
|
71
|
+
async def shutdown(self) -> None:
|
|
72
|
+
"""Shutdown the provider."""
|
|
73
|
+
pass
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""LiteLLM provider for agent delegation.
|
|
2
|
+
|
|
3
|
+
Enables the use of various cloud LLM providers via LiteLLM.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import logging
|
|
8
|
+
import json
|
|
9
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
10
|
+
|
|
11
|
+
from hanzo_mcp.tools.agent.base_provider import BaseModelProvider
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
# Define model capabilities
|
|
16
|
+
DEFAULT_MAX_TOKENS = 4096
|
|
17
|
+
DEFAULT_CONTEXT_WINDOW = 8192
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class LiteLLMProvider(BaseModelProvider):
|
|
21
|
+
"""Provider for cloud models via LiteLLM."""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
"""Initialize the LiteLLM provider."""
|
|
25
|
+
self.models = {}
|
|
26
|
+
self.initialized = False
|
|
27
|
+
|
|
28
|
+
async def initialize(self) -> None:
|
|
29
|
+
"""Initialize the LiteLLM provider."""
|
|
30
|
+
if self.initialized:
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
# Import LiteLLM
|
|
35
|
+
import litellm
|
|
36
|
+
self.litellm = litellm
|
|
37
|
+
self.initialized = True
|
|
38
|
+
logger.info("LiteLLM provider initialized successfully")
|
|
39
|
+
except ImportError:
|
|
40
|
+
logger.error("Failed to import LiteLLM")
|
|
41
|
+
logger.error("Install LiteLLM with 'pip install litellm'")
|
|
42
|
+
except Exception as e:
|
|
43
|
+
logger.error(f"Failed to initialize LiteLLM provider: {str(e)}")
|
|
44
|
+
|
|
45
|
+
async def load_model(self, model_name: str, identifier: Optional[str] = None
|