hanzo-mcp 0.9.1__py3-none-any.whl → 0.9.3__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.

@@ -450,6 +450,9 @@ AGENT RESPONSES:
450
450
  tool_call_count = len(message.tool_calls)
451
451
  await tool_ctx.info(f"Processing {tool_call_count} tool calls")
452
452
 
453
+ # Track which tool calls we've processed to ensure all get results
454
+ tool_results_to_add = []
455
+
453
456
  for tool_call in message.tool_calls:
454
457
  total_tool_use_count += 1
455
458
  function_name = tool_call.function.name
@@ -542,8 +545,8 @@ AGENT RESPONSES:
542
545
  await tool_ctx.info(
543
546
  f"tool {function_name} run with args {function_args} and return {tool_result[: min(100, len(tool_result))]}"
544
547
  )
545
- # Add the tool result to messages
546
- messages.append(
548
+ # Add the tool result to the list
549
+ tool_results_to_add.append(
547
550
  {
548
551
  "role": "tool",
549
552
  "tool_call_id": tool_call.id,
@@ -552,6 +555,9 @@ AGENT RESPONSES:
552
555
  }
553
556
  )
554
557
 
558
+ # Add all tool results to messages atomically
559
+ messages.extend(tool_results_to_add)
560
+
555
561
  # Log progress
556
562
  await tool_ctx.info(f"Processed {len(message.tool_calls)} tool calls. Total: {total_tool_use_count}")
557
563
 
@@ -559,6 +565,41 @@ AGENT RESPONSES:
559
565
  await tool_ctx.error(f"Error in model call: {str(e)}")
560
566
  # Avoid trying to JSON serialize message objects
561
567
  await tool_ctx.error(f"Message count: {len(messages)}")
568
+
569
+ # CRITICAL FIX: Ensure we add tool_result messages for any tool_use blocks that were added
570
+ # Get the last assistant message (which has the tool_calls)
571
+ last_assistant_msg = None
572
+ for msg in reversed(messages):
573
+ if msg.get("role") == "assistant" and hasattr(msg, "tool_calls"):
574
+ last_assistant_msg = msg
575
+ break
576
+
577
+ # If there are orphaned tool calls, add error results for them
578
+ if last_assistant_msg and hasattr(last_assistant_msg, "tool_calls"):
579
+ # Count how many tool results we already have after this message
580
+ tool_results_count = 0
581
+ found_assistant = False
582
+ for msg in reversed(messages):
583
+ if msg == last_assistant_msg:
584
+ found_assistant = True
585
+ break
586
+ if found_assistant and msg.get("role") == "tool":
587
+ tool_results_count += 1
588
+
589
+ # Add error results for any missing tool calls
590
+ expected_results = len(last_assistant_msg.tool_calls)
591
+ if tool_results_count < expected_results:
592
+ for i in range(tool_results_count, expected_results):
593
+ tool_call = last_assistant_msg.tool_calls[i]
594
+ messages.append(
595
+ {
596
+ "role": "tool",
597
+ "tool_call_id": tool_call.id,
598
+ "name": tool_call.function.name,
599
+ "content": f"Error: Tool execution interrupted - {str(e)}",
600
+ }
601
+ )
602
+
562
603
  return f"Error in agent execution: {str(e)}"
563
604
 
564
605
  # If we've reached the limit, add a warning and get final response
@@ -128,47 +128,67 @@ class MCPToolTimeoutManager:
128
128
 
129
129
  def with_auto_timeout(tool_name: str, timeout_manager: Optional[MCPToolTimeoutManager] = None):
130
130
  """Decorator to add automatic timeout and backgrounding to MCP tools.
131
-
131
+
132
132
  Args:
133
133
  tool_name: Name of the tool (for logging and process tracking)
134
134
  timeout_manager: Optional timeout manager instance
135
-
135
+
136
136
  Returns:
137
137
  Decorator function
138
138
  """
139
139
  if timeout_manager is None:
140
140
  timeout_manager = MCPToolTimeoutManager()
141
-
141
+
142
142
  def decorator(func: Callable[..., Awaitable[Any]]) -> Callable[..., Awaitable[Any]]:
143
143
  @functools.wraps(func)
144
- async def wrapper(ctx: MCPContext, **params: Any) -> Any:
144
+ async def wrapper(*args: Any, **params: Any) -> Any:
145
+ # Handle both method calls (with self) and function calls
146
+ # For methods: args = (self, ctx), For functions: args = (ctx,)
147
+ if len(args) >= 2:
148
+ # Method call: self, ctx, **params
149
+ self_or_ctx = args[0]
150
+ ctx = args[1]
151
+ call_func = lambda: func(self_or_ctx, ctx, **params)
152
+ elif len(args) == 1:
153
+ # Function call: ctx, **params
154
+ ctx = args[0]
155
+ call_func = lambda: func(ctx, **params)
156
+ else:
157
+ raise TypeError(f"Expected at least 1 argument (ctx), got {len(args)}")
158
+
145
159
  # Fast path for tests - skip timeout logic
146
160
  if os.getenv("HANZO_MCP_FAST_TESTS") == "1":
147
- return await func(ctx, **params)
148
-
161
+ return await call_func()
162
+
149
163
  # Get tool-specific timeout
150
164
  tool_timeout = timeout_manager._get_timeout_for_tool(tool_name)
151
-
165
+
152
166
  # Create task for the tool execution
153
- tool_task = asyncio.create_task(func(ctx, **params))
154
-
167
+ tool_task = asyncio.create_task(call_func())
168
+
155
169
  try:
156
170
  # Wait for completion with timeout
157
171
  result = await asyncio.wait_for(tool_task, timeout=tool_timeout)
158
172
  return result
159
-
173
+
160
174
  except asyncio.TimeoutError:
161
175
  # Tool timed out - background it
162
176
  process_id = f"{tool_name}_{uuid.uuid4().hex[:8]}"
163
177
  log_file = timeout_manager.process_manager.create_log_file(process_id)
164
-
165
- # Start background execution
178
+
179
+ # Start background execution (need to reconstruct the call)
180
+ async def background_call():
181
+ if len(args) >= 2:
182
+ return await func(args[0], ctx, **params)
183
+ else:
184
+ return await func(ctx, **params)
185
+
166
186
  asyncio.create_task(
167
187
  timeout_manager._background_tool_execution(
168
- func, tool_name, ctx, process_id, log_file, **params
188
+ background_call, tool_name, ctx, process_id, log_file, **params
169
189
  )
170
190
  )
171
-
191
+
172
192
  # Return backgrounding message
173
193
  timeout_formatted = format_timeout(tool_timeout)
174
194
  return (
@@ -179,7 +199,7 @@ def with_auto_timeout(tool_name: str, timeout_manager: Optional[MCPToolTimeoutMa
179
199
  f"Use 'process --action kill --id {process_id}' to cancel\\n\\n"
180
200
  f"The {tool_name} operation is continuing in the background..."
181
201
  )
182
-
202
+
183
203
  return wrapper
184
204
  return decorator
185
205
 
@@ -114,7 +114,7 @@ Searches code structure intelligently, understanding syntax and providing semant
114
114
  Tool result
115
115
  """
116
116
  tool_ctx = self.create_tool_context(ctx)
117
- self.set_tool_context_info(tool_ctx)
117
+ await self.set_tool_context_info(tool_ctx)
118
118
 
119
119
  # Extract parameters
120
120
  pattern: Pattern = params["pattern"]
@@ -104,10 +104,10 @@ class FilesystemBaseTool(FileSystemTool, ABC):
104
104
  tool_ctx = create_tool_context(ctx)
105
105
  return tool_ctx
106
106
 
107
- def set_tool_context_info(self, tool_ctx: ToolContext) -> None:
107
+ async def set_tool_context_info(self, tool_ctx: ToolContext) -> None:
108
108
  """Set the tool info on the context.
109
109
 
110
110
  Args:
111
111
  tool_ctx: Tool context
112
112
  """
113
- tool_ctx.set_tool_info(self.name)
113
+ await tool_ctx.set_tool_info(self.name)
@@ -108,7 +108,7 @@ Usage:
108
108
  Tool result
109
109
  """
110
110
  tool_ctx = self.create_tool_context(ctx)
111
- self.set_tool_context_info(tool_ctx)
111
+ await self.set_tool_context_info(tool_ctx)
112
112
 
113
113
  # Extract parameters
114
114
  file_path: FilePath = params["file_path"]
@@ -152,7 +152,7 @@ If you want to create a new file, use:
152
152
  Tool result
153
153
  """
154
154
  tool_ctx = self.create_tool_context(ctx)
155
- self.set_tool_context_info(tool_ctx)
155
+ await self.set_tool_context_info(tool_ctx)
156
156
 
157
157
  # Extract parameters
158
158
  file_path: FilePath = params["file_path"]
@@ -94,8 +94,6 @@ Usage:
94
94
 
95
95
  @override
96
96
  @auto_timeout("read")
97
-
98
-
99
97
  async def call(
100
98
  self,
101
99
  ctx: MCPContext,
@@ -111,7 +109,7 @@ Usage:
111
109
  Tool result
112
110
  """
113
111
  tool_ctx = self.create_tool_context(ctx)
114
- self.set_tool_context_info(tool_ctx)
112
+ await self.set_tool_context_info(tool_ctx)
115
113
 
116
114
  # Extract parameters
117
115
  file_path = params.get("file_path")
@@ -94,7 +94,7 @@ understand project-specific requirements and preferences."""
94
94
  Tool result
95
95
  """
96
96
  tool_ctx = self.create_tool_context(ctx)
97
- self.set_tool_context_info(tool_ctx)
97
+ await self.set_tool_context_info(tool_ctx)
98
98
 
99
99
  # Extract parameters
100
100
  search_path = params.get("path", ".")
@@ -138,7 +138,7 @@ Finds code structures (functions, classes, methods) with full context."""
138
138
  ) -> str:
139
139
  """Execute symbols operation."""
140
140
  tool_ctx = self.create_tool_context(ctx)
141
- self.set_tool_context_info(tool_ctx)
141
+ await self.set_tool_context_info(tool_ctx)
142
142
 
143
143
  # Extract action
144
144
  action = params.get("action", "search")
@@ -92,7 +92,7 @@ Usage:
92
92
  Tool result
93
93
  """
94
94
  tool_ctx = self.create_tool_context(ctx)
95
- self.set_tool_context_info(tool_ctx)
95
+ await self.set_tool_context_info(tool_ctx)
96
96
 
97
97
  # Extract parameters
98
98
  file_path: FilePath = params["file_path"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hanzo-mcp
3
- Version: 0.9.1
3
+ Version: 0.9.3
4
4
  Summary: The Zen of Hanzo MCP: One server to rule them all. The ultimate MCP that orchestrates all others.
5
5
  Author-email: Hanzo Industries Inc <dev@hanzo.ai>
6
6
  License: MIT
@@ -29,7 +29,7 @@ hanzo_mcp/tools/__init__.py,sha256=RZVr_s1Jnc1cCGcDU2FYKtPqZrTWa-ME9umPixl2YaU,1
29
29
  hanzo_mcp/tools/agent/__init__.py,sha256=K5fWO3MSpMoTHiP38qvZJ9VhOQQlFwSgIPI9fRWtIX4,4879
30
30
  hanzo_mcp/tools/agent/agent.py,sha256=FeWBHGkexpp50Ya7pA8APoHK4ZchDhIDh7eWEX_axDA,13038
31
31
  hanzo_mcp/tools/agent/agent_tool.py,sha256=ysNrkoEd4L2t32f0yS9sa7xFS9cDN6XzzQh2d2v3yfI,16801
32
- hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py,sha256=m86qZC4FmNvRckKXcQlpw6N2hmQsUduzyizhenDG5Ps,26228
32
+ hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py,sha256=k-GoD6JS6GvPAJu4PPQrWy6VQVdWXGa2P1eB9LfBT9k,28353
33
33
  hanzo_mcp/tools/agent/clarification_protocol.py,sha256=QYJTmDSJVRDyZMow80TxWmnJurxuLo1MaIFge8t_Yvk,8041
34
34
  hanzo_mcp/tools/agent/clarification_tool.py,sha256=sye5Y7F8IOaDNh3ZHmcSDGPBJog9-ZJdutV2hGHc1vQ,2674
35
35
  hanzo_mcp/tools/agent/claude_cli_tool.py,sha256=55Wc0LKgYCtDKQ02NXOYPMhx-sW7fL_NSCx0upsvvb4,3812
@@ -52,7 +52,7 @@ hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py,sha256=Qx4GecLtIUFSCeBHjkdcKEM
52
52
  hanzo_mcp/tools/agent/tool_adapter.py,sha256=rLItgdKvvfzJL4chNIrNK_I5kSCm6ocmi83RQm93NgA,3191
53
53
  hanzo_mcp/tools/agent/unified_cli_tools.py,sha256=Cqi39TcT-88wZtlgOocsdE4HAD0xJtuAXjpnd_WwdkE,8230
54
54
  hanzo_mcp/tools/common/__init__.py,sha256=2gXIERXM7sALINWfDBbH_khzBRatvwQSWgpAvKlfy4o,1283
55
- hanzo_mcp/tools/common/auto_timeout.py,sha256=zF7UrB-5ybfMZlkdCpfX7SrElIYIw8WJQLQahgOro6o,8203
55
+ hanzo_mcp/tools/common/auto_timeout.py,sha256=KJ7w_MLcIgwoPphM2Q3gSNG83nybracxsmEMaUGAZII,8980
56
56
  hanzo_mcp/tools/common/base.py,sha256=pI3uoXFDtjUKgCBXwcXe3coMBBcp9xfpxi_XhQKciUY,5964
57
57
  hanzo_mcp/tools/common/batch_tool.py,sha256=l1QXZ2A8qLBH021jpADIEpQbuNOjzCvNCdvIqxCGAHw,15788
58
58
  hanzo_mcp/tools/common/config_tool.py,sha256=fVh__RYg_FEU1kA0a2U3AeBJ1DEG_GWpA3sbD00D7QQ,15978
@@ -102,27 +102,27 @@ hanzo_mcp/tools/editor/neovim_edit.py,sha256=dEzrKXuZKLK16hMieywN0IycvltktzpEhNV
102
102
  hanzo_mcp/tools/editor/neovim_session.py,sha256=r9V9AEQu7xotGjhOdEIQvUKB5u8Hvel-QdMDeSeitTk,11759
103
103
  hanzo_mcp/tools/filesystem/__init__.py,sha256=bj4xfqzZuABKzGi1G0qgk5IIDsFlOa6k2nQLYLc28dc,8532
104
104
  hanzo_mcp/tools/filesystem/ast_multi_edit.py,sha256=kxJL-Nicav9Tn6BcDPBFKGq67XLWhtYgF1NV7UlhzK4,22180
105
- hanzo_mcp/tools/filesystem/ast_tool.py,sha256=KxT8XANBnlBvtNVZG00DU-CXkdQwzYdraJ3kYJfOr_w,7372
106
- hanzo_mcp/tools/filesystem/base.py,sha256=2lJLa4vmSGZz57v8KKVMI9_oLF4_-NYiYZVnm-GsyoQ,3762
105
+ hanzo_mcp/tools/filesystem/ast_tool.py,sha256=ybm8R55-TtK6t8Y7CFUpqnqXeQ6eIs42M0A2OEWE4PY,7378
106
+ hanzo_mcp/tools/filesystem/base.py,sha256=qKrN4VdO-oTWOGxpA7_Iu9UubHqIanlZjn9QRnHQBVA,3774
107
107
  hanzo_mcp/tools/filesystem/batch_search.py,sha256=8r4eDqNaYZzCvYUFV6YEsQ9KcIRP9N1Vsa96XHw6m1c,32830
108
108
  hanzo_mcp/tools/filesystem/content_replace.py,sha256=EA3vuIQp7St5r-ld-r8bnFfikvVDmdTbghBDl1rXTT0,9884
109
109
  hanzo_mcp/tools/filesystem/diff.py,sha256=bhhTtGU9tSZcigd53PBRBCzqmlAngMWlkWxK9j7TX0w,7635
110
110
  hanzo_mcp/tools/filesystem/directory_tree.py,sha256=xfr8Nxl5Na6W8kb2ktBuuE1S10FwQf2ZGoCCBLydvsk,10866
111
111
  hanzo_mcp/tools/filesystem/directory_tree_paginated.py,sha256=2ArA_Uaa76WfM-O8nx5dqD2uYdsImIJ_Ols57QzpouI,11599
112
- hanzo_mcp/tools/filesystem/edit.py,sha256=9VA0svYhozVwFKw5LJInPjgIa-bhKT5h5yS80fb0Efo,10505
112
+ hanzo_mcp/tools/filesystem/edit.py,sha256=s2NKTG-vDrk1iyWJqwns7iXyM6pMpcm_D02-SYj4OEc,10511
113
113
  hanzo_mcp/tools/filesystem/find.py,sha256=EmfhYOhvKgdyk5pxOXymFf-bpXtSMLSxYetg4-D5N4E,15663
114
114
  hanzo_mcp/tools/filesystem/find_files.py,sha256=goo40H1w4F3Re5BwZdn5b8rft7Mxz8WM1pH_ZA1YgsA,10838
115
115
  hanzo_mcp/tools/filesystem/git_search.py,sha256=FQbC-vLf7KNKL83gCOosFw7xbxO_mG6GE_bjEqrGljs,16485
116
116
  hanzo_mcp/tools/filesystem/grep.py,sha256=K20loRoIZOKSaAO3Kcg2mCm5D2jyZCiIqmWQ71EZ3gE,17042
117
- hanzo_mcp/tools/filesystem/multi_edit.py,sha256=Kll71UaLGFL5HRySlV6mSQafpS4UoeSEuZxpcgqY4k8,14042
118
- hanzo_mcp/tools/filesystem/read.py,sha256=5OL4imSwTEs7jSQOo3OCjmlou_E8qdHBwxU6ikqPcqA,9386
119
- hanzo_mcp/tools/filesystem/rules_tool.py,sha256=gUkzq78_caNd8hytiUSAMv7Q_CzGlbng04laffx9XmM,8382
117
+ hanzo_mcp/tools/filesystem/multi_edit.py,sha256=vZZCJ5tE_QCE-8WaY6i7af8hyPatdTCdhOHwbw-3rsQ,14048
118
+ hanzo_mcp/tools/filesystem/read.py,sha256=oPSYXFWQf5R6Ch7v36yUliFf-HW7yjUv0hSWxkN2jUE,9390
119
+ hanzo_mcp/tools/filesystem/rules_tool.py,sha256=JPGubQLiGvrrvQqscPQOmSNk6A3WH63iTHV6ldU6_1g,8388
120
120
  hanzo_mcp/tools/filesystem/search_tool.py,sha256=LFsu7OpTODUN2QnVzokN5y1obSrdsrFzclsNwkh2hjw,25833
121
- hanzo_mcp/tools/filesystem/symbols_tool.py,sha256=oYKcw-Y1BvPXGck0bA0kiXrl0bM5y9SVCNDRh_jCn5Y,15958
121
+ hanzo_mcp/tools/filesystem/symbols_tool.py,sha256=ihZQ7-5X-ubPWXy8p13krFEuU-bJmyzBV8_cf556Deg,15964
122
122
  hanzo_mcp/tools/filesystem/tree.py,sha256=fM6dd7yG45TKNzFqHdM-Z0UzX-PoR2KqBxhCV4AnPoI,7281
123
123
  hanzo_mcp/tools/filesystem/unix_aliases.py,sha256=N4vy9SXtecCNtggv2zjFk8CmHvhuqTvR6Ha_KT1UE_g,3031
124
124
  hanzo_mcp/tools/filesystem/watch.py,sha256=k9BxZfHk7WV2KcE48NwnPnPvXsnb0GG6xb3nWlGCJ8g,6950
125
- hanzo_mcp/tools/filesystem/write.py,sha256=FYFhfTkJ_523DCWRhb58_X_bfWFObVcTtFj30OvGTsg,4777
125
+ hanzo_mcp/tools/filesystem/write.py,sha256=_i5ut7x23p1UoXUQdvlyVlTO18gmedrHE8PVvagEzLc,4783
126
126
  hanzo_mcp/tools/jupyter/__init__.py,sha256=-7uAomIx8tboZ9gcal7t2MRvgZ9A3cltIYA4perfZVE,2646
127
127
  hanzo_mcp/tools/jupyter/base.py,sha256=4O8iMBNqlrCNFEbsihpHyX_nyUqLV7w3AWb_0kcKD14,9788
128
128
  hanzo_mcp/tools/jupyter/jupyter.py,sha256=HTcOtuL-I-t4k-luz3_iSPOe6aViKyGlIoK21I-YQmA,14933
@@ -188,8 +188,8 @@ hanzo_mcp/tools/vector/project_manager.py,sha256=usxOldFajm7UN-74yN7Qa5Xw7Or6EWm
188
188
  hanzo_mcp/tools/vector/vector.py,sha256=KMV1UHH6kCgTrglyLSfepbDDgOo6U3QMXpsCBQyq5to,9963
189
189
  hanzo_mcp/tools/vector/vector_index.py,sha256=Vtdx69DwtsCaokleBhUpaFhP9AQ6Lq7C6xsDbZjPqNY,4274
190
190
  hanzo_mcp/tools/vector/vector_search.py,sha256=bRy-Dcm0SsJD7eV99U_XMdSpenh5WAPimqXofrTNIwE,9402
191
- hanzo_mcp-0.9.1.dist-info/METADATA,sha256=n-cN_4WzeuxbLbIZvzQ8HAOyc0CEBhwV2yonmjic2vs,8974
192
- hanzo_mcp-0.9.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
193
- hanzo_mcp-0.9.1.dist-info/entry_points.txt,sha256=ML30pedHV5wjthfztzMMz3uYhNdR_6inzYY5pSqNME4,142
194
- hanzo_mcp-0.9.1.dist-info/top_level.txt,sha256=eGFANatA0MHWiVlpS56fTYRIShtibrSom1uXI6XU0GU,10
195
- hanzo_mcp-0.9.1.dist-info/RECORD,,
191
+ hanzo_mcp-0.9.3.dist-info/METADATA,sha256=YUL8XY22uipXy32CewjqmECQVEc411pKoAE9lWvqWdk,8974
192
+ hanzo_mcp-0.9.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
193
+ hanzo_mcp-0.9.3.dist-info/entry_points.txt,sha256=ML30pedHV5wjthfztzMMz3uYhNdR_6inzYY5pSqNME4,142
194
+ hanzo_mcp-0.9.3.dist-info/top_level.txt,sha256=eGFANatA0MHWiVlpS56fTYRIShtibrSom1uXI6XU0GU,10
195
+ hanzo_mcp-0.9.3.dist-info/RECORD,,