hanzo-mcp 0.7.7__py3-none-any.whl → 0.8.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 +6 -0
- hanzo_mcp/__main__.py +1 -1
- hanzo_mcp/analytics/__init__.py +2 -2
- hanzo_mcp/analytics/posthog_analytics.py +76 -82
- hanzo_mcp/cli.py +31 -36
- hanzo_mcp/cli_enhanced.py +94 -72
- hanzo_mcp/cli_plugin.py +27 -17
- hanzo_mcp/config/__init__.py +2 -2
- hanzo_mcp/config/settings.py +112 -88
- hanzo_mcp/config/tool_config.py +32 -34
- hanzo_mcp/dev_server.py +66 -67
- hanzo_mcp/prompts/__init__.py +94 -12
- hanzo_mcp/prompts/enhanced_prompts.py +809 -0
- hanzo_mcp/prompts/example_custom_prompt.py +6 -5
- hanzo_mcp/prompts/project_todo_reminder.py +0 -1
- hanzo_mcp/prompts/tool_explorer.py +10 -7
- hanzo_mcp/server.py +17 -21
- hanzo_mcp/server_enhanced.py +15 -22
- hanzo_mcp/tools/__init__.py +56 -28
- hanzo_mcp/tools/agent/__init__.py +16 -19
- hanzo_mcp/tools/agent/agent.py +82 -65
- hanzo_mcp/tools/agent/agent_tool.py +152 -122
- hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +66 -62
- hanzo_mcp/tools/agent/clarification_protocol.py +55 -50
- hanzo_mcp/tools/agent/clarification_tool.py +11 -10
- hanzo_mcp/tools/agent/claude_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/claude_desktop_auth.py +130 -144
- hanzo_mcp/tools/agent/cli_agent_base.py +59 -53
- hanzo_mcp/tools/agent/code_auth.py +102 -107
- hanzo_mcp/tools/agent/code_auth_tool.py +28 -27
- hanzo_mcp/tools/agent/codex_cli_tool.py +20 -19
- hanzo_mcp/tools/agent/critic_tool.py +86 -73
- hanzo_mcp/tools/agent/gemini_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/grok_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/iching_tool.py +404 -139
- hanzo_mcp/tools/agent/network_tool.py +89 -73
- hanzo_mcp/tools/agent/prompt.py +2 -1
- hanzo_mcp/tools/agent/review_tool.py +101 -98
- hanzo_mcp/tools/agent/swarm_alias.py +87 -0
- hanzo_mcp/tools/agent/swarm_tool.py +246 -161
- hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +134 -92
- hanzo_mcp/tools/agent/tool_adapter.py +21 -11
- hanzo_mcp/tools/common/__init__.py +1 -1
- hanzo_mcp/tools/common/base.py +3 -5
- hanzo_mcp/tools/common/batch_tool.py +46 -39
- hanzo_mcp/tools/common/config_tool.py +120 -84
- hanzo_mcp/tools/common/context.py +1 -5
- hanzo_mcp/tools/common/context_fix.py +5 -3
- hanzo_mcp/tools/common/critic_tool.py +4 -8
- hanzo_mcp/tools/common/decorators.py +58 -56
- hanzo_mcp/tools/common/enhanced_base.py +29 -32
- hanzo_mcp/tools/common/fastmcp_pagination.py +91 -94
- hanzo_mcp/tools/common/forgiving_edit.py +91 -87
- hanzo_mcp/tools/common/mode.py +15 -17
- hanzo_mcp/tools/common/mode_loader.py +27 -24
- hanzo_mcp/tools/common/paginated_base.py +61 -53
- hanzo_mcp/tools/common/paginated_response.py +72 -79
- hanzo_mcp/tools/common/pagination.py +50 -53
- hanzo_mcp/tools/common/permissions.py +4 -4
- hanzo_mcp/tools/common/personality.py +186 -138
- hanzo_mcp/tools/common/plugin_loader.py +54 -54
- hanzo_mcp/tools/common/stats.py +65 -47
- hanzo_mcp/tools/common/test_helpers.py +31 -0
- hanzo_mcp/tools/common/thinking_tool.py +4 -8
- hanzo_mcp/tools/common/tool_disable.py +17 -12
- hanzo_mcp/tools/common/tool_enable.py +13 -14
- hanzo_mcp/tools/common/tool_list.py +36 -28
- hanzo_mcp/tools/common/truncate.py +23 -23
- hanzo_mcp/tools/config/__init__.py +4 -4
- hanzo_mcp/tools/config/config_tool.py +42 -29
- hanzo_mcp/tools/config/index_config.py +37 -34
- hanzo_mcp/tools/config/mode_tool.py +175 -55
- hanzo_mcp/tools/database/__init__.py +15 -12
- hanzo_mcp/tools/database/database_manager.py +77 -75
- hanzo_mcp/tools/database/graph.py +137 -91
- hanzo_mcp/tools/database/graph_add.py +30 -18
- hanzo_mcp/tools/database/graph_query.py +178 -102
- hanzo_mcp/tools/database/graph_remove.py +33 -28
- hanzo_mcp/tools/database/graph_search.py +97 -75
- hanzo_mcp/tools/database/graph_stats.py +91 -59
- hanzo_mcp/tools/database/sql.py +107 -79
- hanzo_mcp/tools/database/sql_query.py +30 -24
- hanzo_mcp/tools/database/sql_search.py +29 -25
- hanzo_mcp/tools/database/sql_stats.py +47 -35
- hanzo_mcp/tools/editor/neovim_command.py +25 -28
- hanzo_mcp/tools/editor/neovim_edit.py +21 -23
- hanzo_mcp/tools/editor/neovim_session.py +60 -54
- hanzo_mcp/tools/filesystem/__init__.py +31 -30
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +329 -249
- hanzo_mcp/tools/filesystem/ast_tool.py +4 -4
- hanzo_mcp/tools/filesystem/base.py +1 -1
- hanzo_mcp/tools/filesystem/batch_search.py +316 -224
- hanzo_mcp/tools/filesystem/content_replace.py +4 -4
- hanzo_mcp/tools/filesystem/diff.py +71 -59
- hanzo_mcp/tools/filesystem/directory_tree.py +7 -7
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +49 -37
- hanzo_mcp/tools/filesystem/edit.py +4 -4
- hanzo_mcp/tools/filesystem/find.py +173 -80
- hanzo_mcp/tools/filesystem/find_files.py +73 -52
- hanzo_mcp/tools/filesystem/git_search.py +157 -104
- hanzo_mcp/tools/filesystem/grep.py +8 -8
- hanzo_mcp/tools/filesystem/multi_edit.py +4 -8
- hanzo_mcp/tools/filesystem/read.py +12 -10
- hanzo_mcp/tools/filesystem/rules_tool.py +59 -43
- hanzo_mcp/tools/filesystem/search_tool.py +263 -207
- hanzo_mcp/tools/filesystem/symbols_tool.py +94 -54
- hanzo_mcp/tools/filesystem/tree.py +35 -33
- hanzo_mcp/tools/filesystem/unix_aliases.py +13 -18
- hanzo_mcp/tools/filesystem/watch.py +37 -36
- hanzo_mcp/tools/filesystem/write.py +4 -8
- hanzo_mcp/tools/jupyter/__init__.py +4 -4
- hanzo_mcp/tools/jupyter/base.py +4 -5
- hanzo_mcp/tools/jupyter/jupyter.py +67 -47
- hanzo_mcp/tools/jupyter/notebook_edit.py +4 -4
- hanzo_mcp/tools/jupyter/notebook_read.py +4 -7
- hanzo_mcp/tools/llm/__init__.py +5 -7
- hanzo_mcp/tools/llm/consensus_tool.py +72 -52
- hanzo_mcp/tools/llm/llm_manage.py +101 -60
- hanzo_mcp/tools/llm/llm_tool.py +226 -166
- hanzo_mcp/tools/llm/provider_tools.py +25 -26
- hanzo_mcp/tools/lsp/__init__.py +1 -1
- hanzo_mcp/tools/lsp/lsp_tool.py +228 -143
- hanzo_mcp/tools/mcp/__init__.py +2 -3
- hanzo_mcp/tools/mcp/mcp_add.py +27 -25
- hanzo_mcp/tools/mcp/mcp_remove.py +7 -8
- hanzo_mcp/tools/mcp/mcp_stats.py +23 -22
- hanzo_mcp/tools/mcp/mcp_tool.py +129 -98
- hanzo_mcp/tools/memory/__init__.py +39 -21
- hanzo_mcp/tools/memory/knowledge_tools.py +124 -99
- hanzo_mcp/tools/memory/memory_tools.py +90 -108
- hanzo_mcp/tools/search/__init__.py +7 -2
- hanzo_mcp/tools/search/find_tool.py +297 -212
- hanzo_mcp/tools/search/unified_search.py +366 -314
- hanzo_mcp/tools/shell/__init__.py +8 -7
- hanzo_mcp/tools/shell/auto_background.py +56 -49
- hanzo_mcp/tools/shell/base.py +1 -1
- hanzo_mcp/tools/shell/base_process.py +75 -75
- hanzo_mcp/tools/shell/bash_session.py +2 -2
- hanzo_mcp/tools/shell/bash_session_executor.py +4 -4
- hanzo_mcp/tools/shell/bash_tool.py +24 -31
- hanzo_mcp/tools/shell/command_executor.py +12 -12
- hanzo_mcp/tools/shell/logs.py +43 -33
- hanzo_mcp/tools/shell/npx.py +13 -13
- hanzo_mcp/tools/shell/npx_background.py +24 -21
- hanzo_mcp/tools/shell/npx_tool.py +18 -22
- hanzo_mcp/tools/shell/open.py +19 -21
- hanzo_mcp/tools/shell/pkill.py +31 -26
- hanzo_mcp/tools/shell/process_tool.py +32 -32
- hanzo_mcp/tools/shell/processes.py +57 -58
- hanzo_mcp/tools/shell/run_background.py +24 -25
- hanzo_mcp/tools/shell/run_command.py +5 -5
- hanzo_mcp/tools/shell/run_command_windows.py +5 -5
- hanzo_mcp/tools/shell/session_storage.py +3 -3
- hanzo_mcp/tools/shell/streaming_command.py +141 -126
- hanzo_mcp/tools/shell/uvx.py +24 -25
- hanzo_mcp/tools/shell/uvx_background.py +35 -33
- hanzo_mcp/tools/shell/uvx_tool.py +18 -22
- hanzo_mcp/tools/todo/__init__.py +6 -2
- hanzo_mcp/tools/todo/todo.py +50 -37
- hanzo_mcp/tools/todo/todo_read.py +5 -8
- hanzo_mcp/tools/todo/todo_write.py +5 -7
- hanzo_mcp/tools/vector/__init__.py +40 -28
- hanzo_mcp/tools/vector/ast_analyzer.py +176 -143
- hanzo_mcp/tools/vector/git_ingester.py +170 -179
- hanzo_mcp/tools/vector/index_tool.py +96 -44
- hanzo_mcp/tools/vector/infinity_store.py +283 -228
- hanzo_mcp/tools/vector/mock_infinity.py +39 -40
- hanzo_mcp/tools/vector/project_manager.py +88 -78
- hanzo_mcp/tools/vector/vector.py +59 -42
- hanzo_mcp/tools/vector/vector_index.py +30 -27
- hanzo_mcp/tools/vector/vector_search.py +64 -45
- hanzo_mcp/types.py +6 -4
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.1.dist-info}/METADATA +1 -1
- hanzo_mcp-0.8.1.dist-info/RECORD +185 -0
- hanzo_mcp-0.7.7.dist-info/RECORD +0 -182
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.1.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.1.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.1.dist-info}/top_level.txt +0 -0
|
@@ -4,36 +4,37 @@ This module manages indexing configuration for different scopes.
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import json
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Dict, Any, Optional
|
|
9
7
|
from enum import Enum
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
from pathlib import Path
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class IndexScope(Enum):
|
|
13
13
|
"""Indexing scope options."""
|
|
14
|
+
|
|
14
15
|
PROJECT = "project" # Per-project indexing
|
|
15
|
-
GLOBAL = "global"
|
|
16
|
-
AUTO = "auto"
|
|
16
|
+
GLOBAL = "global" # Global indexing
|
|
17
|
+
AUTO = "auto" # Auto-detect based on git root
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class IndexConfig:
|
|
20
21
|
"""Manages indexing configuration."""
|
|
21
|
-
|
|
22
|
+
|
|
22
23
|
def __init__(self, config_dir: Optional[Path] = None):
|
|
23
24
|
"""Initialize index configuration."""
|
|
24
25
|
self.config_dir = config_dir or Path.home() / ".hanzo" / "mcp"
|
|
25
26
|
self.config_file = self.config_dir / "index_config.json"
|
|
26
27
|
self._config = self._load_config()
|
|
27
|
-
|
|
28
|
+
|
|
28
29
|
def _load_config(self) -> Dict[str, Any]:
|
|
29
30
|
"""Load configuration from disk."""
|
|
30
31
|
if self.config_file.exists():
|
|
31
32
|
try:
|
|
32
33
|
with open(self.config_file, "r") as f:
|
|
33
34
|
return json.load(f)
|
|
34
|
-
except:
|
|
35
|
+
except Exception:
|
|
35
36
|
pass
|
|
36
|
-
|
|
37
|
+
|
|
37
38
|
# Default configuration
|
|
38
39
|
return {
|
|
39
40
|
"default_scope": IndexScope.AUTO.value,
|
|
@@ -56,40 +57,40 @@ class IndexConfig:
|
|
|
56
57
|
"graph": {
|
|
57
58
|
"enabled": True,
|
|
58
59
|
"per_project": True,
|
|
59
|
-
}
|
|
60
|
-
}
|
|
60
|
+
},
|
|
61
|
+
},
|
|
61
62
|
}
|
|
62
|
-
|
|
63
|
+
|
|
63
64
|
def save_config(self) -> None:
|
|
64
65
|
"""Save configuration to disk."""
|
|
65
66
|
self.config_dir.mkdir(parents=True, exist_ok=True)
|
|
66
67
|
with open(self.config_file, "w") as f:
|
|
67
68
|
json.dump(self._config, f, indent=2)
|
|
68
|
-
|
|
69
|
+
|
|
69
70
|
def get_scope(self, path: Optional[str] = None) -> IndexScope:
|
|
70
71
|
"""Get indexing scope for a path."""
|
|
71
72
|
if not path:
|
|
72
73
|
return IndexScope(self._config["default_scope"])
|
|
73
|
-
|
|
74
|
+
|
|
74
75
|
# Check project-specific config
|
|
75
76
|
project_root = self._find_project_root(path)
|
|
76
77
|
if project_root:
|
|
77
78
|
project_config = self._config["project_configs"].get(str(project_root))
|
|
78
79
|
if project_config and "scope" in project_config:
|
|
79
80
|
return IndexScope(project_config["scope"])
|
|
80
|
-
|
|
81
|
+
|
|
81
82
|
# Use default
|
|
82
83
|
scope = IndexScope(self._config["default_scope"])
|
|
83
|
-
|
|
84
|
+
|
|
84
85
|
# Handle auto mode
|
|
85
86
|
if scope == IndexScope.AUTO:
|
|
86
87
|
if project_root:
|
|
87
88
|
return IndexScope.PROJECT
|
|
88
89
|
else:
|
|
89
90
|
return IndexScope.GLOBAL
|
|
90
|
-
|
|
91
|
+
|
|
91
92
|
return scope
|
|
92
|
-
|
|
93
|
+
|
|
93
94
|
def set_scope(self, scope: IndexScope, path: Optional[str] = None) -> None:
|
|
94
95
|
"""Set indexing scope."""
|
|
95
96
|
if path:
|
|
@@ -98,40 +99,42 @@ class IndexConfig:
|
|
|
98
99
|
if project_root:
|
|
99
100
|
if str(project_root) not in self._config["project_configs"]:
|
|
100
101
|
self._config["project_configs"][str(project_root)] = {}
|
|
101
|
-
self._config["project_configs"][str(project_root)][
|
|
102
|
+
self._config["project_configs"][str(project_root)][
|
|
103
|
+
"scope"
|
|
104
|
+
] = scope.value
|
|
102
105
|
else:
|
|
103
106
|
# Set global default
|
|
104
107
|
self._config["default_scope"] = scope.value
|
|
105
|
-
|
|
108
|
+
|
|
106
109
|
self.save_config()
|
|
107
|
-
|
|
110
|
+
|
|
108
111
|
def get_index_path(self, tool: str, path: Optional[str] = None) -> Path:
|
|
109
112
|
"""Get index path for a tool and location."""
|
|
110
113
|
scope = self.get_scope(path)
|
|
111
|
-
|
|
114
|
+
|
|
112
115
|
if scope == IndexScope.PROJECT and path:
|
|
113
116
|
project_root = self._find_project_root(path)
|
|
114
117
|
if project_root:
|
|
115
118
|
return Path(project_root) / ".hanzo" / "index" / tool
|
|
116
|
-
|
|
119
|
+
|
|
117
120
|
# Global index
|
|
118
121
|
return self.config_dir / "index" / tool
|
|
119
|
-
|
|
122
|
+
|
|
120
123
|
def is_indexing_enabled(self, tool: str) -> bool:
|
|
121
124
|
"""Check if indexing is enabled for a tool."""
|
|
122
125
|
return self._config["index_settings"].get(tool, {}).get("enabled", True)
|
|
123
|
-
|
|
126
|
+
|
|
124
127
|
def set_indexing_enabled(self, tool: str, enabled: bool) -> None:
|
|
125
128
|
"""Enable/disable indexing for a tool."""
|
|
126
129
|
if tool not in self._config["index_settings"]:
|
|
127
130
|
self._config["index_settings"][tool] = {}
|
|
128
131
|
self._config["index_settings"][tool]["enabled"] = enabled
|
|
129
132
|
self.save_config()
|
|
130
|
-
|
|
133
|
+
|
|
131
134
|
def toggle_scope(self, path: Optional[str] = None) -> IndexScope:
|
|
132
135
|
"""Toggle between project and global scope."""
|
|
133
136
|
current = self.get_scope(path)
|
|
134
|
-
|
|
137
|
+
|
|
135
138
|
if current == IndexScope.PROJECT:
|
|
136
139
|
new_scope = IndexScope.GLOBAL
|
|
137
140
|
elif current == IndexScope.GLOBAL:
|
|
@@ -142,25 +145,25 @@ class IndexConfig:
|
|
|
142
145
|
new_scope = IndexScope.GLOBAL
|
|
143
146
|
else:
|
|
144
147
|
new_scope = IndexScope.PROJECT
|
|
145
|
-
|
|
148
|
+
|
|
146
149
|
self.set_scope(new_scope, path)
|
|
147
150
|
return new_scope
|
|
148
|
-
|
|
151
|
+
|
|
149
152
|
def _find_project_root(self, path: str) -> Optional[Path]:
|
|
150
153
|
"""Find project root (git root or similar)."""
|
|
151
154
|
current = Path(path).resolve()
|
|
152
|
-
|
|
155
|
+
|
|
153
156
|
# Walk up looking for markers
|
|
154
157
|
markers = [".git", ".hg", "pyproject.toml", "package.json", "Cargo.toml"]
|
|
155
|
-
|
|
158
|
+
|
|
156
159
|
while current != current.parent:
|
|
157
160
|
for marker in markers:
|
|
158
161
|
if (current / marker).exists():
|
|
159
162
|
return current
|
|
160
163
|
current = current.parent
|
|
161
|
-
|
|
164
|
+
|
|
162
165
|
return None
|
|
163
|
-
|
|
166
|
+
|
|
164
167
|
def get_status(self) -> Dict[str, Any]:
|
|
165
168
|
"""Get current configuration status."""
|
|
166
169
|
return {
|
|
@@ -172,5 +175,5 @@ class IndexConfig:
|
|
|
172
175
|
"per_project": settings.get("per_project", True),
|
|
173
176
|
}
|
|
174
177
|
for tool, settings in self._config["index_settings"].items()
|
|
175
|
-
}
|
|
176
|
-
}
|
|
178
|
+
},
|
|
179
|
+
}
|
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Optional, override
|
|
4
4
|
|
|
5
|
+
from mcp.server import FastMCP
|
|
5
6
|
from mcp.server.fastmcp import Context as MCPContext
|
|
6
7
|
|
|
7
8
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
8
9
|
from hanzo_mcp.tools.common.mode import ModeRegistry, register_default_modes
|
|
9
|
-
from mcp.server import FastMCP
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class ModeTool(BaseTool):
|
|
13
13
|
"""Tool for managing development modes."""
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
name = "mode"
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
def __init__(self):
|
|
18
18
|
"""Initialize the mode tool."""
|
|
19
19
|
super().__init__()
|
|
20
20
|
# Register default modes on initialization
|
|
21
21
|
register_default_modes()
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
@property
|
|
24
24
|
@override
|
|
25
25
|
def description(self) -> str:
|
|
@@ -32,7 +32,7 @@ mode --action list
|
|
|
32
32
|
mode --action activate guido
|
|
33
33
|
mode --action show linus
|
|
34
34
|
mode --action current"""
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
@override
|
|
37
37
|
async def run(
|
|
38
38
|
self,
|
|
@@ -41,12 +41,12 @@ mode --action current"""
|
|
|
41
41
|
name: Optional[str] = None,
|
|
42
42
|
) -> str:
|
|
43
43
|
"""Manage development modes.
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
Args:
|
|
46
46
|
ctx: MCP context
|
|
47
47
|
action: Action to perform (list, activate, show, current)
|
|
48
48
|
name: Mode name (for activate/show actions)
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
Returns:
|
|
51
51
|
Action result
|
|
52
52
|
"""
|
|
@@ -54,60 +54,182 @@ mode --action current"""
|
|
|
54
54
|
modes = ModeRegistry.list()
|
|
55
55
|
if not modes:
|
|
56
56
|
return "No modes registered"
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
output = ["Available development modes (100 programmer personalities):"]
|
|
59
59
|
active = ModeRegistry.get_active()
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
# Group modes by category
|
|
62
62
|
categories = {
|
|
63
|
-
"Language Creators": [
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
"Language Creators": [
|
|
64
|
+
"guido",
|
|
65
|
+
"matz",
|
|
66
|
+
"brendan",
|
|
67
|
+
"dennis",
|
|
68
|
+
"bjarne",
|
|
69
|
+
"james",
|
|
70
|
+
"anders",
|
|
71
|
+
"larry",
|
|
72
|
+
"rasmus",
|
|
73
|
+
"rich",
|
|
74
|
+
],
|
|
75
|
+
"Systems & Infrastructure": [
|
|
76
|
+
"linus",
|
|
77
|
+
"rob",
|
|
78
|
+
"ken",
|
|
79
|
+
"bill",
|
|
80
|
+
"richard",
|
|
81
|
+
"brian",
|
|
82
|
+
"donald",
|
|
83
|
+
"graydon",
|
|
84
|
+
"ryan",
|
|
85
|
+
"mitchell",
|
|
86
|
+
],
|
|
87
|
+
"Web & Frontend": [
|
|
88
|
+
"tim",
|
|
89
|
+
"douglas",
|
|
90
|
+
"john",
|
|
91
|
+
"evan",
|
|
92
|
+
"jordan",
|
|
93
|
+
"jeremy",
|
|
94
|
+
"david",
|
|
95
|
+
"taylor",
|
|
96
|
+
"adrian",
|
|
97
|
+
"matt",
|
|
98
|
+
],
|
|
99
|
+
"Database & Data": [
|
|
100
|
+
"michael_s",
|
|
101
|
+
"michael_w",
|
|
102
|
+
"salvatore",
|
|
103
|
+
"dwight",
|
|
104
|
+
"edgar",
|
|
105
|
+
"jim_gray",
|
|
106
|
+
"jeff_dean",
|
|
107
|
+
"sanjay",
|
|
108
|
+
"mike",
|
|
109
|
+
"matei",
|
|
110
|
+
],
|
|
111
|
+
"AI & Machine Learning": [
|
|
112
|
+
"yann",
|
|
113
|
+
"geoffrey",
|
|
114
|
+
"yoshua",
|
|
115
|
+
"andrew",
|
|
116
|
+
"demis",
|
|
117
|
+
"ilya",
|
|
118
|
+
"andrej",
|
|
119
|
+
"chris",
|
|
120
|
+
"francois",
|
|
121
|
+
"jeremy_howard",
|
|
122
|
+
],
|
|
123
|
+
"Security & Cryptography": [
|
|
124
|
+
"bruce",
|
|
125
|
+
"phil",
|
|
126
|
+
"whitfield",
|
|
127
|
+
"ralph",
|
|
128
|
+
"daniel_b",
|
|
129
|
+
"moxie",
|
|
130
|
+
"theo",
|
|
131
|
+
"dan_kaminsky",
|
|
132
|
+
"katie",
|
|
133
|
+
"matt_blaze",
|
|
134
|
+
],
|
|
135
|
+
"Gaming & Graphics": [
|
|
136
|
+
"john_carmack",
|
|
137
|
+
"sid",
|
|
138
|
+
"shigeru",
|
|
139
|
+
"gabe",
|
|
140
|
+
"markus",
|
|
141
|
+
"jonathan",
|
|
142
|
+
"casey",
|
|
143
|
+
"tim_sweeney",
|
|
144
|
+
"hideo",
|
|
145
|
+
"will",
|
|
146
|
+
],
|
|
147
|
+
"Open Source Leaders": [
|
|
148
|
+
"miguel",
|
|
149
|
+
"nat",
|
|
150
|
+
"patrick",
|
|
151
|
+
"ian",
|
|
152
|
+
"mark_shuttleworth",
|
|
153
|
+
"lennart",
|
|
154
|
+
"bram",
|
|
155
|
+
"daniel_r",
|
|
156
|
+
"judd",
|
|
157
|
+
"fabrice",
|
|
158
|
+
],
|
|
159
|
+
"Modern Innovators": [
|
|
160
|
+
"vitalik",
|
|
161
|
+
"satoshi",
|
|
162
|
+
"chris_lattner",
|
|
163
|
+
"joe",
|
|
164
|
+
"jose",
|
|
165
|
+
"sebastian",
|
|
166
|
+
"palmer",
|
|
167
|
+
"dylan",
|
|
168
|
+
"guillermo",
|
|
169
|
+
"tom",
|
|
170
|
+
],
|
|
171
|
+
"Special Configurations": [
|
|
172
|
+
"fullstack",
|
|
173
|
+
"minimal",
|
|
174
|
+
"data_scientist",
|
|
175
|
+
"devops",
|
|
176
|
+
"security",
|
|
177
|
+
"academic",
|
|
178
|
+
"startup",
|
|
179
|
+
"enterprise",
|
|
180
|
+
"creative",
|
|
181
|
+
"hanzo",
|
|
182
|
+
],
|
|
73
183
|
}
|
|
74
|
-
|
|
184
|
+
|
|
75
185
|
for category, mode_names in categories.items():
|
|
76
186
|
output.append(f"\n{category}:")
|
|
77
187
|
for mode_name in mode_names:
|
|
78
188
|
mode = next((m for m in modes if m.name == mode_name), None)
|
|
79
189
|
if mode:
|
|
80
|
-
marker =
|
|
81
|
-
|
|
82
|
-
|
|
190
|
+
marker = (
|
|
191
|
+
" (active)" if active and active.name == mode.name else ""
|
|
192
|
+
)
|
|
193
|
+
output.append(
|
|
194
|
+
f" {mode.name}{marker}: {mode.programmer} - {mode.description}"
|
|
195
|
+
)
|
|
196
|
+
|
|
83
197
|
output.append("\nUse 'mode --action activate <name>' to activate a mode")
|
|
84
|
-
|
|
198
|
+
|
|
85
199
|
return "\n".join(output)
|
|
86
|
-
|
|
200
|
+
|
|
87
201
|
elif action == "activate":
|
|
88
202
|
if not name:
|
|
89
203
|
return "Error: Mode name required for activate action"
|
|
90
|
-
|
|
204
|
+
|
|
91
205
|
try:
|
|
92
206
|
ModeRegistry.set_active(name)
|
|
93
207
|
mode = ModeRegistry.get(name)
|
|
94
|
-
|
|
208
|
+
|
|
95
209
|
output = [f"Activated mode: {mode.name}"]
|
|
96
210
|
output.append(f"Programmer: {mode.programmer}")
|
|
97
211
|
output.append(f"Description: {mode.description}")
|
|
98
212
|
if mode.philosophy:
|
|
99
213
|
output.append(f"Philosophy: {mode.philosophy}")
|
|
100
214
|
output.append(f"\nEnabled tools ({len(mode.tools)}):")
|
|
101
|
-
|
|
215
|
+
|
|
102
216
|
# Group tools by category
|
|
103
217
|
core_tools = []
|
|
104
218
|
package_tools = []
|
|
105
219
|
ai_tools = []
|
|
106
220
|
search_tools = []
|
|
107
221
|
other_tools = []
|
|
108
|
-
|
|
222
|
+
|
|
109
223
|
for tool in sorted(mode.tools):
|
|
110
|
-
if tool in [
|
|
224
|
+
if tool in [
|
|
225
|
+
"read",
|
|
226
|
+
"write",
|
|
227
|
+
"edit",
|
|
228
|
+
"multi_edit",
|
|
229
|
+
"bash",
|
|
230
|
+
"tree",
|
|
231
|
+
"grep",
|
|
232
|
+
]:
|
|
111
233
|
core_tools.append(tool)
|
|
112
234
|
elif tool in ["npx", "uvx", "pip", "cargo", "gem"]:
|
|
113
235
|
package_tools.append(tool)
|
|
@@ -117,7 +239,7 @@ mode --action current"""
|
|
|
117
239
|
search_tools.append(tool)
|
|
118
240
|
else:
|
|
119
241
|
other_tools.append(tool)
|
|
120
|
-
|
|
242
|
+
|
|
121
243
|
if core_tools:
|
|
122
244
|
output.append(f" Core: {', '.join(core_tools)}")
|
|
123
245
|
if package_tools:
|
|
@@ -128,82 +250,80 @@ mode --action current"""
|
|
|
128
250
|
output.append(f" Search: {', '.join(search_tools)}")
|
|
129
251
|
if other_tools:
|
|
130
252
|
output.append(f" Specialized: {', '.join(other_tools)}")
|
|
131
|
-
|
|
253
|
+
|
|
132
254
|
if mode.environment:
|
|
133
255
|
output.append("\nEnvironment variables:")
|
|
134
256
|
for key, value in mode.environment.items():
|
|
135
257
|
output.append(f" {key}={value}")
|
|
136
|
-
|
|
137
|
-
output.append(
|
|
138
|
-
|
|
258
|
+
|
|
259
|
+
output.append(
|
|
260
|
+
"\nNote: Restart MCP session for changes to take full effect"
|
|
261
|
+
)
|
|
262
|
+
|
|
139
263
|
return "\n".join(output)
|
|
140
|
-
|
|
264
|
+
|
|
141
265
|
except ValueError as e:
|
|
142
266
|
return str(e)
|
|
143
|
-
|
|
267
|
+
|
|
144
268
|
elif action == "show":
|
|
145
269
|
if not name:
|
|
146
270
|
return "Error: Mode name required for show action"
|
|
147
|
-
|
|
271
|
+
|
|
148
272
|
mode = ModeRegistry.get(name)
|
|
149
273
|
if not mode:
|
|
150
274
|
return f"Mode '{name}' not found"
|
|
151
|
-
|
|
275
|
+
|
|
152
276
|
output = [f"Mode: {mode.name}"]
|
|
153
277
|
output.append(f"Programmer: {mode.programmer}")
|
|
154
278
|
output.append(f"Description: {mode.description}")
|
|
155
279
|
if mode.philosophy:
|
|
156
280
|
output.append(f"Philosophy: {mode.philosophy}")
|
|
157
281
|
output.append(f"\nTools ({len(mode.tools)}):")
|
|
158
|
-
|
|
282
|
+
|
|
159
283
|
for tool in sorted(mode.tools):
|
|
160
284
|
output.append(f" - {tool}")
|
|
161
|
-
|
|
285
|
+
|
|
162
286
|
if mode.environment:
|
|
163
287
|
output.append("\nEnvironment:")
|
|
164
288
|
for key, value in mode.environment.items():
|
|
165
289
|
output.append(f" {key}={value}")
|
|
166
|
-
|
|
290
|
+
|
|
167
291
|
return "\n".join(output)
|
|
168
|
-
|
|
292
|
+
|
|
169
293
|
elif action == "current":
|
|
170
294
|
active = ModeRegistry.get_active()
|
|
171
295
|
if not active:
|
|
172
296
|
return "No mode currently active\nUse 'mode --action activate <name>' to activate one"
|
|
173
|
-
|
|
297
|
+
|
|
174
298
|
output = [f"Current mode: {active.name}"]
|
|
175
299
|
output.append(f"Programmer: {active.programmer}")
|
|
176
300
|
output.append(f"Description: {active.description}")
|
|
177
301
|
if active.philosophy:
|
|
178
302
|
output.append(f"Philosophy: {active.philosophy}")
|
|
179
303
|
output.append(f"Enabled tools: {len(active.tools)}")
|
|
180
|
-
|
|
304
|
+
|
|
181
305
|
return "\n".join(output)
|
|
182
|
-
|
|
306
|
+
|
|
183
307
|
else:
|
|
184
308
|
return f"Unknown action: {action}. Use 'list', 'activate', 'show', or 'current'"
|
|
185
309
|
|
|
186
310
|
def register(self, server: FastMCP) -> None:
|
|
187
311
|
"""Register the tool with the MCP server."""
|
|
188
312
|
tool_self = self
|
|
189
|
-
|
|
313
|
+
|
|
190
314
|
@server.tool(name=self.name, description=self.description)
|
|
191
315
|
async def mode_handler(
|
|
192
|
-
ctx: MCPContext,
|
|
193
|
-
action: str = "list",
|
|
194
|
-
name: Optional[str] = None
|
|
316
|
+
ctx: MCPContext, action: str = "list", name: Optional[str] = None
|
|
195
317
|
) -> str:
|
|
196
318
|
"""Handle mode tool calls."""
|
|
197
319
|
return await tool_self.run(ctx, action=action, name=name)
|
|
198
|
-
|
|
320
|
+
|
|
199
321
|
async def call(self, ctx: MCPContext, **params) -> str:
|
|
200
322
|
"""Call the tool with arguments."""
|
|
201
323
|
return await self.run(
|
|
202
|
-
ctx,
|
|
203
|
-
action=params.get("action", "list"),
|
|
204
|
-
name=params.get("name")
|
|
324
|
+
ctx, action=params.get("action", "list"), name=params.get("name")
|
|
205
325
|
)
|
|
206
326
|
|
|
207
327
|
|
|
208
328
|
# Create tool instance
|
|
209
|
-
mode_tool = ModeTool()
|
|
329
|
+
mode_tool = ModeTool()
|
|
@@ -4,26 +4,28 @@ This package provides tools for working with embedded SQLite databases
|
|
|
4
4
|
and graph databases in projects.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from mcp.server import FastMCP
|
|
8
|
+
|
|
7
9
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
8
10
|
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
9
|
-
|
|
11
|
+
|
|
12
|
+
from .graph_add import GraphAddTool
|
|
10
13
|
|
|
11
14
|
# Import database tools
|
|
12
15
|
from .sql_query import SqlQueryTool
|
|
13
|
-
from .sql_search import SqlSearchTool
|
|
14
16
|
from .sql_stats import SqlStatsTool
|
|
15
|
-
from .
|
|
16
|
-
from .graph_remove import GraphRemoveTool
|
|
17
|
+
from .sql_search import SqlSearchTool
|
|
17
18
|
from .graph_query import GraphQueryTool
|
|
18
|
-
from .graph_search import GraphSearchTool
|
|
19
19
|
from .graph_stats import GraphStatsTool
|
|
20
|
+
from .graph_remove import GraphRemoveTool
|
|
21
|
+
from .graph_search import GraphSearchTool
|
|
20
22
|
from .database_manager import DatabaseManager
|
|
21
23
|
|
|
22
24
|
__all__ = [
|
|
23
25
|
"register_database_tools",
|
|
24
26
|
"DatabaseManager",
|
|
25
27
|
"SqlQueryTool",
|
|
26
|
-
"SqlSearchTool",
|
|
28
|
+
"SqlSearchTool",
|
|
27
29
|
"SqlStatsTool",
|
|
28
30
|
"GraphAddTool",
|
|
29
31
|
"GraphRemoveTool",
|
|
@@ -39,19 +41,19 @@ def register_database_tools(
|
|
|
39
41
|
db_manager: DatabaseManager | None = None,
|
|
40
42
|
) -> list[BaseTool]:
|
|
41
43
|
"""Register database tools with the MCP server.
|
|
42
|
-
|
|
44
|
+
|
|
43
45
|
Args:
|
|
44
46
|
mcp_server: The FastMCP server instance
|
|
45
47
|
permission_manager: Permission manager for access control
|
|
46
48
|
db_manager: Optional database manager instance
|
|
47
|
-
|
|
49
|
+
|
|
48
50
|
Returns:
|
|
49
51
|
List of registered tools
|
|
50
52
|
"""
|
|
51
53
|
# Create database manager if not provided
|
|
52
54
|
if db_manager is None:
|
|
53
55
|
db_manager = DatabaseManager(permission_manager)
|
|
54
|
-
|
|
56
|
+
|
|
55
57
|
# Create tool instances
|
|
56
58
|
tools = [
|
|
57
59
|
SqlQueryTool(permission_manager, db_manager),
|
|
@@ -63,9 +65,10 @@ def register_database_tools(
|
|
|
63
65
|
GraphSearchTool(permission_manager, db_manager),
|
|
64
66
|
GraphStatsTool(permission_manager, db_manager),
|
|
65
67
|
]
|
|
66
|
-
|
|
68
|
+
|
|
67
69
|
# Register with MCP server
|
|
68
70
|
from hanzo_mcp.tools.common.base import ToolRegistry
|
|
71
|
+
|
|
69
72
|
ToolRegistry.register_tools(mcp_server, tools)
|
|
70
|
-
|
|
71
|
-
return tools
|
|
73
|
+
|
|
74
|
+
return tools
|