hanzo-mcp 0.6.13__py3-none-any.whl → 0.7.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/analytics/__init__.py +5 -0
- hanzo_mcp/analytics/posthog_analytics.py +364 -0
- hanzo_mcp/cli.py +3 -3
- hanzo_mcp/cli_enhanced.py +3 -3
- hanzo_mcp/config/settings.py +1 -1
- hanzo_mcp/config/tool_config.py +18 -4
- hanzo_mcp/server.py +34 -1
- hanzo_mcp/tools/__init__.py +65 -2
- hanzo_mcp/tools/agent/__init__.py +84 -3
- hanzo_mcp/tools/agent/agent_tool.py +102 -4
- hanzo_mcp/tools/agent/agent_tool_v2.py +492 -0
- hanzo_mcp/tools/agent/clarification_protocol.py +220 -0
- hanzo_mcp/tools/agent/clarification_tool.py +68 -0
- hanzo_mcp/tools/agent/claude_cli_tool.py +125 -0
- hanzo_mcp/tools/agent/claude_desktop_auth.py +508 -0
- hanzo_mcp/tools/agent/cli_agent_base.py +191 -0
- hanzo_mcp/tools/agent/code_auth.py +436 -0
- hanzo_mcp/tools/agent/code_auth_tool.py +194 -0
- hanzo_mcp/tools/agent/codex_cli_tool.py +123 -0
- hanzo_mcp/tools/agent/critic_tool.py +376 -0
- hanzo_mcp/tools/agent/gemini_cli_tool.py +128 -0
- hanzo_mcp/tools/agent/grok_cli_tool.py +128 -0
- hanzo_mcp/tools/agent/iching_tool.py +380 -0
- hanzo_mcp/tools/agent/network_tool.py +273 -0
- hanzo_mcp/tools/agent/prompt.py +62 -20
- hanzo_mcp/tools/agent/review_tool.py +433 -0
- hanzo_mcp/tools/agent/swarm_tool.py +535 -0
- hanzo_mcp/tools/agent/swarm_tool_v2.py +654 -0
- hanzo_mcp/tools/common/base.py +1 -0
- hanzo_mcp/tools/common/batch_tool.py +102 -10
- hanzo_mcp/tools/common/fastmcp_pagination.py +369 -0
- hanzo_mcp/tools/common/forgiving_edit.py +243 -0
- hanzo_mcp/tools/common/paginated_base.py +230 -0
- hanzo_mcp/tools/common/paginated_response.py +307 -0
- hanzo_mcp/tools/common/pagination.py +226 -0
- hanzo_mcp/tools/common/tool_list.py +3 -0
- hanzo_mcp/tools/common/truncate.py +101 -0
- hanzo_mcp/tools/filesystem/__init__.py +29 -0
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +562 -0
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +338 -0
- hanzo_mcp/tools/lsp/__init__.py +5 -0
- hanzo_mcp/tools/lsp/lsp_tool.py +512 -0
- hanzo_mcp/tools/memory/__init__.py +76 -0
- hanzo_mcp/tools/memory/knowledge_tools.py +518 -0
- hanzo_mcp/tools/memory/memory_tools.py +456 -0
- hanzo_mcp/tools/search/__init__.py +6 -0
- hanzo_mcp/tools/search/find_tool.py +581 -0
- hanzo_mcp/tools/search/unified_search.py +953 -0
- hanzo_mcp/tools/shell/__init__.py +5 -0
- hanzo_mcp/tools/shell/auto_background.py +203 -0
- hanzo_mcp/tools/shell/base_process.py +53 -27
- hanzo_mcp/tools/shell/bash_tool.py +17 -33
- hanzo_mcp/tools/shell/npx_tool.py +15 -32
- hanzo_mcp/tools/shell/streaming_command.py +594 -0
- hanzo_mcp/tools/shell/uvx_tool.py +15 -32
- hanzo_mcp/types.py +23 -0
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.1.dist-info}/METADATA +229 -71
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.1.dist-info}/RECORD +61 -24
- hanzo_mcp-0.6.13.dist-info/licenses/LICENSE +0 -21
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.1.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.1.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.1.dist-info}/top_level.txt +0 -0
|
@@ -4,9 +4,32 @@ This module provides tools that allow Claude to delegate tasks to sub-agents,
|
|
|
4
4
|
enabling concurrent execution of multiple operations and specialized processing.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import os
|
|
7
8
|
from mcp.server import FastMCP
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
# Try to use hanzo-agents SDK versions if available
|
|
11
|
+
USE_HANZO_AGENTS = os.environ.get("USE_HANZO_AGENTS", "true").lower() == "true"
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
if USE_HANZO_AGENTS:
|
|
15
|
+
from hanzo_mcp.tools.agent.agent_tool_v2 import AgentTool
|
|
16
|
+
from hanzo_mcp.tools.agent.swarm_tool_v2 import SwarmTool
|
|
17
|
+
print("[MCP] Using hanzo-agents SDK for agent and swarm tools")
|
|
18
|
+
else:
|
|
19
|
+
raise ImportError("USE_HANZO_AGENTS=false")
|
|
20
|
+
except ImportError:
|
|
21
|
+
# Fall back to original implementations
|
|
22
|
+
from hanzo_mcp.tools.agent.agent_tool import AgentTool
|
|
23
|
+
from hanzo_mcp.tools.agent.swarm_tool import SwarmTool
|
|
24
|
+
if USE_HANZO_AGENTS:
|
|
25
|
+
print("[MCP] hanzo-agents SDK not available, using original agent implementations")
|
|
26
|
+
|
|
27
|
+
from hanzo_mcp.tools.agent.claude_cli_tool import ClaudeCLITool
|
|
28
|
+
from hanzo_mcp.tools.agent.codex_cli_tool import CodexCLITool
|
|
29
|
+
from hanzo_mcp.tools.agent.gemini_cli_tool import GeminiCLITool
|
|
30
|
+
from hanzo_mcp.tools.agent.grok_cli_tool import GrokCLITool
|
|
31
|
+
from hanzo_mcp.tools.agent.code_auth_tool import CodeAuthTool
|
|
32
|
+
from hanzo_mcp.tools.agent.network_tool import NetworkTool, LocalSwarmTool
|
|
10
33
|
from hanzo_mcp.tools.common.base import BaseTool, ToolRegistry
|
|
11
34
|
|
|
12
35
|
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
@@ -48,9 +71,67 @@ def register_agent_tools(
|
|
|
48
71
|
max_iterations=agent_max_iterations,
|
|
49
72
|
max_tool_uses=agent_max_tool_uses,
|
|
50
73
|
)
|
|
74
|
+
|
|
75
|
+
# Create swarm tool
|
|
76
|
+
swarm_tool = SwarmTool(
|
|
77
|
+
permission_manager=permission_manager,
|
|
78
|
+
model=agent_model,
|
|
79
|
+
api_key=agent_api_key,
|
|
80
|
+
base_url=agent_base_url,
|
|
81
|
+
max_tokens=agent_max_tokens,
|
|
82
|
+
agent_max_iterations=agent_max_iterations,
|
|
83
|
+
agent_max_tool_uses=agent_max_tool_uses,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# Create CLI agent tools
|
|
88
|
+
claude_cli_tool = ClaudeCLITool(
|
|
89
|
+
permission_manager=permission_manager,
|
|
90
|
+
model=agent_model, # Can override default Sonnet
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
codex_cli_tool = CodexCLITool(
|
|
94
|
+
permission_manager=permission_manager,
|
|
95
|
+
model=agent_model if agent_model and "gpt" in agent_model else None,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
gemini_cli_tool = GeminiCLITool(
|
|
99
|
+
permission_manager=permission_manager,
|
|
100
|
+
model=agent_model if agent_model and "gemini" in agent_model else None,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
grok_cli_tool = GrokCLITool(
|
|
104
|
+
permission_manager=permission_manager,
|
|
105
|
+
model=agent_model if agent_model and "grok" in agent_model else None,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Create auth management tool
|
|
109
|
+
code_auth_tool = CodeAuthTool()
|
|
110
|
+
|
|
111
|
+
# Create network tool
|
|
112
|
+
network_tool = NetworkTool(
|
|
113
|
+
permission_manager=permission_manager,
|
|
114
|
+
default_mode="hybrid" # Prefer local, fallback to cloud
|
|
115
|
+
)
|
|
51
116
|
|
|
52
|
-
# Register
|
|
117
|
+
# Register tools
|
|
53
118
|
ToolRegistry.register_tool(mcp_server, agent_tool)
|
|
119
|
+
ToolRegistry.register_tool(mcp_server, swarm_tool)
|
|
120
|
+
ToolRegistry.register_tool(mcp_server, network_tool)
|
|
121
|
+
ToolRegistry.register_tool(mcp_server, claude_cli_tool)
|
|
122
|
+
ToolRegistry.register_tool(mcp_server, codex_cli_tool)
|
|
123
|
+
ToolRegistry.register_tool(mcp_server, gemini_cli_tool)
|
|
124
|
+
ToolRegistry.register_tool(mcp_server, grok_cli_tool)
|
|
125
|
+
ToolRegistry.register_tool(mcp_server, code_auth_tool)
|
|
54
126
|
|
|
55
127
|
# Return list of registered tools
|
|
56
|
-
return [
|
|
128
|
+
return [
|
|
129
|
+
agent_tool,
|
|
130
|
+
swarm_tool,
|
|
131
|
+
network_tool,
|
|
132
|
+
claude_cli_tool,
|
|
133
|
+
codex_cli_tool,
|
|
134
|
+
gemini_cli_tool,
|
|
135
|
+
grok_cli_tool,
|
|
136
|
+
code_auth_tool,
|
|
137
|
+
]
|
|
@@ -30,6 +30,14 @@ from hanzo_mcp.tools.agent.prompt import (
|
|
|
30
30
|
from hanzo_mcp.tools.agent.tool_adapter import (
|
|
31
31
|
convert_tools_to_openai_functions,
|
|
32
32
|
)
|
|
33
|
+
from hanzo_mcp.tools.agent.clarification_protocol import (
|
|
34
|
+
AgentClarificationMixin,
|
|
35
|
+
ClarificationType,
|
|
36
|
+
)
|
|
37
|
+
from hanzo_mcp.tools.agent.clarification_tool import ClarificationTool
|
|
38
|
+
from hanzo_mcp.tools.agent.critic_tool import CriticTool, CriticProtocol
|
|
39
|
+
from hanzo_mcp.tools.agent.review_tool import ReviewTool, ReviewProtocol
|
|
40
|
+
from hanzo_mcp.tools.agent.iching_tool import IChingTool
|
|
33
41
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
34
42
|
from hanzo_mcp.tools.common.batch_tool import BatchTool
|
|
35
43
|
from hanzo_mcp.tools.common.context import (
|
|
@@ -37,7 +45,7 @@ from hanzo_mcp.tools.common.context import (
|
|
|
37
45
|
create_tool_context,
|
|
38
46
|
)
|
|
39
47
|
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
40
|
-
from hanzo_mcp.tools.filesystem import get_read_only_filesystem_tools
|
|
48
|
+
from hanzo_mcp.tools.filesystem import get_read_only_filesystem_tools, Edit, MultiEdit
|
|
41
49
|
from hanzo_mcp.tools.jupyter import get_read_only_jupyter_tools
|
|
42
50
|
|
|
43
51
|
Prompt = Annotated[
|
|
@@ -60,11 +68,13 @@ class AgentToolParams(TypedDict, total=False):
|
|
|
60
68
|
|
|
61
69
|
|
|
62
70
|
@final
|
|
63
|
-
class AgentTool(BaseTool):
|
|
71
|
+
class AgentTool(AgentClarificationMixin, BaseTool):
|
|
64
72
|
"""Tool for delegating tasks to sub-agents.
|
|
65
73
|
|
|
66
74
|
The AgentTool allows Claude to create and manage sub-agents for performing
|
|
67
75
|
specialized tasks concurrently, such as code search, analysis, and more.
|
|
76
|
+
|
|
77
|
+
Agents can request clarification from the main loop up to once per task.
|
|
68
78
|
"""
|
|
69
79
|
|
|
70
80
|
@property
|
|
@@ -88,22 +98,26 @@ class AgentTool(BaseTool):
|
|
|
88
98
|
# TODO: Add glob when it is implemented
|
|
89
99
|
at = [t.name for t in self.available_tools]
|
|
90
100
|
|
|
91
|
-
return f"""Launch a new agent that has access to the following tools: {at} When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries, use the Agent tool to perform the search for you.
|
|
101
|
+
return f"""Launch a new agent that has access to the following tools: {at}. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries, use the Agent tool to perform the search for you.
|
|
92
102
|
|
|
93
103
|
When to use the Agent tool:
|
|
94
104
|
- If you are searching for a keyword like \"config\" or \"logger\", or for questions like \"which file does X?\", the Agent tool is strongly recommended
|
|
105
|
+
- When you need to perform edits across multiple files based on search results
|
|
106
|
+
- When you need to delegate complex file modification tasks
|
|
95
107
|
|
|
96
108
|
When NOT to use the Agent tool:
|
|
97
109
|
- If you want to read a specific file path, use the read or glob tool instead of the Agent tool, to find the match more quickly
|
|
98
110
|
- If you are searching for a specific class definition like \"class Foo\", use the glob tool instead, to find the match more quickly
|
|
99
111
|
- If you are searching for code within a specific file or set of 2-3 files, use the read tool instead of the Agent tool, to find the match more quickly
|
|
112
|
+
- Writing code and running bash commands (use other tools for that)
|
|
113
|
+
- Other tasks that are not related to searching for a keyword or file
|
|
100
114
|
|
|
101
115
|
Usage notes:
|
|
102
116
|
1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
|
|
103
117
|
2. When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
|
|
104
118
|
3. Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.
|
|
105
119
|
4. The agent's outputs should generally be trusted
|
|
106
|
-
5.
|
|
120
|
+
5. Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent"""
|
|
107
121
|
|
|
108
122
|
def __init__(
|
|
109
123
|
self,
|
|
@@ -142,9 +156,30 @@ Usage notes:
|
|
|
142
156
|
self.available_tools.extend(
|
|
143
157
|
get_read_only_jupyter_tools(self.permission_manager)
|
|
144
158
|
)
|
|
159
|
+
|
|
160
|
+
# Always add edit tools - agents should have edit access
|
|
161
|
+
self.available_tools.append(Edit(self.permission_manager))
|
|
162
|
+
self.available_tools.append(MultiEdit(self.permission_manager))
|
|
163
|
+
|
|
164
|
+
# Add clarification tool for agents
|
|
165
|
+
self.available_tools.append(ClarificationTool())
|
|
166
|
+
|
|
167
|
+
# Add critic tool for agents (devil's advocate)
|
|
168
|
+
self.available_tools.append(CriticTool())
|
|
169
|
+
|
|
170
|
+
# Add review tool for agents (balanced review)
|
|
171
|
+
self.available_tools.append(ReviewTool())
|
|
172
|
+
|
|
173
|
+
# Add I Ching tool for creative guidance
|
|
174
|
+
self.available_tools.append(IChingTool())
|
|
175
|
+
|
|
145
176
|
self.available_tools.append(
|
|
146
177
|
BatchTool({t.name: t for t in self.available_tools})
|
|
147
178
|
)
|
|
179
|
+
|
|
180
|
+
# Initialize protocols
|
|
181
|
+
self.critic_protocol = CriticProtocol()
|
|
182
|
+
self.review_protocol = ReviewProtocol()
|
|
148
183
|
|
|
149
184
|
@override
|
|
150
185
|
async def call(
|
|
@@ -445,6 +480,69 @@ AGENT RESPONSES:
|
|
|
445
480
|
)
|
|
446
481
|
if not tool:
|
|
447
482
|
tool_result = f"Error: Tool '{function_name}' not found"
|
|
483
|
+
# Special handling for clarification requests
|
|
484
|
+
elif function_name == "request_clarification":
|
|
485
|
+
try:
|
|
486
|
+
# Extract clarification parameters
|
|
487
|
+
request_type = function_args.get("type", "ADDITIONAL_INFO")
|
|
488
|
+
question = function_args.get("question", "")
|
|
489
|
+
context = function_args.get("context", {})
|
|
490
|
+
options = function_args.get("options", None)
|
|
491
|
+
|
|
492
|
+
# Convert string type to enum
|
|
493
|
+
clarification_type = ClarificationType[request_type]
|
|
494
|
+
|
|
495
|
+
# Request clarification
|
|
496
|
+
answer = await self.request_clarification(
|
|
497
|
+
request_type=clarification_type,
|
|
498
|
+
question=question,
|
|
499
|
+
context=context,
|
|
500
|
+
options=options
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
tool_result = self.format_clarification_in_output(question, answer)
|
|
504
|
+
except Exception as e:
|
|
505
|
+
tool_result = f"Error processing clarification: {str(e)}"
|
|
506
|
+
# Special handling for critic requests
|
|
507
|
+
elif function_name == "critic":
|
|
508
|
+
try:
|
|
509
|
+
# Extract critic parameters
|
|
510
|
+
review_type = function_args.get("review_type", "GENERAL")
|
|
511
|
+
work_description = function_args.get("work_description", "")
|
|
512
|
+
code_snippets = function_args.get("code_snippets", None)
|
|
513
|
+
file_paths = function_args.get("file_paths", None)
|
|
514
|
+
specific_concerns = function_args.get("specific_concerns", None)
|
|
515
|
+
|
|
516
|
+
# Request critical review
|
|
517
|
+
tool_result = self.critic_protocol.request_review(
|
|
518
|
+
review_type=review_type,
|
|
519
|
+
work_description=work_description,
|
|
520
|
+
code_snippets=code_snippets,
|
|
521
|
+
file_paths=file_paths,
|
|
522
|
+
specific_concerns=specific_concerns
|
|
523
|
+
)
|
|
524
|
+
except Exception as e:
|
|
525
|
+
tool_result = f"Error processing critic review: {str(e)}"
|
|
526
|
+
# Special handling for review requests
|
|
527
|
+
elif function_name == "review":
|
|
528
|
+
try:
|
|
529
|
+
# Extract review parameters
|
|
530
|
+
focus = function_args.get("focus", "GENERAL")
|
|
531
|
+
work_description = function_args.get("work_description", "")
|
|
532
|
+
code_snippets = function_args.get("code_snippets", None)
|
|
533
|
+
file_paths = function_args.get("file_paths", None)
|
|
534
|
+
context = function_args.get("context", None)
|
|
535
|
+
|
|
536
|
+
# Request balanced review
|
|
537
|
+
tool_result = self.review_protocol.request_review(
|
|
538
|
+
focus=focus,
|
|
539
|
+
work_description=work_description,
|
|
540
|
+
code_snippets=code_snippets,
|
|
541
|
+
file_paths=file_paths,
|
|
542
|
+
context=context
|
|
543
|
+
)
|
|
544
|
+
except Exception as e:
|
|
545
|
+
tool_result = f"Error processing review: {str(e)}"
|
|
448
546
|
else:
|
|
449
547
|
try:
|
|
450
548
|
tool_result = await tool.call(
|