hanzo-mcp 0.9.0__py3-none-any.whl → 0.9.1__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/cli.py +108 -4
- hanzo_mcp/server.py +11 -0
- hanzo_mcp/tools/__init__.py +3 -16
- hanzo_mcp/tools/agent/__init__.py +5 -0
- hanzo_mcp/tools/agent/agent.py +5 -0
- hanzo_mcp/tools/agent/agent_tool.py +3 -17
- hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +623 -0
- hanzo_mcp/tools/agent/clarification_tool.py +7 -1
- hanzo_mcp/tools/agent/claude_desktop_auth.py +16 -6
- hanzo_mcp/tools/agent/cli_agent_base.py +5 -0
- hanzo_mcp/tools/agent/cli_tools.py +26 -0
- hanzo_mcp/tools/agent/code_auth_tool.py +5 -0
- hanzo_mcp/tools/agent/critic_tool.py +7 -1
- hanzo_mcp/tools/agent/iching_tool.py +5 -0
- hanzo_mcp/tools/agent/network_tool.py +5 -0
- hanzo_mcp/tools/agent/review_tool.py +7 -1
- hanzo_mcp/tools/agent/swarm_alias.py +5 -0
- hanzo_mcp/tools/agent/swarm_tool.py +701 -0
- hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +554 -0
- hanzo_mcp/tools/agent/unified_cli_tools.py +5 -0
- hanzo_mcp/tools/common/auto_timeout.py +234 -0
- hanzo_mcp/tools/common/base.py +4 -0
- hanzo_mcp/tools/common/batch_tool.py +5 -0
- hanzo_mcp/tools/common/config_tool.py +5 -0
- hanzo_mcp/tools/common/critic_tool.py +5 -0
- hanzo_mcp/tools/common/paginated_base.py +4 -0
- hanzo_mcp/tools/common/permissions.py +38 -12
- hanzo_mcp/tools/common/personality.py +673 -980
- hanzo_mcp/tools/common/stats.py +5 -0
- hanzo_mcp/tools/common/thinking_tool.py +5 -0
- hanzo_mcp/tools/common/timeout_parser.py +103 -0
- hanzo_mcp/tools/common/tool_disable.py +5 -0
- hanzo_mcp/tools/common/tool_enable.py +5 -0
- hanzo_mcp/tools/common/tool_list.py +5 -0
- hanzo_mcp/tools/config/config_tool.py +5 -0
- hanzo_mcp/tools/config/mode_tool.py +5 -0
- hanzo_mcp/tools/database/graph.py +5 -0
- hanzo_mcp/tools/database/graph_add.py +5 -0
- hanzo_mcp/tools/database/graph_query.py +5 -0
- hanzo_mcp/tools/database/graph_remove.py +5 -0
- hanzo_mcp/tools/database/graph_search.py +5 -0
- hanzo_mcp/tools/database/graph_stats.py +5 -0
- hanzo_mcp/tools/database/sql.py +5 -0
- hanzo_mcp/tools/database/sql_query.py +2 -0
- hanzo_mcp/tools/database/sql_search.py +5 -0
- hanzo_mcp/tools/database/sql_stats.py +5 -0
- hanzo_mcp/tools/editor/neovim_command.py +5 -0
- hanzo_mcp/tools/editor/neovim_edit.py +7 -2
- hanzo_mcp/tools/editor/neovim_session.py +5 -0
- hanzo_mcp/tools/filesystem/__init__.py +23 -26
- hanzo_mcp/tools/filesystem/ast_tool.py +2 -3
- hanzo_mcp/tools/filesystem/base.py +0 -16
- hanzo_mcp/tools/filesystem/batch_search.py +825 -0
- hanzo_mcp/tools/filesystem/content_replace.py +5 -3
- hanzo_mcp/tools/filesystem/diff.py +5 -0
- hanzo_mcp/tools/filesystem/directory_tree.py +34 -281
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +345 -0
- hanzo_mcp/tools/filesystem/edit.py +5 -4
- hanzo_mcp/tools/filesystem/find.py +177 -311
- hanzo_mcp/tools/filesystem/find_files.py +370 -0
- hanzo_mcp/tools/filesystem/git_search.py +5 -3
- hanzo_mcp/tools/filesystem/grep.py +454 -0
- hanzo_mcp/tools/filesystem/multi_edit.py +5 -4
- hanzo_mcp/tools/filesystem/read.py +11 -8
- hanzo_mcp/tools/filesystem/rules_tool.py +5 -3
- hanzo_mcp/tools/filesystem/search_tool.py +728 -0
- hanzo_mcp/tools/filesystem/symbols_tool.py +510 -0
- hanzo_mcp/tools/filesystem/tree.py +273 -0
- hanzo_mcp/tools/filesystem/watch.py +6 -1
- hanzo_mcp/tools/filesystem/write.py +12 -6
- hanzo_mcp/tools/jupyter/jupyter.py +30 -2
- hanzo_mcp/tools/jupyter/notebook_edit.py +298 -0
- hanzo_mcp/tools/jupyter/notebook_read.py +148 -0
- hanzo_mcp/tools/llm/consensus_tool.py +8 -6
- hanzo_mcp/tools/llm/llm_manage.py +5 -0
- hanzo_mcp/tools/llm/llm_tool.py +2 -0
- hanzo_mcp/tools/llm/llm_unified.py +5 -0
- hanzo_mcp/tools/llm/provider_tools.py +5 -0
- hanzo_mcp/tools/lsp/lsp_tool.py +475 -622
- hanzo_mcp/tools/mcp/mcp_add.py +7 -2
- hanzo_mcp/tools/mcp/mcp_remove.py +15 -2
- hanzo_mcp/tools/mcp/mcp_stats.py +5 -0
- hanzo_mcp/tools/mcp/mcp_tool.py +5 -0
- hanzo_mcp/tools/memory/knowledge_tools.py +14 -0
- hanzo_mcp/tools/memory/memory_tools.py +17 -0
- hanzo_mcp/tools/search/find_tool.py +5 -3
- hanzo_mcp/tools/search/unified_search.py +3 -1
- hanzo_mcp/tools/shell/__init__.py +2 -14
- hanzo_mcp/tools/shell/base_process.py +4 -2
- hanzo_mcp/tools/shell/bash_tool.py +2 -0
- hanzo_mcp/tools/shell/command_executor.py +7 -7
- hanzo_mcp/tools/shell/logs.py +5 -0
- hanzo_mcp/tools/shell/npx.py +5 -0
- hanzo_mcp/tools/shell/npx_background.py +5 -0
- hanzo_mcp/tools/shell/npx_tool.py +5 -0
- hanzo_mcp/tools/shell/open.py +5 -0
- hanzo_mcp/tools/shell/pkill.py +5 -0
- hanzo_mcp/tools/shell/process_tool.py +5 -0
- hanzo_mcp/tools/shell/processes.py +5 -0
- hanzo_mcp/tools/shell/run_background.py +5 -0
- hanzo_mcp/tools/shell/run_command.py +2 -0
- hanzo_mcp/tools/shell/run_command_windows.py +5 -0
- hanzo_mcp/tools/shell/streaming_command.py +5 -0
- hanzo_mcp/tools/shell/uvx.py +5 -0
- hanzo_mcp/tools/shell/uvx_background.py +5 -0
- hanzo_mcp/tools/shell/uvx_tool.py +5 -0
- hanzo_mcp/tools/shell/zsh_tool.py +3 -0
- hanzo_mcp/tools/todo/todo.py +5 -0
- hanzo_mcp/tools/todo/todo_read.py +142 -0
- hanzo_mcp/tools/todo/todo_write.py +367 -0
- hanzo_mcp/tools/vector/__init__.py +42 -95
- hanzo_mcp/tools/vector/index_tool.py +5 -0
- hanzo_mcp/tools/vector/vector.py +5 -0
- hanzo_mcp/tools/vector/vector_index.py +5 -0
- hanzo_mcp/tools/vector/vector_search.py +5 -0
- {hanzo_mcp-0.9.0.dist-info → hanzo_mcp-0.9.1.dist-info}/METADATA +1 -1
- hanzo_mcp-0.9.1.dist-info/RECORD +195 -0
- hanzo_mcp/tools/common/path_utils.py +0 -34
- hanzo_mcp/tools/compiler/__init__.py +0 -8
- hanzo_mcp/tools/compiler/sandboxed_compiler.py +0 -681
- hanzo_mcp/tools/environment/__init__.py +0 -8
- hanzo_mcp/tools/environment/environment_detector.py +0 -594
- hanzo_mcp/tools/filesystem/search.py +0 -1160
- hanzo_mcp/tools/framework/__init__.py +0 -8
- hanzo_mcp/tools/framework/framework_modes.py +0 -714
- hanzo_mcp/tools/memory/conversation_memory.py +0 -636
- hanzo_mcp/tools/shell/run_tool.py +0 -56
- hanzo_mcp/tools/vector/node_tool.py +0 -538
- hanzo_mcp/tools/vector/unified_vector.py +0 -384
- hanzo_mcp-0.9.0.dist-info/RECORD +0 -191
- {hanzo_mcp-0.9.0.dist-info → hanzo_mcp-0.9.1.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.9.0.dist-info → hanzo_mcp-0.9.1.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.9.0.dist-info → hanzo_mcp-0.9.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Read notebook tool implementation.
|
|
2
|
+
|
|
3
|
+
This module provides the NotebookReadTool for reading Jupyter notebook files.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from typing import Unpack, Annotated, TypedDict, final, override
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from pydantic import Field
|
|
11
|
+
from mcp.server import FastMCP
|
|
12
|
+
|
|
13
|
+
from hanzo_mcp.tools.common.auto_timeout import auto_timeout
|
|
14
|
+
from mcp.server.fastmcp import Context as MCPContext
|
|
15
|
+
|
|
16
|
+
from hanzo_mcp.tools.jupyter.base import JupyterBaseTool
|
|
17
|
+
|
|
18
|
+
NotebookPath = Annotated[
|
|
19
|
+
str,
|
|
20
|
+
Field(
|
|
21
|
+
description="The absolute path to the Jupyter notebook file to read (must be absolute, not relative)",
|
|
22
|
+
),
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class NotebookReadToolParams(TypedDict):
|
|
27
|
+
"""Parameters for the NotebookReadTool.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
notebook_path: The absolute path to the Jupyter notebook file to read (must be absolute, not relative)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
notebook_path: NotebookPath
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@final
|
|
37
|
+
class NotebookReadTool(JupyterBaseTool):
|
|
38
|
+
"""Tool for reading Jupyter notebook files."""
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
@override
|
|
42
|
+
def name(self) -> str:
|
|
43
|
+
"""Get the tool name.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Tool name
|
|
47
|
+
"""
|
|
48
|
+
return "notebook_read"
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
@override
|
|
52
|
+
def description(self) -> str:
|
|
53
|
+
"""Get the tool description.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Tool description
|
|
57
|
+
"""
|
|
58
|
+
return "Reads a Jupyter notebook (.ipynb file) and returns all of the cells with their outputs. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path."
|
|
59
|
+
|
|
60
|
+
@override
|
|
61
|
+
@auto_timeout("notebook_read")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
async def call(
|
|
65
|
+
self,
|
|
66
|
+
ctx: MCPContext,
|
|
67
|
+
**params: Unpack[NotebookReadToolParams],
|
|
68
|
+
) -> str:
|
|
69
|
+
"""Execute the tool with the given parameters.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
ctx: MCP context
|
|
73
|
+
**params: Tool parameters
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Tool result
|
|
77
|
+
"""
|
|
78
|
+
tool_ctx = self.create_tool_context(ctx)
|
|
79
|
+
self.set_tool_context_info(tool_ctx)
|
|
80
|
+
|
|
81
|
+
# Extract parameters
|
|
82
|
+
notebook_path: NotebookPath = params["notebook_path"]
|
|
83
|
+
|
|
84
|
+
# Validate path parameter
|
|
85
|
+
path_validation = self.validate_path(notebook_path)
|
|
86
|
+
if path_validation.is_error:
|
|
87
|
+
await tool_ctx.error(path_validation.error_message)
|
|
88
|
+
return f"Error: {path_validation.error_message}"
|
|
89
|
+
|
|
90
|
+
await tool_ctx.info(f"Reading notebook: {notebook_path}")
|
|
91
|
+
|
|
92
|
+
# Check if path is allowed
|
|
93
|
+
if not self.is_path_allowed(notebook_path):
|
|
94
|
+
await tool_ctx.error(f"Access denied - path outside allowed directories: {notebook_path}")
|
|
95
|
+
return f"Error: Access denied - path outside allowed directories: {notebook_path}"
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
file_path = Path(notebook_path)
|
|
99
|
+
|
|
100
|
+
if not file_path.exists():
|
|
101
|
+
await tool_ctx.error(f"File does not exist: {notebook_path}")
|
|
102
|
+
return f"Error: File does not exist: {notebook_path}"
|
|
103
|
+
|
|
104
|
+
if not file_path.is_file():
|
|
105
|
+
await tool_ctx.error(f"Path is not a file: {notebook_path}")
|
|
106
|
+
return f"Error: Path is not a file: {notebook_path}"
|
|
107
|
+
|
|
108
|
+
# Check file extension
|
|
109
|
+
if file_path.suffix.lower() != ".ipynb":
|
|
110
|
+
await tool_ctx.error(f"File is not a Jupyter notebook: {notebook_path}")
|
|
111
|
+
return f"Error: File is not a Jupyter notebook: {notebook_path}"
|
|
112
|
+
|
|
113
|
+
# Read and parse the notebook
|
|
114
|
+
try:
|
|
115
|
+
# This will read the file, so we don't need to read it separately
|
|
116
|
+
_, processed_cells = await self.parse_notebook(file_path)
|
|
117
|
+
|
|
118
|
+
# Format the notebook content as a readable string
|
|
119
|
+
result = self.format_notebook_cells(processed_cells)
|
|
120
|
+
|
|
121
|
+
await tool_ctx.info(f"Successfully read notebook: {notebook_path} ({len(processed_cells)} cells)")
|
|
122
|
+
return result
|
|
123
|
+
except json.JSONDecodeError:
|
|
124
|
+
await tool_ctx.error(f"Invalid notebook format: {notebook_path}")
|
|
125
|
+
return f"Error: Invalid notebook format: {notebook_path}"
|
|
126
|
+
except UnicodeDecodeError:
|
|
127
|
+
await tool_ctx.error(f"Cannot read notebook file: {notebook_path}")
|
|
128
|
+
return f"Error: Cannot read notebook file: {notebook_path}"
|
|
129
|
+
except Exception as e:
|
|
130
|
+
await tool_ctx.error(f"Error reading notebook: {str(e)}")
|
|
131
|
+
return f"Error reading notebook: {str(e)}"
|
|
132
|
+
|
|
133
|
+
@override
|
|
134
|
+
def register(self, mcp_server: FastMCP) -> None:
|
|
135
|
+
"""Register this read notebook tool with the MCP server.
|
|
136
|
+
|
|
137
|
+
Creates a wrapper function with explicitly defined parameters that match
|
|
138
|
+
the tool's parameter schema and registers it with the MCP server.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
mcp_server: The FastMCP server instance
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
tool_self = self # Create a reference to self for use in the closure
|
|
145
|
+
|
|
146
|
+
@mcp_server.tool(name=self.name, description=self.description)
|
|
147
|
+
async def notebook_read(notebook_path: NotebookPath, ctx: MCPContext) -> str:
|
|
148
|
+
return await tool_self.call(ctx, notebook_path=notebook_path)
|
|
@@ -15,9 +15,10 @@ from typing import (
|
|
|
15
15
|
from pydantic import Field
|
|
16
16
|
from mcp.server.fastmcp import Context as MCPContext
|
|
17
17
|
|
|
18
|
+
from hanzo_mcp.tools.common.auto_timeout import auto_timeout
|
|
18
19
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
19
20
|
from hanzo_mcp.tools.llm.llm_tool import LLMTool
|
|
20
|
-
from hanzo_mcp.tools.common.context import create_tool_context
|
|
21
|
+
from hanzo_mcp.tools.common.context import create_tool_context, ToolContext
|
|
21
22
|
|
|
22
23
|
Prompt = Annotated[
|
|
23
24
|
str,
|
|
@@ -155,6 +156,7 @@ The tool will:
|
|
|
155
156
|
"""
|
|
156
157
|
|
|
157
158
|
@override
|
|
159
|
+
@auto_timeout("consensus")
|
|
158
160
|
async def call(
|
|
159
161
|
self,
|
|
160
162
|
ctx: MCPContext,
|
|
@@ -269,10 +271,10 @@ The tool will:
|
|
|
269
271
|
if max_tokens:
|
|
270
272
|
params["max_tokens"] = max_tokens
|
|
271
273
|
|
|
272
|
-
# Create a
|
|
273
|
-
|
|
274
|
+
# Create a proper context for the LLM tool
|
|
275
|
+
tool_ctx = create_tool_context("consensus", self.server)
|
|
274
276
|
|
|
275
|
-
result = await asyncio.wait_for(self.llm_tool.call(
|
|
277
|
+
result = await asyncio.wait_for(self.llm_tool.call(tool_ctx, **params), timeout=timeout)
|
|
276
278
|
return (model, result)
|
|
277
279
|
except asyncio.TimeoutError:
|
|
278
280
|
return (model, f"Error: Timeout after {timeout} seconds")
|
|
@@ -317,7 +319,7 @@ Be concise but thorough. Focus on providing actionable insights."""
|
|
|
317
319
|
|
|
318
320
|
try:
|
|
319
321
|
# Use the LLM tool to get the aggregation
|
|
320
|
-
|
|
322
|
+
tool_ctx = create_tool_context("consensus_aggregation", self.server)
|
|
321
323
|
|
|
322
324
|
aggregation_params = {
|
|
323
325
|
"model": aggregation_model,
|
|
@@ -326,7 +328,7 @@ Be concise but thorough. Focus on providing actionable insights."""
|
|
|
326
328
|
"system_prompt": "You are an expert at analyzing and synthesizing multiple AI responses to provide balanced, insightful consensus.",
|
|
327
329
|
}
|
|
328
330
|
|
|
329
|
-
result = await self.llm_tool.call(
|
|
331
|
+
result = await self.llm_tool.call(tool_ctx, **aggregation_params)
|
|
330
332
|
return result
|
|
331
333
|
|
|
332
334
|
except Exception:
|
|
@@ -7,6 +7,8 @@ from pathlib import Path
|
|
|
7
7
|
from pydantic import Field
|
|
8
8
|
from mcp.server.fastmcp import Context as MCPContext
|
|
9
9
|
|
|
10
|
+
from hanzo_mcp.tools.common.auto_timeout import auto_timeout
|
|
11
|
+
|
|
10
12
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
11
13
|
from hanzo_mcp.tools.llm.llm_tool import LLMTool
|
|
12
14
|
from hanzo_mcp.tools.common.context import create_tool_context
|
|
@@ -110,6 +112,9 @@ Providers are automatically detected based on environment variables:
|
|
|
110
112
|
"""
|
|
111
113
|
|
|
112
114
|
@override
|
|
115
|
+
@auto_timeout("llm_manage")
|
|
116
|
+
|
|
117
|
+
|
|
113
118
|
async def call(
|
|
114
119
|
self,
|
|
115
120
|
ctx: MCPContext,
|
hanzo_mcp/tools/llm/llm_tool.py
CHANGED
|
@@ -21,6 +21,7 @@ from mcp.server.fastmcp import Context as MCPContext
|
|
|
21
21
|
|
|
22
22
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
23
23
|
from hanzo_mcp.tools.common.context import create_tool_context
|
|
24
|
+
from hanzo_mcp.tools.common.auto_timeout import auto_timeout
|
|
24
25
|
|
|
25
26
|
# Check if litellm is available
|
|
26
27
|
try:
|
|
@@ -263,6 +264,7 @@ llm --action models --provider openai
|
|
|
263
264
|
Available: {", ".join(available) if available else "None"}"""
|
|
264
265
|
|
|
265
266
|
@override
|
|
267
|
+
@auto_timeout("llm")
|
|
266
268
|
async def call(
|
|
267
269
|
self,
|
|
268
270
|
ctx: MCPContext,
|
|
@@ -19,6 +19,8 @@ from pathlib import Path
|
|
|
19
19
|
from pydantic import Field
|
|
20
20
|
from mcp.server.fastmcp import Context as MCPContext
|
|
21
21
|
|
|
22
|
+
from hanzo_mcp.tools.common.auto_timeout import auto_timeout
|
|
23
|
+
|
|
22
24
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
23
25
|
from hanzo_mcp.tools.common.context import create_tool_context
|
|
24
26
|
|
|
@@ -263,6 +265,9 @@ llm --action models --provider openai
|
|
|
263
265
|
Available: {", ".join(available) if available else "None"}"""
|
|
264
266
|
|
|
265
267
|
@override
|
|
268
|
+
@auto_timeout("llm_unified")
|
|
269
|
+
|
|
270
|
+
|
|
266
271
|
async def call(
|
|
267
272
|
self,
|
|
268
273
|
ctx: MCPContext,
|
|
@@ -5,6 +5,8 @@ from typing import Dict, Unpack, Optional, Annotated, TypedDict, final, override
|
|
|
5
5
|
from pydantic import Field
|
|
6
6
|
from mcp.server.fastmcp import Context as MCPContext
|
|
7
7
|
|
|
8
|
+
from hanzo_mcp.tools.common.auto_timeout import auto_timeout
|
|
9
|
+
|
|
8
10
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
9
11
|
from hanzo_mcp.tools.llm.llm_tool import LLMTool
|
|
10
12
|
|
|
@@ -98,6 +100,9 @@ class BaseProviderTool(BaseTool):
|
|
|
98
100
|
return model
|
|
99
101
|
|
|
100
102
|
@override
|
|
103
|
+
@auto_timeout("provider_tools")
|
|
104
|
+
|
|
105
|
+
|
|
101
106
|
async def call(
|
|
102
107
|
self,
|
|
103
108
|
ctx: MCPContext,
|