hanzo-mcp 0.5.0__py3-none-any.whl → 0.5.2__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/config/settings.py +61 -0
- hanzo_mcp/tools/__init__.py +158 -12
- hanzo_mcp/tools/common/base.py +7 -2
- hanzo_mcp/tools/common/config_tool.py +396 -0
- hanzo_mcp/tools/common/stats.py +261 -0
- hanzo_mcp/tools/common/tool_disable.py +144 -0
- hanzo_mcp/tools/common/tool_enable.py +182 -0
- hanzo_mcp/tools/common/tool_list.py +263 -0
- hanzo_mcp/tools/database/__init__.py +71 -0
- hanzo_mcp/tools/database/database_manager.py +246 -0
- hanzo_mcp/tools/database/graph_add.py +257 -0
- hanzo_mcp/tools/database/graph_query.py +536 -0
- hanzo_mcp/tools/database/graph_remove.py +267 -0
- hanzo_mcp/tools/database/graph_search.py +348 -0
- hanzo_mcp/tools/database/graph_stats.py +345 -0
- hanzo_mcp/tools/database/sql_query.py +229 -0
- hanzo_mcp/tools/database/sql_search.py +296 -0
- hanzo_mcp/tools/database/sql_stats.py +254 -0
- hanzo_mcp/tools/editor/__init__.py +11 -0
- hanzo_mcp/tools/editor/neovim_command.py +272 -0
- hanzo_mcp/tools/editor/neovim_edit.py +290 -0
- hanzo_mcp/tools/editor/neovim_session.py +356 -0
- hanzo_mcp/tools/filesystem/__init__.py +20 -1
- hanzo_mcp/tools/filesystem/batch_search.py +812 -0
- hanzo_mcp/tools/filesystem/find_files.py +348 -0
- hanzo_mcp/tools/filesystem/git_search.py +505 -0
- hanzo_mcp/tools/llm/__init__.py +27 -0
- hanzo_mcp/tools/llm/consensus_tool.py +351 -0
- hanzo_mcp/tools/llm/llm_manage.py +413 -0
- hanzo_mcp/tools/llm/llm_tool.py +346 -0
- hanzo_mcp/tools/llm/provider_tools.py +412 -0
- hanzo_mcp/tools/mcp/__init__.py +11 -0
- hanzo_mcp/tools/mcp/mcp_add.py +263 -0
- hanzo_mcp/tools/mcp/mcp_remove.py +127 -0
- hanzo_mcp/tools/mcp/mcp_stats.py +165 -0
- hanzo_mcp/tools/shell/__init__.py +27 -7
- hanzo_mcp/tools/shell/logs.py +265 -0
- hanzo_mcp/tools/shell/npx.py +194 -0
- hanzo_mcp/tools/shell/npx_background.py +254 -0
- hanzo_mcp/tools/shell/pkill.py +262 -0
- hanzo_mcp/tools/shell/processes.py +279 -0
- hanzo_mcp/tools/shell/run_background.py +326 -0
- hanzo_mcp/tools/shell/uvx.py +187 -0
- hanzo_mcp/tools/shell/uvx_background.py +249 -0
- hanzo_mcp/tools/vector/__init__.py +21 -12
- hanzo_mcp/tools/vector/ast_analyzer.py +459 -0
- hanzo_mcp/tools/vector/git_ingester.py +485 -0
- hanzo_mcp/tools/vector/index_tool.py +358 -0
- hanzo_mcp/tools/vector/infinity_store.py +465 -1
- hanzo_mcp/tools/vector/mock_infinity.py +162 -0
- hanzo_mcp/tools/vector/vector_index.py +7 -6
- hanzo_mcp/tools/vector/vector_search.py +22 -7
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/METADATA +68 -20
- hanzo_mcp-0.5.2.dist-info/RECORD +106 -0
- hanzo_mcp-0.5.0.dist-info/RECORD +0 -63
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/licenses/LICENSE +0 -0
- {hanzo_mcp-0.5.0.dist-info → hanzo_mcp-0.5.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""Disable tools dynamically."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated, TypedDict, Unpack, final, override
|
|
4
|
+
|
|
5
|
+
from fastmcp import Context as MCPContext
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
|
|
8
|
+
from hanzo_mcp.tools.common.base import BaseTool
|
|
9
|
+
from hanzo_mcp.tools.common.context import create_tool_context
|
|
10
|
+
from hanzo_mcp.tools.common.tool_enable import ToolEnableTool
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
ToolName = Annotated[
|
|
14
|
+
str,
|
|
15
|
+
Field(
|
|
16
|
+
description="Name of the tool to disable (e.g., 'grep', 'vector_search')",
|
|
17
|
+
min_length=1,
|
|
18
|
+
),
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
Persist = Annotated[
|
|
22
|
+
bool,
|
|
23
|
+
Field(
|
|
24
|
+
description="Persist the change to config file",
|
|
25
|
+
default=True,
|
|
26
|
+
),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ToolDisableParams(TypedDict, total=False):
|
|
31
|
+
"""Parameters for tool disable."""
|
|
32
|
+
|
|
33
|
+
tool: str
|
|
34
|
+
persist: bool
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@final
|
|
38
|
+
class ToolDisableTool(BaseTool):
|
|
39
|
+
"""Tool for disabling other tools dynamically."""
|
|
40
|
+
|
|
41
|
+
def __init__(self):
|
|
42
|
+
"""Initialize the tool disable tool."""
|
|
43
|
+
# Ensure states are loaded
|
|
44
|
+
if not ToolEnableTool._initialized:
|
|
45
|
+
ToolEnableTool._load_states()
|
|
46
|
+
ToolEnableTool._initialized = True
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
@override
|
|
50
|
+
def name(self) -> str:
|
|
51
|
+
"""Get the tool name."""
|
|
52
|
+
return "tool_disable"
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
@override
|
|
56
|
+
def description(self) -> str:
|
|
57
|
+
"""Get the tool description."""
|
|
58
|
+
return """Disable tools to prevent their use.
|
|
59
|
+
|
|
60
|
+
This allows you to temporarily or permanently disable tools.
|
|
61
|
+
Useful for testing or when a tool is misbehaving.
|
|
62
|
+
Changes are persisted by default.
|
|
63
|
+
|
|
64
|
+
Critical tools (tool_enable, tool_disable, tool_list) cannot be disabled.
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
- tool_disable --tool vector_search
|
|
68
|
+
- tool_disable --tool uvx_background
|
|
69
|
+
- tool_disable --tool grep --no-persist
|
|
70
|
+
|
|
71
|
+
Use 'tool_list' to see all available tools and their status.
|
|
72
|
+
Use 'tool_enable' to re-enable disabled tools.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
@override
|
|
76
|
+
async def call(
|
|
77
|
+
self,
|
|
78
|
+
ctx: MCPContext,
|
|
79
|
+
**params: Unpack[ToolDisableParams],
|
|
80
|
+
) -> str:
|
|
81
|
+
"""Disable a tool.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
ctx: MCP context
|
|
85
|
+
**params: Tool parameters
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Result of disabling the tool
|
|
89
|
+
"""
|
|
90
|
+
tool_ctx = create_tool_context(ctx)
|
|
91
|
+
await tool_ctx.set_tool_info(self.name)
|
|
92
|
+
|
|
93
|
+
# Extract parameters
|
|
94
|
+
tool_name = params.get("tool")
|
|
95
|
+
if not tool_name:
|
|
96
|
+
return "Error: tool name is required"
|
|
97
|
+
|
|
98
|
+
persist = params.get("persist", True)
|
|
99
|
+
|
|
100
|
+
# Prevent disabling critical tools
|
|
101
|
+
critical_tools = {"tool_enable", "tool_disable", "tool_list", "stats"}
|
|
102
|
+
if tool_name in critical_tools:
|
|
103
|
+
return f"Error: Cannot disable critical tool '{tool_name}'. These tools are required for system management."
|
|
104
|
+
|
|
105
|
+
# Check current state
|
|
106
|
+
was_enabled = ToolEnableTool.is_tool_enabled(tool_name)
|
|
107
|
+
|
|
108
|
+
if not was_enabled:
|
|
109
|
+
return f"Tool '{tool_name}' is already disabled."
|
|
110
|
+
|
|
111
|
+
# Disable the tool
|
|
112
|
+
ToolEnableTool._tool_states[tool_name] = False
|
|
113
|
+
|
|
114
|
+
# Persist if requested
|
|
115
|
+
if persist:
|
|
116
|
+
ToolEnableTool._save_states()
|
|
117
|
+
await tool_ctx.info(f"Disabled tool '{tool_name}' (persisted)")
|
|
118
|
+
else:
|
|
119
|
+
await tool_ctx.info(f"Disabled tool '{tool_name}' (temporary)")
|
|
120
|
+
|
|
121
|
+
output = [
|
|
122
|
+
f"Successfully disabled tool '{tool_name}'",
|
|
123
|
+
"",
|
|
124
|
+
"The tool is now unavailable for use.",
|
|
125
|
+
f"Use 'tool_enable --tool {tool_name}' to re-enable it.",
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
if not persist:
|
|
129
|
+
output.append("\nNote: This change is temporary and will be lost on restart.")
|
|
130
|
+
|
|
131
|
+
# Warn about commonly used tools
|
|
132
|
+
common_tools = {"grep", "read", "write", "bash", "edit"}
|
|
133
|
+
if tool_name in common_tools:
|
|
134
|
+
output.append(f"\n⚠️ Warning: '{tool_name}' is a commonly used tool. Disabling it may affect normal operations.")
|
|
135
|
+
|
|
136
|
+
# Count disabled tools
|
|
137
|
+
disabled_count = sum(1 for enabled in ToolEnableTool._tool_states.values() if not enabled)
|
|
138
|
+
output.append(f"\nTotal disabled tools: {disabled_count}")
|
|
139
|
+
|
|
140
|
+
return "\n".join(output)
|
|
141
|
+
|
|
142
|
+
def register(self, mcp_server) -> None:
|
|
143
|
+
"""Register this tool with the MCP server."""
|
|
144
|
+
pass
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Enable tools dynamically."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Annotated, TypedDict, Unpack, final, override
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from fastmcp import Context as MCPContext
|
|
8
|
+
from pydantic import Field
|
|
9
|
+
|
|
10
|
+
from hanzo_mcp.tools.common.base import BaseTool
|
|
11
|
+
from hanzo_mcp.tools.common.context import create_tool_context
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
ToolName = Annotated[
|
|
15
|
+
str,
|
|
16
|
+
Field(
|
|
17
|
+
description="Name of the tool to enable (e.g., 'grep', 'vector_search')",
|
|
18
|
+
min_length=1,
|
|
19
|
+
),
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
Persist = Annotated[
|
|
23
|
+
bool,
|
|
24
|
+
Field(
|
|
25
|
+
description="Persist the change to config file",
|
|
26
|
+
default=True,
|
|
27
|
+
),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ToolEnableParams(TypedDict, total=False):
|
|
32
|
+
"""Parameters for tool enable."""
|
|
33
|
+
|
|
34
|
+
tool: str
|
|
35
|
+
persist: bool
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@final
|
|
39
|
+
class ToolEnableTool(BaseTool):
|
|
40
|
+
"""Tool for enabling other tools dynamically."""
|
|
41
|
+
|
|
42
|
+
# Class variable to track enabled/disabled tools
|
|
43
|
+
_tool_states = {}
|
|
44
|
+
_config_file = Path.home() / ".hanzo" / "mcp" / "tool_states.json"
|
|
45
|
+
_initialized = False
|
|
46
|
+
|
|
47
|
+
def __init__(self):
|
|
48
|
+
"""Initialize the tool enable tool."""
|
|
49
|
+
if not ToolEnableTool._initialized:
|
|
50
|
+
self._load_states()
|
|
51
|
+
ToolEnableTool._initialized = True
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def _load_states(cls):
|
|
55
|
+
"""Load tool states from config file."""
|
|
56
|
+
if cls._config_file.exists():
|
|
57
|
+
try:
|
|
58
|
+
with open(cls._config_file, 'r') as f:
|
|
59
|
+
cls._tool_states = json.load(f)
|
|
60
|
+
except Exception:
|
|
61
|
+
cls._tool_states = {}
|
|
62
|
+
else:
|
|
63
|
+
# Default all tools to enabled
|
|
64
|
+
cls._tool_states = {}
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def _save_states(cls):
|
|
68
|
+
"""Save tool states to config file."""
|
|
69
|
+
cls._config_file.parent.mkdir(parents=True, exist_ok=True)
|
|
70
|
+
with open(cls._config_file, 'w') as f:
|
|
71
|
+
json.dump(cls._tool_states, f, indent=2)
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def is_tool_enabled(cls, tool_name: str) -> bool:
|
|
75
|
+
"""Check if a tool is enabled.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
tool_name: Name of the tool
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
True if enabled (default), False if explicitly disabled
|
|
82
|
+
"""
|
|
83
|
+
# Load states if not initialized
|
|
84
|
+
if not cls._initialized:
|
|
85
|
+
cls._load_states()
|
|
86
|
+
cls._initialized = True
|
|
87
|
+
|
|
88
|
+
# Default to enabled if not in states
|
|
89
|
+
return cls._tool_states.get(tool_name, True)
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def get_all_states(cls) -> dict:
|
|
93
|
+
"""Get all tool states."""
|
|
94
|
+
if not cls._initialized:
|
|
95
|
+
cls._load_states()
|
|
96
|
+
cls._initialized = True
|
|
97
|
+
return cls._tool_states.copy()
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
@override
|
|
101
|
+
def name(self) -> str:
|
|
102
|
+
"""Get the tool name."""
|
|
103
|
+
return "tool_enable"
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
@override
|
|
107
|
+
def description(self) -> str:
|
|
108
|
+
"""Get the tool description."""
|
|
109
|
+
return """Enable tools that have been disabled.
|
|
110
|
+
|
|
111
|
+
This allows you to re-enable tools that were previously disabled.
|
|
112
|
+
Changes are persisted by default.
|
|
113
|
+
|
|
114
|
+
Examples:
|
|
115
|
+
- tool_enable --tool grep
|
|
116
|
+
- tool_enable --tool vector_search
|
|
117
|
+
- tool_enable --tool uvx_background --no-persist
|
|
118
|
+
|
|
119
|
+
Use 'tool_list' to see all available tools and their status.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
@override
|
|
123
|
+
async def call(
|
|
124
|
+
self,
|
|
125
|
+
ctx: MCPContext,
|
|
126
|
+
**params: Unpack[ToolEnableParams],
|
|
127
|
+
) -> str:
|
|
128
|
+
"""Enable a tool.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
ctx: MCP context
|
|
132
|
+
**params: Tool parameters
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Result of enabling the tool
|
|
136
|
+
"""
|
|
137
|
+
tool_ctx = create_tool_context(ctx)
|
|
138
|
+
await tool_ctx.set_tool_info(self.name)
|
|
139
|
+
|
|
140
|
+
# Extract parameters
|
|
141
|
+
tool_name = params.get("tool")
|
|
142
|
+
if not tool_name:
|
|
143
|
+
return "Error: tool name is required"
|
|
144
|
+
|
|
145
|
+
persist = params.get("persist", True)
|
|
146
|
+
|
|
147
|
+
# Check current state
|
|
148
|
+
was_enabled = self.is_tool_enabled(tool_name)
|
|
149
|
+
|
|
150
|
+
if was_enabled:
|
|
151
|
+
return f"Tool '{tool_name}' is already enabled."
|
|
152
|
+
|
|
153
|
+
# Enable the tool
|
|
154
|
+
self._tool_states[tool_name] = True
|
|
155
|
+
|
|
156
|
+
# Persist if requested
|
|
157
|
+
if persist:
|
|
158
|
+
self._save_states()
|
|
159
|
+
await tool_ctx.info(f"Enabled tool '{tool_name}' (persisted)")
|
|
160
|
+
else:
|
|
161
|
+
await tool_ctx.info(f"Enabled tool '{tool_name}' (temporary)")
|
|
162
|
+
|
|
163
|
+
output = [
|
|
164
|
+
f"Successfully enabled tool '{tool_name}'",
|
|
165
|
+
"",
|
|
166
|
+
"The tool is now available for use.",
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
if not persist:
|
|
170
|
+
output.append("Note: This change is temporary and will be lost on restart.")
|
|
171
|
+
|
|
172
|
+
# Count enabled/disabled tools
|
|
173
|
+
disabled_count = sum(1 for enabled in self._tool_states.values() if not enabled)
|
|
174
|
+
if disabled_count > 0:
|
|
175
|
+
output.append(f"\nCurrently disabled tools: {disabled_count}")
|
|
176
|
+
output.append("Use 'tool_list --disabled' to see them.")
|
|
177
|
+
|
|
178
|
+
return "\n".join(output)
|
|
179
|
+
|
|
180
|
+
def register(self, mcp_server) -> None:
|
|
181
|
+
"""Register this tool with the MCP server."""
|
|
182
|
+
pass
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""List all available tools and their status."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated, TypedDict, Unpack, final, override, Optional
|
|
4
|
+
|
|
5
|
+
from fastmcp import Context as MCPContext
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
|
|
8
|
+
from hanzo_mcp.tools.common.base import BaseTool
|
|
9
|
+
from hanzo_mcp.tools.common.context import create_tool_context
|
|
10
|
+
from hanzo_mcp.tools.common.tool_enable import ToolEnableTool
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
ShowDisabled = Annotated[
|
|
14
|
+
bool,
|
|
15
|
+
Field(
|
|
16
|
+
description="Show only disabled tools",
|
|
17
|
+
default=False,
|
|
18
|
+
),
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
ShowEnabled = Annotated[
|
|
22
|
+
bool,
|
|
23
|
+
Field(
|
|
24
|
+
description="Show only enabled tools",
|
|
25
|
+
default=False,
|
|
26
|
+
),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
Category = Annotated[
|
|
30
|
+
Optional[str],
|
|
31
|
+
Field(
|
|
32
|
+
description="Filter by category (filesystem, shell, database, etc.)",
|
|
33
|
+
default=None,
|
|
34
|
+
),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ToolListParams(TypedDict, total=False):
|
|
39
|
+
"""Parameters for tool list."""
|
|
40
|
+
|
|
41
|
+
show_disabled: bool
|
|
42
|
+
show_enabled: bool
|
|
43
|
+
category: Optional[str]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@final
|
|
47
|
+
class ToolListTool(BaseTool):
|
|
48
|
+
"""Tool for listing all available tools and their status."""
|
|
49
|
+
|
|
50
|
+
# Tool information organized by category
|
|
51
|
+
TOOL_INFO = {
|
|
52
|
+
"filesystem": [
|
|
53
|
+
("read", "Read contents of files"),
|
|
54
|
+
("write", "Write contents to files"),
|
|
55
|
+
("edit", "Edit specific parts of files"),
|
|
56
|
+
("multi_edit", "Make multiple edits to a file"),
|
|
57
|
+
("directory_tree", "Display directory structure"),
|
|
58
|
+
("grep", "Search file contents with patterns"),
|
|
59
|
+
("grep_ast", "Search code with AST patterns"),
|
|
60
|
+
("git_search", "Search git history"),
|
|
61
|
+
("batch_search", "Run multiple searches in parallel"),
|
|
62
|
+
("find_files", "Find files by name pattern"),
|
|
63
|
+
("content_replace", "Replace content across files"),
|
|
64
|
+
],
|
|
65
|
+
"shell": [
|
|
66
|
+
("run_command", "Execute shell commands"),
|
|
67
|
+
("run_background", "Run commands in background"),
|
|
68
|
+
("processes", "List background processes"),
|
|
69
|
+
("pkill", "Kill background processes"),
|
|
70
|
+
("logs", "View process logs"),
|
|
71
|
+
("uvx", "Run Python packages"),
|
|
72
|
+
("uvx_background", "Run Python servers"),
|
|
73
|
+
("npx", "Run Node.js packages"),
|
|
74
|
+
("npx_background", "Run Node.js servers"),
|
|
75
|
+
],
|
|
76
|
+
"database": [
|
|
77
|
+
("sql_query", "Execute SQL queries"),
|
|
78
|
+
("sql_search", "Search in SQLite databases"),
|
|
79
|
+
("sql_stats", "SQLite database statistics"),
|
|
80
|
+
("graph_add", "Add nodes/edges to graph"),
|
|
81
|
+
("graph_remove", "Remove nodes/edges from graph"),
|
|
82
|
+
("graph_query", "Query graph relationships"),
|
|
83
|
+
("graph_search", "Search in graph database"),
|
|
84
|
+
("graph_stats", "Graph database statistics"),
|
|
85
|
+
],
|
|
86
|
+
"vector": [
|
|
87
|
+
("vector_index", "Index files into vector store"),
|
|
88
|
+
("vector_search", "Semantic search in vector store"),
|
|
89
|
+
],
|
|
90
|
+
"mcp": [
|
|
91
|
+
("mcp_add", "Add MCP servers"),
|
|
92
|
+
("mcp_remove", "Remove MCP servers"),
|
|
93
|
+
("mcp_stats", "MCP server statistics"),
|
|
94
|
+
],
|
|
95
|
+
"system": [
|
|
96
|
+
("stats", "System and resource statistics"),
|
|
97
|
+
("tool_enable", "Enable tools"),
|
|
98
|
+
("tool_disable", "Disable tools"),
|
|
99
|
+
("tool_list", "List all tools (this tool)"),
|
|
100
|
+
],
|
|
101
|
+
"editor": [
|
|
102
|
+
("neovim_edit", "Open files in Neovim"),
|
|
103
|
+
("neovim_command", "Execute Neovim commands"),
|
|
104
|
+
("neovim_session", "Manage Neovim sessions"),
|
|
105
|
+
],
|
|
106
|
+
"llm": [
|
|
107
|
+
("llm", "Query any LLM via LiteLLM"),
|
|
108
|
+
("consensus", "Get consensus from multiple LLMs"),
|
|
109
|
+
("llm_manage", "Manage LLM providers"),
|
|
110
|
+
("openai", "Query OpenAI models"),
|
|
111
|
+
("anthropic", "Query Anthropic Claude models"),
|
|
112
|
+
("gemini", "Query Google Gemini models"),
|
|
113
|
+
("groq", "Query Groq fast models"),
|
|
114
|
+
("mistral", "Query Mistral models"),
|
|
115
|
+
("perplexity", "Query Perplexity with search"),
|
|
116
|
+
],
|
|
117
|
+
"other": [
|
|
118
|
+
("think", "Structured thinking space"),
|
|
119
|
+
("dispatch_agent", "Delegate tasks to sub-agents"),
|
|
120
|
+
("todo_read", "Read todo list"),
|
|
121
|
+
("todo_write", "Write todo list"),
|
|
122
|
+
("notebook_read", "Read Jupyter notebooks"),
|
|
123
|
+
("notebook_edit", "Edit Jupyter notebooks"),
|
|
124
|
+
("batch", "Run multiple tools in parallel"),
|
|
125
|
+
],
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
def __init__(self):
|
|
129
|
+
"""Initialize the tool list tool."""
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
@override
|
|
134
|
+
def name(self) -> str:
|
|
135
|
+
"""Get the tool name."""
|
|
136
|
+
return "tool_list"
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
@override
|
|
140
|
+
def description(self) -> str:
|
|
141
|
+
"""Get the tool description."""
|
|
142
|
+
return """List all available tools and their current status.
|
|
143
|
+
|
|
144
|
+
Shows:
|
|
145
|
+
- Tool names and descriptions
|
|
146
|
+
- Whether each tool is enabled or disabled
|
|
147
|
+
- Tools organized by category
|
|
148
|
+
|
|
149
|
+
Examples:
|
|
150
|
+
- tool_list # Show all tools
|
|
151
|
+
- tool_list --show-disabled # Show only disabled tools
|
|
152
|
+
- tool_list --show-enabled # Show only enabled tools
|
|
153
|
+
- tool_list --category shell # Show only shell tools
|
|
154
|
+
|
|
155
|
+
Use 'tool_enable' and 'tool_disable' to change tool status.
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
@override
|
|
159
|
+
async def call(
|
|
160
|
+
self,
|
|
161
|
+
ctx: MCPContext,
|
|
162
|
+
**params: Unpack[ToolListParams],
|
|
163
|
+
) -> str:
|
|
164
|
+
"""List all tools.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
ctx: MCP context
|
|
168
|
+
**params: Tool parameters
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
List of tools and their status
|
|
172
|
+
"""
|
|
173
|
+
tool_ctx = create_tool_context(ctx)
|
|
174
|
+
await tool_ctx.set_tool_info(self.name)
|
|
175
|
+
|
|
176
|
+
# Extract parameters
|
|
177
|
+
show_disabled = params.get("show_disabled", False)
|
|
178
|
+
show_enabled = params.get("show_enabled", False)
|
|
179
|
+
category_filter = params.get("category")
|
|
180
|
+
|
|
181
|
+
# Get all tool states
|
|
182
|
+
all_states = ToolEnableTool.get_all_states()
|
|
183
|
+
|
|
184
|
+
output = []
|
|
185
|
+
|
|
186
|
+
# Header
|
|
187
|
+
if show_disabled:
|
|
188
|
+
output.append("=== Disabled Tools ===")
|
|
189
|
+
elif show_enabled:
|
|
190
|
+
output.append("=== Enabled Tools ===")
|
|
191
|
+
else:
|
|
192
|
+
output.append("=== All Available Tools ===")
|
|
193
|
+
|
|
194
|
+
if category_filter:
|
|
195
|
+
output.append(f"Category: {category_filter}")
|
|
196
|
+
|
|
197
|
+
output.append("")
|
|
198
|
+
|
|
199
|
+
# Count statistics
|
|
200
|
+
total_tools = 0
|
|
201
|
+
disabled_count = 0
|
|
202
|
+
shown_count = 0
|
|
203
|
+
|
|
204
|
+
# Iterate through categories
|
|
205
|
+
categories = [category_filter] if category_filter and category_filter in self.TOOL_INFO else self.TOOL_INFO.keys()
|
|
206
|
+
|
|
207
|
+
for category in categories:
|
|
208
|
+
if category not in self.TOOL_INFO:
|
|
209
|
+
continue
|
|
210
|
+
|
|
211
|
+
category_tools = self.TOOL_INFO[category]
|
|
212
|
+
category_shown = []
|
|
213
|
+
|
|
214
|
+
for tool_name, description in category_tools:
|
|
215
|
+
total_tools += 1
|
|
216
|
+
is_enabled = ToolEnableTool.is_tool_enabled(tool_name)
|
|
217
|
+
|
|
218
|
+
if not is_enabled:
|
|
219
|
+
disabled_count += 1
|
|
220
|
+
|
|
221
|
+
# Apply filters
|
|
222
|
+
if show_disabled and is_enabled:
|
|
223
|
+
continue
|
|
224
|
+
if show_enabled and not is_enabled:
|
|
225
|
+
continue
|
|
226
|
+
|
|
227
|
+
status = "✅" if is_enabled else "❌"
|
|
228
|
+
category_shown.append((tool_name, description, status))
|
|
229
|
+
shown_count += 1
|
|
230
|
+
|
|
231
|
+
# Show category if it has tools
|
|
232
|
+
if category_shown:
|
|
233
|
+
output.append(f"=== {category.title()} Tools ===")
|
|
234
|
+
|
|
235
|
+
# Find max tool name length for alignment
|
|
236
|
+
max_name_len = max(len(name) for name, _, _ in category_shown)
|
|
237
|
+
|
|
238
|
+
for tool_name, description, status in category_shown:
|
|
239
|
+
output.append(f"{status} {tool_name.ljust(max_name_len)} - {description}")
|
|
240
|
+
|
|
241
|
+
output.append("")
|
|
242
|
+
|
|
243
|
+
# Summary
|
|
244
|
+
if not show_disabled and not show_enabled:
|
|
245
|
+
output.append("=== Summary ===")
|
|
246
|
+
output.append(f"Total tools: {total_tools}")
|
|
247
|
+
output.append(f"Enabled: {total_tools - disabled_count}")
|
|
248
|
+
output.append(f"Disabled: {disabled_count}")
|
|
249
|
+
else:
|
|
250
|
+
output.append(f"Showing {shown_count} tool(s)")
|
|
251
|
+
|
|
252
|
+
if disabled_count > 0 and not show_disabled:
|
|
253
|
+
output.append("\nUse 'tool_list --show-disabled' to see disabled tools.")
|
|
254
|
+
output.append("Use 'tool_enable --tool <name>' to enable a tool.")
|
|
255
|
+
|
|
256
|
+
if show_disabled:
|
|
257
|
+
output.append("\nUse 'tool_enable --tool <name>' to enable these tools.")
|
|
258
|
+
|
|
259
|
+
return "\n".join(output)
|
|
260
|
+
|
|
261
|
+
def register(self, mcp_server) -> None:
|
|
262
|
+
"""Register this tool with the MCP server."""
|
|
263
|
+
pass
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Database tools for Hanzo MCP.
|
|
2
|
+
|
|
3
|
+
This package provides tools for working with embedded SQLite databases
|
|
4
|
+
and graph databases in projects.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from hanzo_mcp.tools.common.base import BaseTool
|
|
8
|
+
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
9
|
+
from fastmcp import FastMCP
|
|
10
|
+
|
|
11
|
+
# Import database tools
|
|
12
|
+
from .sql_query import SqlQueryTool
|
|
13
|
+
from .sql_search import SqlSearchTool
|
|
14
|
+
from .sql_stats import SqlStatsTool
|
|
15
|
+
from .graph_add import GraphAddTool
|
|
16
|
+
from .graph_remove import GraphRemoveTool
|
|
17
|
+
from .graph_query import GraphQueryTool
|
|
18
|
+
from .graph_search import GraphSearchTool
|
|
19
|
+
from .graph_stats import GraphStatsTool
|
|
20
|
+
from .database_manager import DatabaseManager
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"register_database_tools",
|
|
24
|
+
"DatabaseManager",
|
|
25
|
+
"SqlQueryTool",
|
|
26
|
+
"SqlSearchTool",
|
|
27
|
+
"SqlStatsTool",
|
|
28
|
+
"GraphAddTool",
|
|
29
|
+
"GraphRemoveTool",
|
|
30
|
+
"GraphQueryTool",
|
|
31
|
+
"GraphSearchTool",
|
|
32
|
+
"GraphStatsTool",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def register_database_tools(
|
|
37
|
+
mcp_server: FastMCP,
|
|
38
|
+
permission_manager: PermissionManager,
|
|
39
|
+
db_manager: DatabaseManager | None = None,
|
|
40
|
+
) -> list[BaseTool]:
|
|
41
|
+
"""Register database tools with the MCP server.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
mcp_server: The FastMCP server instance
|
|
45
|
+
permission_manager: Permission manager for access control
|
|
46
|
+
db_manager: Optional database manager instance
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
List of registered tools
|
|
50
|
+
"""
|
|
51
|
+
# Create database manager if not provided
|
|
52
|
+
if db_manager is None:
|
|
53
|
+
db_manager = DatabaseManager(permission_manager)
|
|
54
|
+
|
|
55
|
+
# Create tool instances
|
|
56
|
+
tools = [
|
|
57
|
+
SqlQueryTool(permission_manager, db_manager),
|
|
58
|
+
SqlSearchTool(permission_manager, db_manager),
|
|
59
|
+
SqlStatsTool(permission_manager, db_manager),
|
|
60
|
+
GraphAddTool(permission_manager, db_manager),
|
|
61
|
+
GraphRemoveTool(permission_manager, db_manager),
|
|
62
|
+
GraphQueryTool(permission_manager, db_manager),
|
|
63
|
+
GraphSearchTool(permission_manager, db_manager),
|
|
64
|
+
GraphStatsTool(permission_manager, db_manager),
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
# Register with MCP server
|
|
68
|
+
from hanzo_mcp.tools.common.base import ToolRegistry
|
|
69
|
+
ToolRegistry.register_tools(mcp_server, tools)
|
|
70
|
+
|
|
71
|
+
return tools
|