Skip to content

Commit 0de7ae8

Browse files
committed
fix: resolve MCP tools race condition causing 'completion 无法解析' error
- Wait for MCP client initialization to complete before accepting requests - Add Future-based synchronization in init_mcp_clients() - Prevent tool_calls from being rejected due to empty func_list - Improve error logging for MCP initialization failures Fixes race condition where AI attempts to call MCP tools before they are registered, resulting in 'API 返回的 completion 无法解析' exceptions. The issue occurred because: 1. MCP clients were initialized asynchronously without waiting 2. System accepted user requests immediately after startup 3. AI received empty tool list and attempted to call non-existent tools 4. Tool matching failed, causing parsing errors This fix ensures all MCP tools are loaded before the system processes any requests that might use them.
1 parent 42e84af commit 0de7ae8

2 files changed

Lines changed: 24 additions & 3 deletions

File tree

astrbot/core/provider/func_tool_manager.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,15 +212,36 @@ async def init_mcp_clients(self) -> None:
212212
open(mcp_json_file, encoding="utf-8"),
213213
)["mcpServers"]
214214

215+
# 收集所有初始化任务的 Future
216+
init_futures: dict[str, asyncio.Future] = {}
217+
215218
for name in mcp_server_json_obj:
216219
cfg = mcp_server_json_obj[name]
217220
if cfg.get("active", True):
218221
event = asyncio.Event()
222+
ready_future = asyncio.Future()
223+
init_futures[name] = ready_future
219224
asyncio.create_task(
220-
self._init_mcp_client_task_wrapper(name, cfg, event),
225+
self._init_mcp_client_task_wrapper(name, cfg, event, ready_future),
221226
)
222227
self.mcp_client_event[name] = event
223228

229+
# 等待所有 MCP 客户端初始化完成(或失败)
230+
if init_futures:
231+
logger.info(f"等待 {len(init_futures)} 个 MCP 服务初始化...")
232+
results = await asyncio.gather(
233+
*init_futures.values(), return_exceptions=True
234+
)
235+
236+
success_count = 0
237+
for name, result in zip(init_futures.keys(), results):
238+
if isinstance(result, Exception):
239+
logger.error(f"MCP 服务 {name} 初始化失败: {result}")
240+
else:
241+
success_count += 1
242+
243+
logger.info(f"MCP 服务初始化完成: {success_count}/{len(init_futures)} 成功")
244+
224245
async def _init_mcp_client_task_wrapper(
225246
self,
226247
name: str,

astrbot/core/provider/manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,8 @@ async def initialize(self):
274274
if not self.curr_tts_provider_inst and self.tts_provider_insts:
275275
self.curr_tts_provider_inst = self.tts_provider_insts[0]
276276

277-
# 初始化 MCP Client 连接
278-
asyncio.create_task(self.llm_tools.init_mcp_clients(), name="init_mcp_clients")
277+
# 初始化 MCP Client 连接(等待完成以确保工具可用)
278+
await self.llm_tools.init_mcp_clients()
279279

280280
def dynamic_import_provider(self, type: str):
281281
"""动态导入提供商适配器模块

0 commit comments

Comments
 (0)