diff --git a/letta/services/mcp/base_client.py b/letta/services/mcp/base_client.py index 5e444e04..28f541ca 100644 --- a/letta/services/mcp/base_client.py +++ b/letta/services/mcp/base_client.py @@ -109,9 +109,21 @@ class AsyncBaseMCPClient: logger.error("MCPClient has not been initialized") raise RuntimeError("MCPClient has not been initialized") - # TODO: still hitting some async errors for voice agents, need to fix async def cleanup(self): - await self.exit_stack.aclose() + """Clean up resources used by the MCP client. + + This method handles ExceptionGroup errors that can occur when closing async context managers + (e.g., from the MCP library's internal TaskGroup usage). Cleanup is a best-effort operation + and errors are logged but not re-raised to prevent masking the original exception. + """ + try: + await self.exit_stack.aclose() + except* Exception as eg: + # ExceptionGroup can be raised when closing async context managers that use TaskGroup + # Log each sub-exception at debug level since cleanup errors are expected in some cases + # (e.g., connection already closed, server unavailable) + for exc in eg.exceptions: + logger.debug(f"MCP client cleanup error (suppressed): {type(exc).__name__}: {exc}") def to_sync_client(self): raise NotImplementedError("Subclasses must implement to_sync_client") diff --git a/letta/services/mcp_manager.py b/letta/services/mcp_manager.py index db740a5e..a4708484 100644 --- a/letta/services/mcp_manager.py +++ b/letta/services/mcp_manager.py @@ -93,12 +93,7 @@ class MCPManager: raise e finally: if mcp_client: - try: - await mcp_client.cleanup() - except* Exception as eg: - for e in eg.exceptions: - logger.warning(f"Error listing tools for MCP server {mcp_server_name}: {e}") - raise e + await mcp_client.cleanup() @enforce_types async def execute_mcp_server_tool( diff --git a/letta/services/mcp_server_manager.py b/letta/services/mcp_server_manager.py index b5fd06d1..6c71dedb 100644 --- a/letta/services/mcp_server_manager.py +++ b/letta/services/mcp_server_manager.py @@ -186,11 +186,7 @@ class MCPServerManager: raise e finally: if mcp_client: - try: - await mcp_client.cleanup() - except Exception as e: - logger.warning(f"Error listing tools for MCP server {mcp_server_id}: {e}") - raise e + await mcp_client.cleanup() @enforce_types async def execute_mcp_server_tool(