44import copy
55import json
66import os
7+ import urllib .parse
78from collections .abc import AsyncGenerator , Awaitable , Callable
89from typing import Any
910
@@ -212,59 +213,51 @@ async def init_mcp_clients(self) -> None:
212213 open (mcp_json_file , encoding = "utf-8" ),
213214 )["mcpServers" ]
214215
215- # 收集所有初始化任务的 Future
216- init_futures : dict [str , asyncio .Future ] = {}
216+ tasks : dict [str , asyncio .Task ] = {}
217217
218- for name in mcp_server_json_obj :
219- cfg = mcp_server_json_obj [name ]
218+ for name , cfg in mcp_server_json_obj .items ():
220219 if cfg .get ("active" , True ):
221220 event = asyncio .Event ()
222- ready_future = asyncio .Future ()
223- init_futures [name ] = ready_future
224- asyncio .create_task (
225- self ._init_mcp_client_task_wrapper (name , cfg , event , ready_future ),
221+ task = asyncio .create_task (
222+ self ._init_mcp_client_task_wrapper (name , cfg , event ),
226223 )
224+ tasks [name ] = task
227225 self .mcp_client_event [name ] = event
228226
229- # 等待所有 MCP 客户端初始化完成(或失败)
230- if init_futures :
231- logger .info (f"等待 { len (init_futures )} 个 MCP 服务初始化..." )
227+ if tasks :
228+ logger .info (f"等待 { len (tasks )} 个 MCP 服务初始化..." )
232229
233- try :
234- # 设置总超时时间为 20 秒,避免慢速 MCP 服务器阻塞启动过久
235- results = await asyncio .wait_for (
236- asyncio .gather (* init_futures .values (), return_exceptions = True ),
237- timeout = 20.0 ,
238- )
239- except asyncio .TimeoutError :
230+ done , pending = await asyncio .wait (tasks .values (), timeout = 20.0 )
231+
232+ if pending :
240233 logger .warning (
241234 "MCP 服务初始化超时(20秒),部分服务可能未完全加载。"
242235 "建议检查 MCP 服务器配置和网络连接。"
243236 )
244- # 即使超时也继续,已完成的服务仍然可用
245- results = []
246- for name , future in zip (init_futures .keys (), init_futures .values ()):
247- if future .done ():
248- try :
249- results .append (future .result ())
250- except Exception as e :
251- results .append (e )
252- else :
253- results .append (TimeoutError (f"MCP 服务 { name } 初始化超时" ))
237+ for task in pending :
238+ task .cancel ()
254239
255240 success_count = 0
256- failed_services = []
257- for name , result in zip (init_futures .keys (), results ):
258- if isinstance (result , Exception ):
259- logger .error (f"MCP 服务 { name } 初始化失败: { result } " )
260- # 显示配置信息以便调试
241+ failed_services : list [str ] = []
242+
243+ for name , task in tasks .items ():
244+ if task in pending :
245+ logger .error (f"MCP 服务 { name } 初始化超时" )
246+ failed_services .append (name )
247+ continue
248+
249+ exc = task .exception ()
250+ if exc is not None :
251+ logger .error (f"MCP 服务 { name } 初始化失败: { exc } " )
252+ # 仅在 debug 级别输出完整配置,避免在生产日志中泄露敏感信息
261253 cfg = mcp_server_json_obj .get (name , {})
262254 if "command" in cfg :
263- logger .error (f" 命令: { cfg ['command' ]} " )
255+ logger .debug (f" 命令: { cfg ['command' ]} " )
264256 if "args" in cfg :
265- logger .error (f" 参数: { cfg ['args' ]} " )
257+ logger .debug (f" 参数: { cfg ['args' ]} " )
266258 elif "url" in cfg :
267- logger .error (f" URL: { cfg ['url' ]} " )
259+ parsed = urllib .parse .urlparse (cfg ["url" ])
260+ logger .debug (f" 主机: { parsed .scheme } ://{ parsed .netloc } " )
268261 failed_services .append (name )
269262 else :
270263 success_count += 1
@@ -275,28 +268,24 @@ async def init_mcp_clients(self) -> None:
275268 f"请检查配置文件 mcp_server.json 和服务器可用性。"
276269 )
277270
278- logger .info (f"MCP 服务初始化完成: { success_count } /{ len (init_futures )} 成功" )
271+ logger .info (f"MCP 服务初始化完成: { success_count } /{ len (tasks )} 成功" )
279272
280273 async def _init_mcp_client_task_wrapper (
281274 self ,
282275 name : str ,
283276 cfg : dict ,
284277 event : asyncio .Event ,
285- ready_future : asyncio .Future | None = None ,
286278 ) -> None :
287279 """初始化 MCP 客户端的包装函数,用于捕获异常"""
288280 try :
289281 await self ._init_mcp_client (name , cfg )
290282 tools = await self .mcp_client_dict [name ].list_tools_and_save ()
291- if ready_future and not ready_future .done ():
292- # tell the caller we are ready
293- ready_future .set_result (tools )
283+ logger .debug (f"MCP 服务 { name } 初始化完成,工具: { tools } " )
294284 await event .wait ()
295285 logger .info (f"收到 MCP 客户端 { name } 终止信号" )
296- except Exception as e :
286+ except Exception :
297287 logger .error (f"初始化 MCP 客户端 { name } 失败" , exc_info = True )
298- if ready_future and not ready_future .done ():
299- ready_future .set_exception (e )
288+ raise
300289 finally :
301290 # 无论如何都能清理
302291 await self ._terminate_mcp_client (name )
0 commit comments