feat(mcp): 增强MCP服务器异常处理和错误描述
- 添加_iter_leaf_exceptions函数用于处理嵌套异常组 - 实现_describe_mcp_exception函数提供详细的MCP服务器错误信息 - 改进connect_mcp_servers中的错误处理,使用更精确的错误描述 - 在日志记录中包含更具体的错误详情 feat(outlook): 优化Outlook集成异常处理 - 添加_iter_leaf_exceptions函数用于异常处理 - 创建_coerce_outlook_mcp_exception函数统一异常转换 - 改进_call_outlook_mcp_tool中的异常捕获和处理 - 对认证令牌获取和MCP调用添加专门的超时和HTTP错误处理 feat(web): 改进Web会话定时任务结果记录 - 实现_record_cron_result_for_web_session函数 - 为Web模式下的独立定时任务执行结果提供持久化存储 - 支持将定时任务响应消息添加到目标会话中 - 确保前端可以显示定时任务执行结果
This commit is contained in:
@ -19,6 +19,37 @@ from nanobot.agent.tools.base import Tool
|
||||
from nanobot.agent.tools.registry import ToolRegistry
|
||||
|
||||
|
||||
def _iter_leaf_exceptions(exc: BaseException) -> list[BaseException]:
|
||||
if isinstance(exc, BaseExceptionGroup):
|
||||
leaves: list[BaseException] = []
|
||||
for sub_exc in exc.exceptions:
|
||||
leaves.extend(_iter_leaf_exceptions(sub_exc))
|
||||
return leaves
|
||||
return [exc]
|
||||
|
||||
|
||||
def _describe_mcp_exception(exc: BaseException, *, server_name: str, url: str | None = None) -> str:
|
||||
leaves = _iter_leaf_exceptions(exc)
|
||||
target = f" ({url})" if url else ""
|
||||
|
||||
for leaf in leaves:
|
||||
if isinstance(leaf, httpx.TimeoutException):
|
||||
return f"MCP server '{server_name}' timed out while waiting for a response{target}"
|
||||
if isinstance(leaf, httpx.ConnectError):
|
||||
return f"MCP server '{server_name}' is unreachable{target}"
|
||||
if isinstance(leaf, httpx.HTTPStatusError):
|
||||
return f"MCP server '{server_name}' returned HTTP {leaf.response.status_code}{target}"
|
||||
if isinstance(leaf, httpx.HTTPError):
|
||||
detail = str(leaf).strip() or leaf.__class__.__name__
|
||||
return f"MCP server '{server_name}' HTTP error{target}: {detail}"
|
||||
|
||||
detail_source = leaves[0] if leaves else exc
|
||||
detail = str(detail_source).strip() or detail_source.__class__.__name__
|
||||
if isinstance(exc, BaseExceptionGroup):
|
||||
return f"MCP server '{server_name}' failed: {detail_source.__class__.__name__}: {detail}"
|
||||
return detail
|
||||
|
||||
|
||||
class MCPToolWrapper(Tool):
|
||||
"""把单个 MCP server tool 包装成 nanobot Tool。"""
|
||||
|
||||
@ -340,7 +371,12 @@ async def connect_mcp_servers(
|
||||
)
|
||||
except Exception as e:
|
||||
# 单个 server 失败不影响其他 server 继续连;错误写进 report 供 UI 展示。
|
||||
error_detail = _describe_mcp_exception(
|
||||
e,
|
||||
server_name=name,
|
||||
url=str(getattr(cfg, "url", "") or "").strip() or None,
|
||||
)
|
||||
report[name]["status"] = "error"
|
||||
report[name]["last_error"] = str(e)
|
||||
logger.error("MCP server '{}': failed to connect: {}", name, e)
|
||||
report[name]["last_error"] = error_detail
|
||||
logger.error("MCP server '{}': failed to connect: {}", name, error_detail)
|
||||
return report
|
||||
|
||||
Reference in New Issue
Block a user