hanzo-mcp 0.8.13__py3-none-any.whl → 0.8.15__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/analytics/posthog_analytics.py +14 -1
- hanzo_mcp/server.py +11 -0
- hanzo_mcp/tools/agent/clarification_tool.py +5 -1
- hanzo_mcp/tools/agent/claude_desktop_auth.py +11 -6
- hanzo_mcp/tools/agent/critic_tool.py +5 -1
- hanzo_mcp/tools/agent/review_tool.py +5 -1
- hanzo_mcp/tools/common/permissions.py +35 -2
- hanzo_mcp/tools/editor/neovim_edit.py +2 -2
- hanzo_mcp/tools/jupyter/jupyter.py +25 -2
- hanzo_mcp/tools/llm/consensus_tool.py +6 -6
- hanzo_mcp/tools/mcp/mcp_add.py +2 -2
- hanzo_mcp/tools/mcp/mcp_remove.py +10 -2
- hanzo_mcp/tools/shell/command_executor.py +7 -7
- {hanzo_mcp-0.8.13.dist-info → hanzo_mcp-0.8.15.dist-info}/METADATA +1 -1
- {hanzo_mcp-0.8.13.dist-info → hanzo_mcp-0.8.15.dist-info}/RECORD +19 -19
- {hanzo_mcp-0.8.13.dist-info → hanzo_mcp-0.8.15.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.8.13.dist-info → hanzo_mcp-0.8.15.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.8.13.dist-info → hanzo_mcp-0.8.15.dist-info}/top_level.txt +0 -0
hanzo_mcp/__init__.py
CHANGED
|
@@ -16,6 +16,7 @@ import traceback
|
|
|
16
16
|
from typing import Any, Dict, TypeVar, Callable, Optional
|
|
17
17
|
from datetime import datetime
|
|
18
18
|
from dataclasses import dataclass
|
|
19
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
19
20
|
|
|
20
21
|
# Try to import PostHog, but make it optional
|
|
21
22
|
try:
|
|
@@ -98,7 +99,7 @@ class Analytics:
|
|
|
98
99
|
"timestamp": datetime.utcnow().isoformat(),
|
|
99
100
|
"platform": platform.system(),
|
|
100
101
|
"python_version": platform.python_version(),
|
|
101
|
-
"mcp_version":
|
|
102
|
+
"mcp_version": self._get_package_version(),
|
|
102
103
|
**(properties or {}),
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -179,6 +180,18 @@ class Analytics:
|
|
|
179
180
|
except Exception:
|
|
180
181
|
pass
|
|
181
182
|
|
|
183
|
+
def _get_package_version(self) -> str:
|
|
184
|
+
"""Get the current package version."""
|
|
185
|
+
try:
|
|
186
|
+
return version('hanzo-mcp')
|
|
187
|
+
except PackageNotFoundError:
|
|
188
|
+
# Fallback to hardcoded version if package not installed
|
|
189
|
+
try:
|
|
190
|
+
from hanzo_mcp import __version__
|
|
191
|
+
return __version__
|
|
192
|
+
except ImportError:
|
|
193
|
+
return "0.8.14"
|
|
194
|
+
|
|
182
195
|
def shutdown(self) -> None:
|
|
183
196
|
"""Shutdown analytics client."""
|
|
184
197
|
if self.is_enabled():
|
hanzo_mcp/server.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import os
|
|
4
4
|
import atexit
|
|
5
5
|
import signal
|
|
6
|
+
import secrets
|
|
6
7
|
import logging
|
|
7
8
|
import warnings
|
|
8
9
|
import threading
|
|
@@ -53,6 +54,7 @@ class HanzoMCPServer:
|
|
|
53
54
|
port: int = 8888,
|
|
54
55
|
enabled_tools: dict[str, bool] | None = None,
|
|
55
56
|
disabled_tools: list[str] | None = None,
|
|
57
|
+
auth_token: str | None = None,
|
|
56
58
|
):
|
|
57
59
|
"""Initialize the Hanzo AI server.
|
|
58
60
|
|
|
@@ -80,6 +82,15 @@ class HanzoMCPServer:
|
|
|
80
82
|
# Use enhanced server for automatic context normalization
|
|
81
83
|
self.mcp = mcp_instance if mcp_instance is not None else EnhancedFastMCP(name)
|
|
82
84
|
|
|
85
|
+
# Initialize authentication token
|
|
86
|
+
self.auth_token = auth_token or os.environ.get('HANZO_MCP_TOKEN')
|
|
87
|
+
if not self.auth_token:
|
|
88
|
+
# Generate a secure random token if none provided
|
|
89
|
+
self.auth_token = secrets.token_urlsafe(32)
|
|
90
|
+
logger = logging.getLogger(__name__)
|
|
91
|
+
logger.warning(f"No auth token provided. Generated token: {self.auth_token}")
|
|
92
|
+
logger.warning("Set HANZO_MCP_TOKEN environment variable for persistent auth")
|
|
93
|
+
|
|
83
94
|
# Initialize permissions and command executor
|
|
84
95
|
self.permission_manager = PermissionManager()
|
|
85
96
|
|
|
@@ -50,7 +50,11 @@ request_clarification(
|
|
|
50
50
|
context: Dict[str, Any],
|
|
51
51
|
options: Optional[List[str]] = None,
|
|
52
52
|
) -> str:
|
|
53
|
-
"""
|
|
53
|
+
"""Delegate to AgentTool for actual implementation.
|
|
54
|
+
|
|
55
|
+
This method provides the interface, but the actual clarification logic
|
|
56
|
+
is handled by the AgentTool's execution framework.
|
|
57
|
+
"""
|
|
54
58
|
# This tool is handled specially in the agent execution
|
|
55
59
|
return f"Clarification request: {question}"
|
|
56
60
|
|
|
@@ -186,20 +186,25 @@ class ClaudeDesktopAuth:
|
|
|
186
186
|
|
|
187
187
|
async def _login_headless(self, account: Optional[str]) -> Tuple[bool, str]:
|
|
188
188
|
"""Login in headless mode using TTY automation."""
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
return False, "Headless login
|
|
189
|
+
# Headless login requires browser automation or OAuth flow
|
|
190
|
+
# This is not supported in CLI mode for security reasons
|
|
191
|
+
return False, "Headless login requires browser. Use 'claude login' with --browser flag"
|
|
192
192
|
|
|
193
193
|
async def _exchange_code_for_session(self, code: str, account: Optional[str]) -> bool:
|
|
194
194
|
"""Exchange auth code for session token."""
|
|
195
|
-
#
|
|
196
|
-
|
|
195
|
+
# Create a session from the OAuth code
|
|
196
|
+
import hashlib
|
|
197
|
+
|
|
198
|
+
# Generate a secure session token from the auth code
|
|
199
|
+
session_token = hashlib.sha256(f"{code}:{time.time()}".encode()).hexdigest()
|
|
200
|
+
|
|
197
201
|
session = {
|
|
198
|
-
"access_token":
|
|
202
|
+
"access_token": session_token,
|
|
199
203
|
"account": account or "default",
|
|
200
204
|
"email": account,
|
|
201
205
|
"expires_at": time.time() + 3600 * 24, # 24 hours
|
|
202
206
|
"created_at": time.time(),
|
|
207
|
+
"auth_type": "oauth",
|
|
203
208
|
}
|
|
204
209
|
|
|
205
210
|
try:
|
|
@@ -66,7 +66,11 @@ critic(
|
|
|
66
66
|
file_paths: Optional[List[str]] = None,
|
|
67
67
|
specific_concerns: Optional[str] = None,
|
|
68
68
|
) -> str:
|
|
69
|
-
"""
|
|
69
|
+
"""Delegate to AgentTool for actual implementation.
|
|
70
|
+
|
|
71
|
+
This method provides the interface, but the actual critic logic
|
|
72
|
+
is handled by the AgentTool's execution framework.
|
|
73
|
+
"""
|
|
70
74
|
# This tool is handled specially in the agent execution
|
|
71
75
|
return f"Critic review requested for: {work_description}"
|
|
72
76
|
|
|
@@ -66,7 +66,11 @@ review(
|
|
|
66
66
|
file_paths: Optional[List[str]] = None,
|
|
67
67
|
context: Optional[str] = None,
|
|
68
68
|
) -> str:
|
|
69
|
-
"""
|
|
69
|
+
"""Delegate to AgentTool for actual implementation.
|
|
70
|
+
|
|
71
|
+
This method provides the interface, but the actual review logic
|
|
72
|
+
is handled by the AgentTool's execution framework.
|
|
73
|
+
"""
|
|
70
74
|
# This tool is handled specially in the agent execution
|
|
71
75
|
return f"Review requested for: {work_description}"
|
|
72
76
|
|
|
@@ -112,7 +112,7 @@ class PermissionManager:
|
|
|
112
112
|
self.excluded_patterns.append(pattern)
|
|
113
113
|
|
|
114
114
|
def is_path_allowed(self, path: str) -> bool:
|
|
115
|
-
"""Check if a path is allowed.
|
|
115
|
+
"""Check if a path is allowed with security validation.
|
|
116
116
|
|
|
117
117
|
Args:
|
|
118
118
|
path: The path to check
|
|
@@ -120,7 +120,24 @@ class PermissionManager:
|
|
|
120
120
|
Returns:
|
|
121
121
|
True if the path is allowed, False otherwise
|
|
122
122
|
"""
|
|
123
|
-
|
|
123
|
+
# Security check: Reject paths with traversal attempts
|
|
124
|
+
if ".." in str(path) or "~" in str(path):
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
# Resolve the path (follows symlinks and makes absolute)
|
|
129
|
+
resolved_path: Path = Path(path).resolve(strict=False)
|
|
130
|
+
|
|
131
|
+
# Security check: Ensure resolved path doesn't escape allowed directories
|
|
132
|
+
# by checking if it's actually under an allowed path after resolution
|
|
133
|
+
original_path = Path(path)
|
|
134
|
+
if original_path.is_absolute() and str(resolved_path) != str(original_path.resolve(strict=False)):
|
|
135
|
+
# Path resolution changed the path significantly, might be symlink attack
|
|
136
|
+
# Additional check: is the resolved path still under allowed paths?
|
|
137
|
+
pass # Continue to normal checks
|
|
138
|
+
except (OSError, RuntimeError) as e:
|
|
139
|
+
# Path resolution failed, deny access
|
|
140
|
+
return False
|
|
124
141
|
|
|
125
142
|
# Check exclusions first
|
|
126
143
|
if self._is_path_excluded(resolved_path):
|
|
@@ -129,12 +146,28 @@ class PermissionManager:
|
|
|
129
146
|
# Check if the path is within any allowed path
|
|
130
147
|
for allowed_path in self.allowed_paths:
|
|
131
148
|
try:
|
|
149
|
+
# This will raise ValueError if resolved_path is not under allowed_path
|
|
132
150
|
resolved_path.relative_to(allowed_path)
|
|
151
|
+
# Additional check: ensure no symlinks are escaping the allowed directory
|
|
152
|
+
if resolved_path.exists() and resolved_path.is_symlink():
|
|
153
|
+
link_target = Path(os.readlink(resolved_path))
|
|
154
|
+
if link_target.is_absolute():
|
|
155
|
+
# Absolute symlink - check if it points within allowed paths
|
|
156
|
+
if not any(self._is_subpath(link_target, ap) for ap in self.allowed_paths):
|
|
157
|
+
return False
|
|
133
158
|
return True
|
|
134
159
|
except ValueError:
|
|
135
160
|
continue
|
|
136
161
|
|
|
137
162
|
return False
|
|
163
|
+
|
|
164
|
+
def _is_subpath(self, child: Path, parent: Path) -> bool:
|
|
165
|
+
"""Check if child is a subpath of parent."""
|
|
166
|
+
try:
|
|
167
|
+
child.resolve().relative_to(parent.resolve())
|
|
168
|
+
return True
|
|
169
|
+
except ValueError:
|
|
170
|
+
return False
|
|
138
171
|
|
|
139
172
|
def _is_path_excluded(self, path: Path) -> bool:
|
|
140
173
|
"""Check if a path is excluded.
|
|
@@ -252,7 +252,7 @@ Or visit: https://neovim.io/"""
|
|
|
252
252
|
end if
|
|
253
253
|
end tell"""
|
|
254
254
|
|
|
255
|
-
subprocess.run(["osascript", "-e", applescript])
|
|
255
|
+
subprocess.run(["osascript", "-e", applescript], timeout=10)
|
|
256
256
|
return f"Opened {file_path} in Neovim (new terminal window)"
|
|
257
257
|
|
|
258
258
|
elif shutil.which("gnome-terminal"):
|
|
@@ -272,7 +272,7 @@ Or visit: https://neovim.io/"""
|
|
|
272
272
|
|
|
273
273
|
else:
|
|
274
274
|
# Run and wait for completion
|
|
275
|
-
result = subprocess.run(cmd)
|
|
275
|
+
result = subprocess.run(cmd, timeout=120)
|
|
276
276
|
|
|
277
277
|
if result.returncode == 0:
|
|
278
278
|
return f"Successfully edited {file_path} in Neovim"
|
|
@@ -311,8 +311,31 @@ jupyter --action create "new.ipynb"
|
|
|
311
311
|
return f"Error deleting notebook: {str(e)}"
|
|
312
312
|
|
|
313
313
|
async def _handle_execute(self, notebook_path: str, params: Dict[str, Any], tool_ctx) -> str:
|
|
314
|
-
"""Execute notebook cells
|
|
315
|
-
|
|
314
|
+
"""Execute notebook cells using nbclient."""
|
|
315
|
+
try:
|
|
316
|
+
import nbclient
|
|
317
|
+
from nbclient import NotebookClient
|
|
318
|
+
|
|
319
|
+
nb = nbformat.read(notebook_path, as_version=4)
|
|
320
|
+
|
|
321
|
+
# Create a notebook client with default kernel
|
|
322
|
+
client = NotebookClient(
|
|
323
|
+
nb,
|
|
324
|
+
timeout=params.get('timeout', 600),
|
|
325
|
+
kernel_name=params.get('kernel_name', 'python3')
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
# Execute the notebook
|
|
329
|
+
await client.async_execute()
|
|
330
|
+
|
|
331
|
+
# Save the executed notebook
|
|
332
|
+
nbformat.write(nb, notebook_path)
|
|
333
|
+
|
|
334
|
+
return f"Successfully executed all cells in {notebook_path}"
|
|
335
|
+
except ImportError:
|
|
336
|
+
return "Error: nbclient not installed. Install with: pip install nbclient"
|
|
337
|
+
except Exception as e:
|
|
338
|
+
return f"Error executing notebook: {str(e)}"
|
|
316
339
|
|
|
317
340
|
def _format_cell(self, cell: dict, index: int) -> str:
|
|
318
341
|
"""Format a single cell for display."""
|
|
@@ -17,7 +17,7 @@ from mcp.server.fastmcp import Context as MCPContext
|
|
|
17
17
|
|
|
18
18
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
19
19
|
from hanzo_mcp.tools.llm.llm_tool import LLMTool
|
|
20
|
-
from hanzo_mcp.tools.common.context import create_tool_context
|
|
20
|
+
from hanzo_mcp.tools.common.context import create_tool_context, ToolContext
|
|
21
21
|
|
|
22
22
|
Prompt = Annotated[
|
|
23
23
|
str,
|
|
@@ -269,10 +269,10 @@ The tool will:
|
|
|
269
269
|
if max_tokens:
|
|
270
270
|
params["max_tokens"] = max_tokens
|
|
271
271
|
|
|
272
|
-
# Create a
|
|
273
|
-
|
|
272
|
+
# Create a proper context for the LLM tool
|
|
273
|
+
tool_ctx = create_tool_context("consensus", self.server)
|
|
274
274
|
|
|
275
|
-
result = await asyncio.wait_for(self.llm_tool.call(
|
|
275
|
+
result = await asyncio.wait_for(self.llm_tool.call(tool_ctx, **params), timeout=timeout)
|
|
276
276
|
return (model, result)
|
|
277
277
|
except asyncio.TimeoutError:
|
|
278
278
|
return (model, f"Error: Timeout after {timeout} seconds")
|
|
@@ -317,7 +317,7 @@ Be concise but thorough. Focus on providing actionable insights."""
|
|
|
317
317
|
|
|
318
318
|
try:
|
|
319
319
|
# Use the LLM tool to get the aggregation
|
|
320
|
-
|
|
320
|
+
tool_ctx = create_tool_context("consensus_aggregation", self.server)
|
|
321
321
|
|
|
322
322
|
aggregation_params = {
|
|
323
323
|
"model": aggregation_model,
|
|
@@ -326,7 +326,7 @@ Be concise but thorough. Focus on providing actionable insights."""
|
|
|
326
326
|
"system_prompt": "You are an expert at analyzing and synthesizing multiple AI responses to provide balanced, insightful consensus.",
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
result = await self.llm_tool.call(
|
|
329
|
+
result = await self.llm_tool.call(tool_ctx, **aggregation_params)
|
|
330
330
|
return result
|
|
331
331
|
|
|
332
332
|
except Exception:
|
hanzo_mcp/tools/mcp/mcp_add.py
CHANGED
|
@@ -219,8 +219,8 @@ Use 'mcp_stats' to see all added servers and their status.
|
|
|
219
219
|
if not shutil.which("uvx"):
|
|
220
220
|
return "Error: uvx not found. Install uv first."
|
|
221
221
|
|
|
222
|
-
#
|
|
223
|
-
#
|
|
222
|
+
# Server is validated and ready to be used
|
|
223
|
+
# The actual connection happens when tools are invoked
|
|
224
224
|
server_config["status"] = "ready"
|
|
225
225
|
|
|
226
226
|
except Exception as e:
|
|
@@ -103,8 +103,16 @@ Use 'mcp_stats' to see all servers before removing.
|
|
|
103
103
|
if not force:
|
|
104
104
|
return f"Error: Server '{name}' is currently running. Use --force to remove anyway."
|
|
105
105
|
else:
|
|
106
|
-
#
|
|
107
|
-
|
|
106
|
+
# Stop the server process if it's running
|
|
107
|
+
process_id = server.get("process_id")
|
|
108
|
+
if process_id:
|
|
109
|
+
try:
|
|
110
|
+
import signal
|
|
111
|
+
import os
|
|
112
|
+
os.kill(process_id, signal.SIGTERM)
|
|
113
|
+
await tool_ctx.info(f"Stopped running server '{name}' (PID: {process_id})")
|
|
114
|
+
except ProcessLookupError:
|
|
115
|
+
await tool_ctx.info(f"Server '{name}' process not found (already stopped)")
|
|
108
116
|
|
|
109
117
|
# Remove from registry
|
|
110
118
|
del McpAddTool._mcp_servers[name]
|
|
@@ -109,13 +109,12 @@ class CommandExecutor:
|
|
|
109
109
|
if shell_basename in ["wsl", "wsl.exe"]:
|
|
110
110
|
# For WSL, handle commands with shell operators differently
|
|
111
111
|
if any(char in command for char in ";&|<>(){}[]$\"'`"):
|
|
112
|
-
#
|
|
113
|
-
|
|
114
|
-
escaped_command = command.replace('"', '\\"')
|
|
112
|
+
# Use shlex.quote for proper escaping to prevent command injection
|
|
113
|
+
escaped_command = shlex.quote(command)
|
|
115
114
|
if use_login_shell:
|
|
116
|
-
formatted_command = f'{user_shell} bash -l -c
|
|
115
|
+
formatted_command = f'{user_shell} bash -l -c {escaped_command}'
|
|
117
116
|
else:
|
|
118
|
-
formatted_command = f'{user_shell} bash -c
|
|
117
|
+
formatted_command = f'{user_shell} bash -c {escaped_command}'
|
|
119
118
|
else:
|
|
120
119
|
# # For simple commands without special characters
|
|
121
120
|
# # Still respect login shell preference
|
|
@@ -125,8 +124,9 @@ class CommandExecutor:
|
|
|
125
124
|
formatted_command = f"{user_shell} {command}"
|
|
126
125
|
|
|
127
126
|
elif shell_basename in ["powershell", "powershell.exe", "pwsh", "pwsh.exe"]:
|
|
128
|
-
#
|
|
129
|
-
|
|
127
|
+
# Use proper escaping for PowerShell to prevent injection
|
|
128
|
+
# PowerShell requires different escaping than POSIX shells
|
|
129
|
+
escaped_command = command.replace('"', '`"').replace("'", "``'").replace('$', '`$')
|
|
130
130
|
formatted_command = f'"{user_shell}" -Command "{escaped_command}"'
|
|
131
131
|
|
|
132
132
|
else:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
hanzo_mcp/__init__.py,sha256=
|
|
1
|
+
hanzo_mcp/__init__.py,sha256=CiiAhLNcOwQWEFcxsXct2OS3eKsCLcyc2o-FHh6wpiQ,863
|
|
2
2
|
hanzo_mcp/__main__.py,sha256=EvDEygOjvP6S_CrZSL8E4qgGUcO_xfmzEIbsLEHPaK4,130
|
|
3
3
|
hanzo_mcp/bridge.py,sha256=ObrWXK01tthz7SmlGie7S-W5bn8xT9M-utCBbDie6wc,14853
|
|
4
4
|
hanzo_mcp/cli.py,sha256=ZljeP_yS-LcPRQ4E-A3g91VYoYvee1Kh-t6wUva6tSA,14751
|
|
@@ -6,11 +6,11 @@ hanzo_mcp/cli_enhanced.py,sha256=iwYreGC6GiCqfFWDlRzMOmDqHKVm_qD7YD6I2nOxlpY,159
|
|
|
6
6
|
hanzo_mcp/cli_plugin.py,sha256=WvqxDrErFXlgv5ZejMsrN78FsPLq9Gi_DoteFTPlcXU,3143
|
|
7
7
|
hanzo_mcp/compute_nodes.py,sha256=mFHQdxyo_SEeiwrQaPg-V9q2xmMRQiO7X_NePrWhSZ4,6315
|
|
8
8
|
hanzo_mcp/dev_server.py,sha256=uBGdvpK8rXPgLSoYv1quOIrCQnsUf02FwmYcTu8SvSI,8231
|
|
9
|
-
hanzo_mcp/server.py,sha256=
|
|
9
|
+
hanzo_mcp/server.py,sha256=WHUV0FU0LBozPmHbPaImv9r_g0PDoAGrMol8Cn3iNSk,11000
|
|
10
10
|
hanzo_mcp/server_enhanced.py,sha256=bBrObdysyda6Ggf-E3aL7UwktUNzYO_HG1V45Av5r-E,2003
|
|
11
11
|
hanzo_mcp/types.py,sha256=4YjIJmM7byrsY4eN10pbhIUpFMQ-fZrpK6scgt-U9dU,648
|
|
12
12
|
hanzo_mcp/analytics/__init__.py,sha256=ANyntTooBrpa_uvwE6KbYxB9uda610UT10pt2rrLiUU,213
|
|
13
|
-
hanzo_mcp/analytics/posthog_analytics.py,sha256=
|
|
13
|
+
hanzo_mcp/analytics/posthog_analytics.py,sha256=k_LcXHznKd-Wbqrq1v8azsTVuPDd7Fw1BE244OhQtPM,11086
|
|
14
14
|
hanzo_mcp/config/__init__.py,sha256=1ifMucAN-htFEGdRpiC1T809Q03Bd7YUE5ATOHNi6Po,505
|
|
15
15
|
hanzo_mcp/config/settings.py,sha256=doZFlgwVyQHH4PMThHB6U2USTA0TfzqFag8n1JiFeK4,18859
|
|
16
16
|
hanzo_mcp/config/tool_config.py,sha256=N2yQSb3D5TtA_EDHxGaY_UFotAqonXMOXLwyBUjv_EU,6828
|
|
@@ -31,21 +31,21 @@ hanzo_mcp/tools/agent/agent.py,sha256=CNiR4LA3E1vJcD5OUfzAEgPNVcHMYPy29B98TP948f
|
|
|
31
31
|
hanzo_mcp/tools/agent/agent_tool.py,sha256=gP68MnrI8zdtcI7HqSDc_fj213vw3-G97_napfoZXhU,16712
|
|
32
32
|
hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py,sha256=IeM5jz8NlIyJi5Q8AKuyyvbfY5CzhTujRpUd9EuV54Q,26118
|
|
33
33
|
hanzo_mcp/tools/agent/clarification_protocol.py,sha256=QYJTmDSJVRDyZMow80TxWmnJurxuLo1MaIFge8t_Yvk,8041
|
|
34
|
-
hanzo_mcp/tools/agent/clarification_tool.py,sha256=
|
|
34
|
+
hanzo_mcp/tools/agent/clarification_tool.py,sha256=fxkN4VSq9sRYABj3ap5Igg8DYmV2HgJ00jhZmDm9ITw,2578
|
|
35
35
|
hanzo_mcp/tools/agent/claude_cli_tool.py,sha256=55Wc0LKgYCtDKQ02NXOYPMhx-sW7fL_NSCx0upsvvb4,3812
|
|
36
|
-
hanzo_mcp/tools/agent/claude_desktop_auth.py,sha256=
|
|
36
|
+
hanzo_mcp/tools/agent/claude_desktop_auth.py,sha256=zvm70alW1mPNMgWJ0E2iNSyOYq5YB0qHCZXyJLikiGY,16362
|
|
37
37
|
hanzo_mcp/tools/agent/cli_agent_base.py,sha256=4F2iOk6nvB63wcxb1ZLuZyK2USWRFizZvcnBWdMes28,6190
|
|
38
38
|
hanzo_mcp/tools/agent/cli_tools.py,sha256=eOFOlyWX_BExduAuBppTwQXbYGKhKlMC1pOAFhwFNVs,16116
|
|
39
39
|
hanzo_mcp/tools/agent/code_auth.py,sha256=97g3qqBBJNfGdoUppVhc2-BzvyWJVQUe9sYUYS9cBmQ,13902
|
|
40
40
|
hanzo_mcp/tools/agent/code_auth_tool.py,sha256=blxLpYxamH-BXSySWp8D1zDdqC82GUBhd8U7pGSPugU,6105
|
|
41
41
|
hanzo_mcp/tools/agent/codex_cli_tool.py,sha256=9jyB4cTtdcK50g6oapk7Bo4n8C8bAO2B9RuHHLOtP54,3697
|
|
42
|
-
hanzo_mcp/tools/agent/critic_tool.py,sha256
|
|
42
|
+
hanzo_mcp/tools/agent/critic_tool.py,sha256=-K1PrNz03G9EGF3Ez7gDNk0OT7ze6Le74qJK3pJtl2w,13897
|
|
43
43
|
hanzo_mcp/tools/agent/gemini_cli_tool.py,sha256=4PE7qYGlFC6_u0T2_Yh3WfBqZjuZM4UY2rPBkKtwaEU,3927
|
|
44
44
|
hanzo_mcp/tools/agent/grok_cli_tool.py,sha256=YH1qweHDWDm-Yo84gcw_bL2w_vIdhSc6f7LNJlAHSeQ,3761
|
|
45
45
|
hanzo_mcp/tools/agent/iching_tool.py,sha256=v29rVUM2yaY1vlpab00G3RsUuFEfE_RwPixGGe1tOUU,23314
|
|
46
46
|
hanzo_mcp/tools/agent/network_tool.py,sha256=rD9kEAqBY8SCh1Spey6ifhlIfRAbGEbDSZowoTFZPVw,8340
|
|
47
47
|
hanzo_mcp/tools/agent/prompt.py,sha256=16UWq8cxCPDWru5V8izcBqqorEohCxhQkh4KLPzcibI,6782
|
|
48
|
-
hanzo_mcp/tools/agent/review_tool.py,sha256=
|
|
48
|
+
hanzo_mcp/tools/agent/review_tool.py,sha256=plJowtV9fwf-EuJWFfRE9JxROTDSbjLcCrlucWxhnGU,16704
|
|
49
49
|
hanzo_mcp/tools/agent/swarm_alias.py,sha256=pbTtNXuwiWwXlywNeAgNmgTo5DdfpE5SRKtnwPD5-no,2970
|
|
50
50
|
hanzo_mcp/tools/agent/swarm_tool.py,sha256=nkTjGof-E3O0kaCtWGbpDx5wY5vapsCbwJlWvk2JxEI,22152
|
|
51
51
|
hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py,sha256=bo5QmIiIEOERGL2moPqIYoe7bDmyJkBLzv00D2e0pDE,20200
|
|
@@ -67,7 +67,7 @@ hanzo_mcp/tools/common/mode_loader.py,sha256=Q5PtbGoLEpcGnZchoGPrlf6HA1kZK32PLzi
|
|
|
67
67
|
hanzo_mcp/tools/common/paginated_base.py,sha256=fea1MIwghSPEg9MVs1un3XqF2xIHbbKywcrBPPsLdng,8437
|
|
68
68
|
hanzo_mcp/tools/common/paginated_response.py,sha256=Y2PfXlnFYuKMir9BvYcKBc3nVgX6k7l5gs1eFGmiQF0,9942
|
|
69
69
|
hanzo_mcp/tools/common/pagination.py,sha256=vLO-DwjgzhlHmykkMdy5AAzEak5htv8qgxETnpsnqG4,6033
|
|
70
|
-
hanzo_mcp/tools/common/permissions.py,sha256=
|
|
70
|
+
hanzo_mcp/tools/common/permissions.py,sha256=DkpVDNq1tua4QmCIT-ZQH9kUBQJYcqRfyG5jc0Khhx4,9581
|
|
71
71
|
hanzo_mcp/tools/common/personality.py,sha256=MiT8QlOGzWGYlWuGgxokFcQU6bUbTWdpsEFBrTyB360,37315
|
|
72
72
|
hanzo_mcp/tools/common/plugin_loader.py,sha256=dVmwi-_sYfnTqIK_MbD1rBBp5I6Av8A6bF6-VAsOqSA,8701
|
|
73
73
|
hanzo_mcp/tools/common/stats.py,sha256=6QppW1BuSSj_IbadXGlPNoAVDuh9Azn9K76p8ZUvoH4,9565
|
|
@@ -96,7 +96,7 @@ hanzo_mcp/tools/database/sql_search.py,sha256=MLL4isK3hO2Vl7TFBkCvtNyo1Z4GAYMB7M
|
|
|
96
96
|
hanzo_mcp/tools/database/sql_stats.py,sha256=DPr9wDw5cQNmlX6qrbTXDcfs-somAx3Ufs3bcfPP31U,8699
|
|
97
97
|
hanzo_mcp/tools/editor/__init__.py,sha256=UfwWP23OUFmd6dYRwm2fKfaYDlignQ2gfi32yRson08,331
|
|
98
98
|
hanzo_mcp/tools/editor/neovim_command.py,sha256=OAmgF2bOoWbksvWAO5ZB-bP7p-y35AWHeBbfU3S8-0c,8024
|
|
99
|
-
hanzo_mcp/tools/editor/neovim_edit.py,sha256=
|
|
99
|
+
hanzo_mcp/tools/editor/neovim_edit.py,sha256=IJhUq5A8PImc6_XA2yXEIEfX-OLMhTo2TRqLCM_YTww,8615
|
|
100
100
|
hanzo_mcp/tools/editor/neovim_session.py,sha256=oegYqCQdTTkQxoL9a5qB--UsaK_pmBBBazmI8QUW1cY,11659
|
|
101
101
|
hanzo_mcp/tools/filesystem/__init__.py,sha256=bj4xfqzZuABKzGi1G0qgk5IIDsFlOa6k2nQLYLc28dc,8532
|
|
102
102
|
hanzo_mcp/tools/filesystem/ast_multi_edit.py,sha256=kxJL-Nicav9Tn6BcDPBFKGq67XLWhtYgF1NV7UlhzK4,22180
|
|
@@ -123,11 +123,11 @@ hanzo_mcp/tools/filesystem/watch.py,sha256=42O4HBnkzvokxK8ZGtjEnSiM2-s4rsY_41ZKr
|
|
|
123
123
|
hanzo_mcp/tools/filesystem/write.py,sha256=hf2Jra9B1bQoZXip9ssQ7_-Q2UPMiF0uVAEjN4dJmXg,4686
|
|
124
124
|
hanzo_mcp/tools/jupyter/__init__.py,sha256=-7uAomIx8tboZ9gcal7t2MRvgZ9A3cltIYA4perfZVE,2646
|
|
125
125
|
hanzo_mcp/tools/jupyter/base.py,sha256=4O8iMBNqlrCNFEbsihpHyX_nyUqLV7w3AWb_0kcKD14,9788
|
|
126
|
-
hanzo_mcp/tools/jupyter/jupyter.py,sha256=
|
|
126
|
+
hanzo_mcp/tools/jupyter/jupyter.py,sha256=VfaP9gsM4NrZvcfC7SsO8_AAHlMMd4h0OPLZ4Y_FBFg,14840
|
|
127
127
|
hanzo_mcp/tools/jupyter/notebook_edit.py,sha256=Vz6isDmVJfZUvSb3xLi27AXYC9crEIImHP3GshiS7Gw,11377
|
|
128
128
|
hanzo_mcp/tools/jupyter/notebook_read.py,sha256=9pcslhUwuQK5Vpfi9ZUraSwkOk0YRGtaVQj6bkXsC3o,5120
|
|
129
129
|
hanzo_mcp/tools/llm/__init__.py,sha256=4j8X6wqwchBEur0KYqsmPebRw8ZthDj9StpC41csk0M,1524
|
|
130
|
-
hanzo_mcp/tools/llm/consensus_tool.py,sha256=
|
|
130
|
+
hanzo_mcp/tools/llm/consensus_tool.py,sha256=1S1CYmOa4wZWelvpv1s6IrkHKe64fOeVLmDPjtifUiw,11352
|
|
131
131
|
hanzo_mcp/tools/llm/llm_manage.py,sha256=i4AKypbBNWs0FmMXsKZMm0bN5eI1Rl2SmGWBbiKuGjA,15954
|
|
132
132
|
hanzo_mcp/tools/llm/llm_tool.py,sha256=_UK94gyz_xg_ClXAWq7lDfoMKcqgxVAo8ssdoCL_9Gg,29573
|
|
133
133
|
hanzo_mcp/tools/llm/llm_unified.py,sha256=YCkKmof8eEEgv-nygfkT2zVVJPxxPAvq5AmtNdLrb40,28833
|
|
@@ -135,8 +135,8 @@ hanzo_mcp/tools/llm/provider_tools.py,sha256=LpWsBphq1LaJofpPKQxsBXPCD69uUDAsTbL
|
|
|
135
135
|
hanzo_mcp/tools/lsp/__init__.py,sha256=2Z1edOMrLV6gi1dyGgUyN3lN4HOWynf73Eye_eBk2Xo,150
|
|
136
136
|
hanzo_mcp/tools/lsp/lsp_tool.py,sha256=GDmveLFV-k3UKpzV9XaET2WOVMV_t7B3IxBb204_RhM,19261
|
|
137
137
|
hanzo_mcp/tools/mcp/__init__.py,sha256=Rml2im2dg4wNra4nsDH09q73G-yoifQrXL9iYhPmfTg,347
|
|
138
|
-
hanzo_mcp/tools/mcp/mcp_add.py,sha256=
|
|
139
|
-
hanzo_mcp/tools/mcp/mcp_remove.py,sha256=
|
|
138
|
+
hanzo_mcp/tools/mcp/mcp_add.py,sha256=Rfmld4eefYfKfx5PuZx_58Ma2tmrklFRraZA4iRnG-8,7827
|
|
139
|
+
hanzo_mcp/tools/mcp/mcp_remove.py,sha256=d6d7Yctn7JkClQKPtP4KacCNl33GzSmdWc18Fbf5xMI,3659
|
|
140
140
|
hanzo_mcp/tools/mcp/mcp_stats.py,sha256=f3UNVnppBbNHMizZ1W3Goxed5YRmLs30m3zqURUiucs,5273
|
|
141
141
|
hanzo_mcp/tools/mcp/mcp_tool.py,sha256=fUL01Zr6yI6FH_Yrxx3vtonQlEfAX5g61fp2ET_vq2Q,16549
|
|
142
142
|
hanzo_mcp/tools/memory/__init__.py,sha256=GQ17ESC6ecPkBEDtAnOYPfHQaXRrs9sr-jv8sUcvKcw,3167
|
|
@@ -152,7 +152,7 @@ hanzo_mcp/tools/shell/base_process.py,sha256=2UVZ-OD82z0mMu71aEM9hAXw5iEATGIM8x7
|
|
|
152
152
|
hanzo_mcp/tools/shell/bash_session.py,sha256=OPWajWdEan9-LBCdQGgh-hCP7bNXh_OuehaNrEXIz3Q,27058
|
|
153
153
|
hanzo_mcp/tools/shell/bash_session_executor.py,sha256=vHduqxC8H4iJqmuQrWaN0FnykOHTPDZQSHQPeJBaYkI,10714
|
|
154
154
|
hanzo_mcp/tools/shell/bash_tool.py,sha256=gnINuifEYTwRsoO3b0vWNgtNT35whwBbW-JRld6WK6k,3685
|
|
155
|
-
hanzo_mcp/tools/shell/command_executor.py,sha256=
|
|
155
|
+
hanzo_mcp/tools/shell/command_executor.py,sha256=djNPK2RSRLGaBYY3_xqnwIQ61sm4OHWvOXTZsD1P3qs,35453
|
|
156
156
|
hanzo_mcp/tools/shell/logs.py,sha256=4qEtn1HjcnjTuJ1wmH8zywB48SWvXCaC1edaZZxjJOw,8218
|
|
157
157
|
hanzo_mcp/tools/shell/npx.py,sha256=EtrgyDu1UySN995fFAznL8rNLpjkMYGXIj98L59VBCc,4965
|
|
158
158
|
hanzo_mcp/tools/shell/npx_background.py,sha256=_hFAw8tDXGHC8BTd-g5gOq0izFoOubQv0F_TjKz0zq0,7107
|
|
@@ -186,8 +186,8 @@ hanzo_mcp/tools/vector/project_manager.py,sha256=usxOldFajm7UN-74yN7Qa5Xw7Or6EWm
|
|
|
186
186
|
hanzo_mcp/tools/vector/vector.py,sha256=ETcukhy5hGDngEWa-zDZMmZxeh4fBds-yyPQeWHiBms,9871
|
|
187
187
|
hanzo_mcp/tools/vector/vector_index.py,sha256=UWCsWr_7ijv4sEeyLlBfLrxyT_HIS4z9WfIsQVR1Vic,4176
|
|
188
188
|
hanzo_mcp/tools/vector/vector_search.py,sha256=q9MA0clubMAqmaShfLSr_PHSpB7z0zkOAAJbfyM4DFI,9303
|
|
189
|
-
hanzo_mcp-0.8.
|
|
190
|
-
hanzo_mcp-0.8.
|
|
191
|
-
hanzo_mcp-0.8.
|
|
192
|
-
hanzo_mcp-0.8.
|
|
193
|
-
hanzo_mcp-0.8.
|
|
189
|
+
hanzo_mcp-0.8.15.dist-info/METADATA,sha256=Z4Z7MOHYLh5Ia03HOur-KLzjpJTBI8_-pomft79Ca_Y,8975
|
|
190
|
+
hanzo_mcp-0.8.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
191
|
+
hanzo_mcp-0.8.15.dist-info/entry_points.txt,sha256=ML30pedHV5wjthfztzMMz3uYhNdR_6inzYY5pSqNME4,142
|
|
192
|
+
hanzo_mcp-0.8.15.dist-info/top_level.txt,sha256=eGFANatA0MHWiVlpS56fTYRIShtibrSom1uXI6XU0GU,10
|
|
193
|
+
hanzo_mcp-0.8.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|