hanzo-mcp 0.7.7__py3-none-any.whl → 0.8.0__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.0.dist-info}/METADATA +1 -1
- hanzo_mcp-0.8.0.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.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/top_level.txt +0 -0
hanzo_mcp/config/tool_config.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"""Tool configuration definitions for Hanzo AI."""
|
|
2
2
|
|
|
3
3
|
from enum import Enum
|
|
4
|
-
from typing import Dict, List
|
|
4
|
+
from typing import Dict, List
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class ToolCategory(str, Enum):
|
|
9
9
|
"""Categories of tools available in Hanzo AI."""
|
|
10
|
+
|
|
10
11
|
FILESYSTEM = "filesystem"
|
|
11
12
|
SHELL = "shell"
|
|
12
13
|
JUPYTER = "jupyter"
|
|
@@ -19,13 +20,14 @@ class ToolCategory(str, Enum):
|
|
|
19
20
|
@dataclass
|
|
20
21
|
class ToolConfig:
|
|
21
22
|
"""Configuration for an individual tool."""
|
|
23
|
+
|
|
22
24
|
name: str
|
|
23
25
|
category: ToolCategory
|
|
24
26
|
enabled: bool = True
|
|
25
27
|
description: str = ""
|
|
26
28
|
requires_permissions: bool = True
|
|
27
29
|
cli_flag: str = ""
|
|
28
|
-
|
|
30
|
+
|
|
29
31
|
def __post_init__(self):
|
|
30
32
|
"""Generate CLI flag if not provided."""
|
|
31
33
|
if not self.cli_flag:
|
|
@@ -39,138 +41,132 @@ TOOL_REGISTRY: Dict[str, ToolConfig] = {
|
|
|
39
41
|
name="read",
|
|
40
42
|
category=ToolCategory.FILESYSTEM,
|
|
41
43
|
description="Read file contents with line numbers and truncation support",
|
|
42
|
-
cli_flag="--disable-read"
|
|
44
|
+
cli_flag="--disable-read",
|
|
43
45
|
),
|
|
44
46
|
"write": ToolConfig(
|
|
45
|
-
name="write",
|
|
47
|
+
name="write",
|
|
46
48
|
category=ToolCategory.FILESYSTEM,
|
|
47
49
|
description="Write content to files, create new files or overwrite existing ones",
|
|
48
|
-
cli_flag="--disable-write"
|
|
50
|
+
cli_flag="--disable-write",
|
|
49
51
|
),
|
|
50
52
|
"edit": ToolConfig(
|
|
51
53
|
name="edit",
|
|
52
|
-
category=ToolCategory.FILESYSTEM,
|
|
54
|
+
category=ToolCategory.FILESYSTEM,
|
|
53
55
|
description="Make precise string replacements in files with validation",
|
|
54
|
-
cli_flag="--disable-edit"
|
|
56
|
+
cli_flag="--disable-edit",
|
|
55
57
|
),
|
|
56
58
|
"multi_edit": ToolConfig(
|
|
57
59
|
name="multi_edit",
|
|
58
60
|
category=ToolCategory.FILESYSTEM,
|
|
59
|
-
description="Perform multiple edits to a single file in one operation",
|
|
60
|
-
cli_flag="--disable-multi-edit"
|
|
61
|
+
description="Perform multiple edits to a single file in one operation",
|
|
62
|
+
cli_flag="--disable-multi-edit",
|
|
61
63
|
),
|
|
62
64
|
"directory_tree": ToolConfig(
|
|
63
65
|
name="directory_tree",
|
|
64
66
|
category=ToolCategory.FILESYSTEM,
|
|
65
67
|
description="Display directory structure as a tree",
|
|
66
|
-
cli_flag="--disable-directory-tree"
|
|
68
|
+
cli_flag="--disable-directory-tree",
|
|
67
69
|
),
|
|
68
70
|
"grep": ToolConfig(
|
|
69
71
|
name="grep",
|
|
70
72
|
category=ToolCategory.FILESYSTEM,
|
|
71
73
|
description="Fast content search using ripgrep or fallback Python implementation",
|
|
72
|
-
cli_flag="--disable-grep"
|
|
74
|
+
cli_flag="--disable-grep",
|
|
73
75
|
),
|
|
74
76
|
"ast": ToolConfig(
|
|
75
|
-
name="ast",
|
|
77
|
+
name="ast",
|
|
76
78
|
category=ToolCategory.FILESYSTEM,
|
|
77
79
|
description="Search source code with AST context using tree-sitter",
|
|
78
|
-
cli_flag="--disable-ast"
|
|
80
|
+
cli_flag="--disable-ast",
|
|
79
81
|
),
|
|
80
82
|
"content_replace": ToolConfig(
|
|
81
83
|
name="content_replace",
|
|
82
84
|
category=ToolCategory.FILESYSTEM,
|
|
83
85
|
description="Bulk text replacement across multiple files",
|
|
84
|
-
cli_flag="--disable-content-replace"
|
|
86
|
+
cli_flag="--disable-content-replace",
|
|
85
87
|
),
|
|
86
|
-
|
|
87
88
|
# Shell Tools (1)
|
|
88
89
|
"run_command": ToolConfig(
|
|
89
90
|
name="run_command",
|
|
90
91
|
category=ToolCategory.SHELL,
|
|
91
92
|
description="Execute shell commands with session support",
|
|
92
|
-
cli_flag="--disable-run-command"
|
|
93
|
+
cli_flag="--disable-run-command",
|
|
93
94
|
),
|
|
94
|
-
|
|
95
95
|
# Jupyter Tools (2)
|
|
96
96
|
"notebook_read": ToolConfig(
|
|
97
97
|
name="notebook_read",
|
|
98
98
|
category=ToolCategory.JUPYTER,
|
|
99
99
|
description="Read Jupyter notebook files (.ipynb)",
|
|
100
|
-
cli_flag="--disable-notebook-read"
|
|
100
|
+
cli_flag="--disable-notebook-read",
|
|
101
101
|
),
|
|
102
102
|
"notebook_edit": ToolConfig(
|
|
103
103
|
name="notebook_edit",
|
|
104
104
|
category=ToolCategory.JUPYTER,
|
|
105
105
|
description="Edit Jupyter notebook cells (replace, insert, delete)",
|
|
106
|
-
cli_flag="--disable-notebook-edit"
|
|
106
|
+
cli_flag="--disable-notebook-edit",
|
|
107
107
|
),
|
|
108
|
-
|
|
109
108
|
# Todo Tools (2)
|
|
110
109
|
"todo_read": ToolConfig(
|
|
111
110
|
name="todo_read",
|
|
112
111
|
category=ToolCategory.TODO,
|
|
113
112
|
description="Read the current todo list for a session",
|
|
114
|
-
cli_flag="--disable-todo-read"
|
|
113
|
+
cli_flag="--disable-todo-read",
|
|
115
114
|
),
|
|
116
115
|
"todo_write": ToolConfig(
|
|
117
|
-
name="todo_write",
|
|
116
|
+
name="todo_write",
|
|
118
117
|
category=ToolCategory.TODO,
|
|
119
118
|
description="Create and manage structured task lists",
|
|
120
|
-
cli_flag="--disable-todo-write"
|
|
119
|
+
cli_flag="--disable-todo-write",
|
|
121
120
|
),
|
|
122
|
-
|
|
123
121
|
# Agent Tools (3)
|
|
124
122
|
"dispatch_agent": ToolConfig(
|
|
125
123
|
name="dispatch_agent",
|
|
126
124
|
category=ToolCategory.AGENT,
|
|
127
125
|
enabled=False, # Disabled by default
|
|
128
126
|
description="Delegate tasks to sub-agents for concurrent/specialized processing",
|
|
129
|
-
cli_flag="--enable-dispatch-agent"
|
|
127
|
+
cli_flag="--enable-dispatch-agent",
|
|
130
128
|
),
|
|
131
129
|
"swarm": ToolConfig(
|
|
132
130
|
name="swarm",
|
|
133
131
|
category=ToolCategory.AGENT,
|
|
134
132
|
enabled=False, # Disabled by default
|
|
135
133
|
description="Execute multiple agent tasks in parallel across different files",
|
|
136
|
-
cli_flag="--enable-swarm"
|
|
134
|
+
cli_flag="--enable-swarm",
|
|
137
135
|
),
|
|
138
136
|
"hierarchical_swarm": ToolConfig(
|
|
139
137
|
name="hierarchical_swarm",
|
|
140
138
|
category=ToolCategory.AGENT,
|
|
141
139
|
enabled=False, # Disabled by default
|
|
142
140
|
description="Execute hierarchical agent swarms with Claude Code integration",
|
|
143
|
-
cli_flag="--enable-hierarchical-swarm"
|
|
141
|
+
cli_flag="--enable-hierarchical-swarm",
|
|
144
142
|
),
|
|
145
|
-
|
|
146
143
|
# Common Tools (3)
|
|
147
144
|
"think": ToolConfig(
|
|
148
145
|
name="think",
|
|
149
146
|
category=ToolCategory.COMMON,
|
|
150
147
|
description="Provide structured thinking space for complex reasoning",
|
|
151
|
-
cli_flag="--disable-think"
|
|
148
|
+
cli_flag="--disable-think",
|
|
152
149
|
),
|
|
153
150
|
"batch": ToolConfig(
|
|
154
151
|
name="batch",
|
|
155
152
|
category=ToolCategory.COMMON,
|
|
156
153
|
description="Execute multiple tools in parallel or serial",
|
|
157
|
-
cli_flag="--disable-batch"
|
|
154
|
+
cli_flag="--disable-batch",
|
|
158
155
|
),
|
|
159
|
-
|
|
160
156
|
# Vector Tools (2)
|
|
161
157
|
"vector_index": ToolConfig(
|
|
162
158
|
name="vector_index",
|
|
163
159
|
category=ToolCategory.VECTOR,
|
|
164
160
|
enabled=False, # Disabled by default
|
|
165
161
|
description="Index documents in local vector database for semantic search",
|
|
166
|
-
cli_flag="--enable-vector-index"
|
|
162
|
+
cli_flag="--enable-vector-index",
|
|
167
163
|
),
|
|
168
164
|
"vector_search": ToolConfig(
|
|
169
165
|
name="vector_search",
|
|
170
166
|
category=ToolCategory.VECTOR,
|
|
171
167
|
enabled=False, # Disabled by default
|
|
172
168
|
description="Search documents using semantic similarity in vector database",
|
|
173
|
-
cli_flag="--enable-vector-search"
|
|
169
|
+
cli_flag="--enable-vector-search",
|
|
174
170
|
),
|
|
175
171
|
}
|
|
176
172
|
|
|
@@ -208,4 +204,6 @@ def disable_tool(tool_name: str) -> bool:
|
|
|
208
204
|
|
|
209
205
|
def is_tool_enabled(tool_name: str) -> bool:
|
|
210
206
|
"""Check if a tool is enabled."""
|
|
211
|
-
return TOOL_REGISTRY.get(
|
|
207
|
+
return TOOL_REGISTRY.get(
|
|
208
|
+
tool_name, ToolConfig("", ToolCategory.COMMON, False)
|
|
209
|
+
).enabled
|
hanzo_mcp/dev_server.py
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
"""Development server with hot reload for Hanzo AI."""
|
|
2
2
|
|
|
3
|
+
import time
|
|
3
4
|
import asyncio
|
|
4
5
|
import logging
|
|
5
|
-
import
|
|
6
|
-
import sys
|
|
7
|
-
import time
|
|
6
|
+
from typing import Set, Optional
|
|
8
7
|
from pathlib import Path
|
|
9
|
-
from typing import Optional, Set
|
|
10
8
|
|
|
11
9
|
import watchdog.events
|
|
12
10
|
import watchdog.observers
|
|
@@ -17,77 +15,87 @@ from hanzo_mcp.server import HanzoMCPServer
|
|
|
17
15
|
|
|
18
16
|
class MCPReloadHandler(FileSystemEventHandler):
|
|
19
17
|
"""Handler for file system events that triggers MCP server reload."""
|
|
20
|
-
|
|
18
|
+
|
|
21
19
|
def __init__(self, restart_callback, ignore_patterns: Optional[Set[str]] = None):
|
|
22
20
|
"""Initialize the reload handler.
|
|
23
|
-
|
|
21
|
+
|
|
24
22
|
Args:
|
|
25
23
|
restart_callback: Function to call when files change
|
|
26
24
|
ignore_patterns: Set of patterns to ignore
|
|
27
25
|
"""
|
|
28
26
|
self.restart_callback = restart_callback
|
|
29
27
|
self.ignore_patterns = ignore_patterns or {
|
|
30
|
-
"__pycache__",
|
|
31
|
-
".
|
|
32
|
-
".
|
|
28
|
+
"__pycache__",
|
|
29
|
+
".pyc",
|
|
30
|
+
".pyo",
|
|
31
|
+
".git",
|
|
32
|
+
".pytest_cache",
|
|
33
|
+
".mypy_cache",
|
|
34
|
+
".ruff_cache",
|
|
35
|
+
".coverage",
|
|
36
|
+
"*.log",
|
|
37
|
+
".env",
|
|
38
|
+
".venv",
|
|
39
|
+
"venv",
|
|
40
|
+
"node_modules",
|
|
33
41
|
}
|
|
34
42
|
self.last_reload = 0
|
|
35
43
|
self.reload_delay = 0.5 # Debounce delay in seconds
|
|
36
|
-
|
|
44
|
+
|
|
37
45
|
def should_ignore(self, path: str) -> bool:
|
|
38
46
|
"""Check if a path should be ignored."""
|
|
39
47
|
path_obj = Path(path)
|
|
40
|
-
|
|
48
|
+
|
|
41
49
|
# Check against ignore patterns
|
|
42
50
|
for pattern in self.ignore_patterns:
|
|
43
51
|
if pattern in str(path_obj):
|
|
44
52
|
return True
|
|
45
53
|
if path_obj.name.endswith(pattern):
|
|
46
54
|
return True
|
|
47
|
-
|
|
55
|
+
|
|
48
56
|
# Only watch Python files and config files
|
|
49
57
|
if path_obj.is_file():
|
|
50
58
|
allowed_extensions = {".py", ".json", ".yaml", ".yml", ".toml"}
|
|
51
59
|
if path_obj.suffix not in allowed_extensions:
|
|
52
60
|
return True
|
|
53
|
-
|
|
61
|
+
|
|
54
62
|
return False
|
|
55
|
-
|
|
63
|
+
|
|
56
64
|
def on_any_event(self, event):
|
|
57
65
|
"""Handle any file system event."""
|
|
58
66
|
if event.is_directory:
|
|
59
67
|
return
|
|
60
|
-
|
|
68
|
+
|
|
61
69
|
if self.should_ignore(event.src_path):
|
|
62
70
|
return
|
|
63
|
-
|
|
71
|
+
|
|
64
72
|
# Debounce rapid changes
|
|
65
73
|
current_time = time.time()
|
|
66
74
|
if current_time - self.last_reload < self.reload_delay:
|
|
67
75
|
return
|
|
68
|
-
|
|
76
|
+
|
|
69
77
|
self.last_reload = current_time
|
|
70
|
-
|
|
78
|
+
|
|
71
79
|
logger = logging.getLogger(__name__)
|
|
72
80
|
logger.info(f"\n🔄 File changed: {event.src_path}")
|
|
73
81
|
logger.info("🔄 Reloading MCP server...")
|
|
74
|
-
|
|
82
|
+
|
|
75
83
|
self.restart_callback()
|
|
76
84
|
|
|
77
85
|
|
|
78
86
|
class DevServer:
|
|
79
87
|
"""Development server with hot reload capability."""
|
|
80
|
-
|
|
88
|
+
|
|
81
89
|
def __init__(
|
|
82
90
|
self,
|
|
83
91
|
name: str = "hanzo-dev",
|
|
84
92
|
allowed_paths: Optional[list[str]] = None,
|
|
85
93
|
project_paths: Optional[list[str]] = None,
|
|
86
94
|
project_dir: Optional[str] = None,
|
|
87
|
-
**kwargs
|
|
95
|
+
**kwargs,
|
|
88
96
|
):
|
|
89
97
|
"""Initialize the development server.
|
|
90
|
-
|
|
98
|
+
|
|
91
99
|
Args:
|
|
92
100
|
name: Server name
|
|
93
101
|
allowed_paths: Allowed paths for the server
|
|
@@ -103,7 +111,7 @@ class DevServer:
|
|
|
103
111
|
self.server_process = None
|
|
104
112
|
self.observer = None
|
|
105
113
|
self.running = False
|
|
106
|
-
|
|
114
|
+
|
|
107
115
|
def create_server(self) -> HanzoMCPServer:
|
|
108
116
|
"""Create a new MCP server instance."""
|
|
109
117
|
return HanzoMCPServer(
|
|
@@ -111,76 +119,80 @@ class DevServer:
|
|
|
111
119
|
allowed_paths=self.allowed_paths,
|
|
112
120
|
project_paths=self.project_paths,
|
|
113
121
|
project_dir=self.project_dir,
|
|
114
|
-
**self.server_kwargs
|
|
122
|
+
**self.server_kwargs,
|
|
115
123
|
)
|
|
116
|
-
|
|
124
|
+
|
|
117
125
|
def start_file_watcher(self):
|
|
118
126
|
"""Start watching for file changes."""
|
|
119
127
|
# Watch the hanzo_mcp package directory
|
|
120
128
|
package_dir = Path(__file__).parent
|
|
121
|
-
|
|
129
|
+
|
|
122
130
|
# Create observer and handler
|
|
123
131
|
self.observer = watchdog.observers.Observer()
|
|
124
132
|
handler = MCPReloadHandler(self.restart_server)
|
|
125
|
-
|
|
133
|
+
|
|
126
134
|
# Watch the package directory
|
|
127
135
|
self.observer.schedule(handler, str(package_dir), recursive=True)
|
|
128
|
-
|
|
136
|
+
|
|
129
137
|
# Also watch any project directories
|
|
130
138
|
if self.project_dir:
|
|
131
139
|
self.observer.schedule(handler, self.project_dir, recursive=True)
|
|
132
|
-
|
|
140
|
+
|
|
133
141
|
for path in self.allowed_paths:
|
|
134
142
|
if Path(path).is_dir() and path not in [str(package_dir), self.project_dir]:
|
|
135
143
|
self.observer.schedule(handler, path, recursive=True)
|
|
136
|
-
|
|
144
|
+
|
|
137
145
|
self.observer.start()
|
|
138
146
|
logger = logging.getLogger(__name__)
|
|
139
147
|
logger.info(f"👀 Watching for changes in: {package_dir}")
|
|
140
148
|
if self.project_dir:
|
|
141
149
|
logger.info(f"👀 Also watching: {self.project_dir}")
|
|
142
|
-
|
|
150
|
+
|
|
143
151
|
def stop_file_watcher(self):
|
|
144
152
|
"""Stop the file watcher."""
|
|
145
153
|
if self.observer and self.observer.is_alive():
|
|
146
154
|
self.observer.stop()
|
|
147
155
|
self.observer.join(timeout=2)
|
|
148
|
-
|
|
156
|
+
|
|
149
157
|
def restart_server(self):
|
|
150
158
|
"""Restart the MCP server."""
|
|
151
159
|
# Since MCP servers run in the same process, we need to handle this differently
|
|
152
160
|
# For now, we'll log a message indicating a restart is needed
|
|
153
161
|
logger = logging.getLogger(__name__)
|
|
154
|
-
logger.warning(
|
|
155
|
-
|
|
156
|
-
|
|
162
|
+
logger.warning(
|
|
163
|
+
"\n⚠️ Server restart required. Please restart the MCP client to reload changes."
|
|
164
|
+
)
|
|
165
|
+
logger.info(
|
|
166
|
+
"💡 Tip: In development, consider using the MCP test client for easier reloading."
|
|
167
|
+
)
|
|
168
|
+
|
|
157
169
|
async def run_async(self, transport: str = "stdio"):
|
|
158
170
|
"""Run the development server asynchronously."""
|
|
159
171
|
self.running = True
|
|
160
|
-
|
|
172
|
+
|
|
161
173
|
logger = logging.getLogger(__name__)
|
|
162
174
|
logger.info(f"\n🚀 Starting Hanzo AI in development mode...")
|
|
163
175
|
logger.info(f"🔧 Hot reload enabled - watching for file changes")
|
|
164
176
|
logger.info(f"📁 Project: {self.project_dir or 'current directory'}")
|
|
165
177
|
logger.info(f"🌐 Transport: {transport}\n")
|
|
166
|
-
|
|
178
|
+
|
|
167
179
|
# Start file watcher
|
|
168
180
|
self.start_file_watcher()
|
|
169
|
-
|
|
181
|
+
|
|
170
182
|
try:
|
|
171
183
|
# Create and run server
|
|
172
184
|
server = self.create_server()
|
|
173
|
-
|
|
185
|
+
|
|
174
186
|
# Run the server (this will block)
|
|
175
187
|
server.run(transport=transport)
|
|
176
|
-
|
|
188
|
+
|
|
177
189
|
except KeyboardInterrupt:
|
|
178
190
|
logger.info("\n\n🛑 Shutting down development server...")
|
|
179
191
|
finally:
|
|
180
192
|
self.running = False
|
|
181
193
|
self.stop_file_watcher()
|
|
182
194
|
logger.info("👋 Development server stopped")
|
|
183
|
-
|
|
195
|
+
|
|
184
196
|
def run(self, transport: str = "stdio"):
|
|
185
197
|
"""Run the development server."""
|
|
186
198
|
try:
|
|
@@ -193,48 +205,35 @@ class DevServer:
|
|
|
193
205
|
def run_dev_server():
|
|
194
206
|
"""Entry point for development server."""
|
|
195
207
|
import argparse
|
|
196
|
-
|
|
197
|
-
parser = argparse.ArgumentParser(
|
|
198
|
-
|
|
199
|
-
"--name",
|
|
200
|
-
type=str,
|
|
201
|
-
default="hanzo-dev",
|
|
202
|
-
help="Name of the MCP server"
|
|
208
|
+
|
|
209
|
+
parser = argparse.ArgumentParser(
|
|
210
|
+
description="Run Hanzo AI in development mode with hot reload"
|
|
203
211
|
)
|
|
204
212
|
parser.add_argument(
|
|
205
|
-
"--
|
|
206
|
-
type=str,
|
|
207
|
-
help="Project directory to serve"
|
|
213
|
+
"--name", type=str, default="hanzo-dev", help="Name of the MCP server"
|
|
208
214
|
)
|
|
215
|
+
parser.add_argument("--project-dir", type=str, help="Project directory to serve")
|
|
209
216
|
parser.add_argument(
|
|
210
217
|
"--allowed-path",
|
|
211
218
|
type=str,
|
|
212
219
|
action="append",
|
|
213
220
|
dest="allowed_paths",
|
|
214
|
-
help="Additional allowed paths (can be specified multiple times)"
|
|
221
|
+
help="Additional allowed paths (can be specified multiple times)",
|
|
215
222
|
)
|
|
216
223
|
parser.add_argument(
|
|
217
224
|
"--transport",
|
|
218
225
|
type=str,
|
|
219
226
|
default="stdio",
|
|
220
227
|
choices=["stdio", "sse"],
|
|
221
|
-
help="Transport type (default: stdio)"
|
|
228
|
+
help="Transport type (default: stdio)",
|
|
222
229
|
)
|
|
223
230
|
parser.add_argument(
|
|
224
|
-
"--host",
|
|
225
|
-
type=str,
|
|
226
|
-
default="127.0.0.1",
|
|
227
|
-
help="Host for SSE transport"
|
|
231
|
+
"--host", type=str, default="127.0.0.1", help="Host for SSE transport"
|
|
228
232
|
)
|
|
229
|
-
parser.add_argument(
|
|
230
|
-
|
|
231
|
-
type=int,
|
|
232
|
-
default=3000,
|
|
233
|
-
help="Port for SSE transport"
|
|
234
|
-
)
|
|
235
|
-
|
|
233
|
+
parser.add_argument("--port", type=int, default=3000, help="Port for SSE transport")
|
|
234
|
+
|
|
236
235
|
args = parser.parse_args()
|
|
237
|
-
|
|
236
|
+
|
|
238
237
|
# Create and run dev server
|
|
239
238
|
dev_server = DevServer(
|
|
240
239
|
name=args.name,
|
|
@@ -243,9 +242,9 @@ def run_dev_server():
|
|
|
243
242
|
host=args.host,
|
|
244
243
|
port=args.port,
|
|
245
244
|
)
|
|
246
|
-
|
|
245
|
+
|
|
247
246
|
dev_server.run(transport=args.transport)
|
|
248
247
|
|
|
249
248
|
|
|
250
249
|
if __name__ == "__main__":
|
|
251
|
-
run_dev_server()
|
|
250
|
+
run_dev_server()
|
hanzo_mcp/prompts/__init__.py
CHANGED
|
@@ -2,25 +2,36 @@ import os
|
|
|
2
2
|
|
|
3
3
|
from mcp.server import FastMCP
|
|
4
4
|
|
|
5
|
-
from hanzo_mcp.prompts.compact_conversation import COMPACT_CONVERSATION_PROMPT
|
|
6
|
-
from hanzo_mcp.prompts.create_release import CREATE_RELEASE_PROMPT
|
|
7
|
-
from hanzo_mcp.prompts.project_system import PROJECT_SYSTEM_PROMPT
|
|
8
|
-
from hanzo_mcp.prompts.project_todo_reminder import (
|
|
9
|
-
PROJECT_TODO_EMPTY_REMINDER,
|
|
10
|
-
get_project_todo_reminder,
|
|
11
|
-
)
|
|
12
5
|
from hanzo_mcp.prompts.utils import (
|
|
13
|
-
get_directory_structure,
|
|
14
|
-
get_git_info,
|
|
15
6
|
get_os_info,
|
|
7
|
+
get_git_info,
|
|
8
|
+
get_directory_structure,
|
|
16
9
|
)
|
|
17
10
|
from hanzo_mcp.prompts.tool_explorer import (
|
|
18
|
-
TOOL_EXPLORER_PROMPT,
|
|
19
|
-
FILESYSTEM_TOOLS_HELP,
|
|
20
11
|
AGENT_TOOLS_HELP,
|
|
21
12
|
SHELL_TOOLS_HELP,
|
|
22
13
|
BATCH_TOOL_EXAMPLES,
|
|
23
|
-
|
|
14
|
+
TOOL_EXPLORER_PROMPT,
|
|
15
|
+
FILESYSTEM_TOOLS_HELP,
|
|
16
|
+
)
|
|
17
|
+
from hanzo_mcp.prompts.create_release import CREATE_RELEASE_PROMPT
|
|
18
|
+
from hanzo_mcp.prompts.project_system import PROJECT_SYSTEM_PROMPT
|
|
19
|
+
from hanzo_mcp.prompts.enhanced_prompts import (
|
|
20
|
+
QUICK_START_PROMPT,
|
|
21
|
+
LSP_TOOLS_HELP_PROMPT,
|
|
22
|
+
PAGINATION_GUIDE_PROMPT,
|
|
23
|
+
PERFORMANCE_TIPS_PROMPT,
|
|
24
|
+
MEMORY_VECTOR_HELP_PROMPT,
|
|
25
|
+
CONFIGURATION_GUIDE_PROMPT,
|
|
26
|
+
DATABASE_TOOLS_HELP_PROMPT,
|
|
27
|
+
NETWORK_AGENT_GUIDE_PROMPT,
|
|
28
|
+
TROUBLESHOOTING_GUIDE_PROMPT,
|
|
29
|
+
SECURITY_BEST_PRACTICES_PROMPT,
|
|
30
|
+
)
|
|
31
|
+
from hanzo_mcp.prompts.compact_conversation import COMPACT_CONVERSATION_PROMPT
|
|
32
|
+
from hanzo_mcp.prompts.project_todo_reminder import (
|
|
33
|
+
PROJECT_TODO_EMPTY_REMINDER,
|
|
34
|
+
get_project_todo_reminder,
|
|
24
35
|
)
|
|
25
36
|
|
|
26
37
|
CONTINUE_FROM_LAST_SESSION_PROMPT = """<system-reminder>
|
|
@@ -140,6 +151,77 @@ def register_all_prompts(
|
|
|
140
151
|
"""
|
|
141
152
|
return BATCH_TOOL_EXAMPLES
|
|
142
153
|
|
|
154
|
+
# Enhanced prompts for better discoverability
|
|
155
|
+
@mcp_server.prompt(name="Quick start guide")
|
|
156
|
+
def quick_start() -> str:
|
|
157
|
+
"""
|
|
158
|
+
Common workflows and recipes for getting started quickly.
|
|
159
|
+
"""
|
|
160
|
+
return QUICK_START_PROMPT
|
|
161
|
+
|
|
162
|
+
@mcp_server.prompt(name="Pagination guide")
|
|
163
|
+
def pagination_guide() -> str:
|
|
164
|
+
"""
|
|
165
|
+
How to use pagination for large result sets.
|
|
166
|
+
"""
|
|
167
|
+
return PAGINATION_GUIDE_PROMPT
|
|
168
|
+
|
|
169
|
+
@mcp_server.prompt(name="Memory and vector tools help")
|
|
170
|
+
def memory_vector_help() -> str:
|
|
171
|
+
"""
|
|
172
|
+
Guide for semantic search and memory tools.
|
|
173
|
+
"""
|
|
174
|
+
return MEMORY_VECTOR_HELP_PROMPT
|
|
175
|
+
|
|
176
|
+
@mcp_server.prompt(name="Database tools help")
|
|
177
|
+
def database_help() -> str:
|
|
178
|
+
"""
|
|
179
|
+
SQL and graph database operations guide.
|
|
180
|
+
"""
|
|
181
|
+
return DATABASE_TOOLS_HELP_PROMPT
|
|
182
|
+
|
|
183
|
+
@mcp_server.prompt(name="LSP tools help")
|
|
184
|
+
def lsp_help() -> str:
|
|
185
|
+
"""
|
|
186
|
+
Language Server Protocol features and code intelligence.
|
|
187
|
+
"""
|
|
188
|
+
return LSP_TOOLS_HELP_PROMPT
|
|
189
|
+
|
|
190
|
+
@mcp_server.prompt(name="Configuration guide")
|
|
191
|
+
def config_guide() -> str:
|
|
192
|
+
"""
|
|
193
|
+
How to configure tools, presets, and settings.
|
|
194
|
+
"""
|
|
195
|
+
return CONFIGURATION_GUIDE_PROMPT
|
|
196
|
+
|
|
197
|
+
@mcp_server.prompt(name="Network agent guide")
|
|
198
|
+
def network_guide() -> str:
|
|
199
|
+
"""
|
|
200
|
+
Distributed AI orchestration with network/swarm tools.
|
|
201
|
+
"""
|
|
202
|
+
return NETWORK_AGENT_GUIDE_PROMPT
|
|
203
|
+
|
|
204
|
+
@mcp_server.prompt(name="Performance tips")
|
|
205
|
+
def performance_tips() -> str:
|
|
206
|
+
"""
|
|
207
|
+
Optimization strategies for better performance.
|
|
208
|
+
"""
|
|
209
|
+
return PERFORMANCE_TIPS_PROMPT
|
|
210
|
+
|
|
211
|
+
@mcp_server.prompt(name="Security best practices")
|
|
212
|
+
def security_practices() -> str:
|
|
213
|
+
"""
|
|
214
|
+
Safe usage patterns and security guidelines.
|
|
215
|
+
"""
|
|
216
|
+
return SECURITY_BEST_PRACTICES_PROMPT
|
|
217
|
+
|
|
218
|
+
@mcp_server.prompt(name="Troubleshooting guide")
|
|
219
|
+
def troubleshooting() -> str:
|
|
220
|
+
"""
|
|
221
|
+
Common issues and their solutions.
|
|
222
|
+
"""
|
|
223
|
+
return TROUBLESHOOTING_GUIDE_PROMPT
|
|
224
|
+
|
|
143
225
|
if projects is None:
|
|
144
226
|
return
|
|
145
227
|
|