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.
This commit is contained in:
@@ -212,15 +212,36 @@ class FunctionToolManager:
|
||||
open(mcp_json_file, encoding="utf-8"),
|
||||
)["mcpServers"]
|
||||
|
||||
# 收集所有初始化任务的 Future
|
||||
init_futures: dict[str, asyncio.Future] = {}
|
||||
|
||||
for name in mcp_server_json_obj:
|
||||
cfg = mcp_server_json_obj[name]
|
||||
if cfg.get("active", True):
|
||||
event = asyncio.Event()
|
||||
ready_future = asyncio.Future()
|
||||
init_futures[name] = ready_future
|
||||
asyncio.create_task(
|
||||
self._init_mcp_client_task_wrapper(name, cfg, event),
|
||||
self._init_mcp_client_task_wrapper(name, cfg, event, ready_future),
|
||||
)
|
||||
self.mcp_client_event[name] = event
|
||||
|
||||
# 等待所有 MCP 客户端初始化完成(或失败)
|
||||
if init_futures:
|
||||
logger.info(f"等待 {len(init_futures)} 个 MCP 服务初始化...")
|
||||
results = await asyncio.gather(
|
||||
*init_futures.values(), return_exceptions=True
|
||||
)
|
||||
|
||||
success_count = 0
|
||||
for name, result in zip(init_futures.keys(), results):
|
||||
if isinstance(result, Exception):
|
||||
logger.error(f"MCP 服务 {name} 初始化失败: {result}")
|
||||
else:
|
||||
success_count += 1
|
||||
|
||||
logger.info(f"MCP 服务初始化完成: {success_count}/{len(init_futures)} 成功")
|
||||
|
||||
async def _init_mcp_client_task_wrapper(
|
||||
self,
|
||||
name: str,
|
||||
|
||||
@@ -274,8 +274,8 @@ class ProviderManager:
|
||||
if not self.curr_tts_provider_inst and self.tts_provider_insts:
|
||||
self.curr_tts_provider_inst = self.tts_provider_insts[0]
|
||||
|
||||
# 初始化 MCP Client 连接
|
||||
asyncio.create_task(self.llm_tools.init_mcp_clients(), name="init_mcp_clients")
|
||||
# 初始化 MCP Client 连接(等待完成以确保工具可用)
|
||||
await self.llm_tools.init_mcp_clients()
|
||||
|
||||
def dynamic_import_provider(self, type: str):
|
||||
"""动态导入提供商适配器模块
|
||||
|
||||
Reference in New Issue
Block a user