Fix: Add connect_timeout parameter to get_mcp_tools method

- Add Optional[int] connect_timeout parameter with default value of 30 seconds
- Pass connect_timeout to MCPServerAdapter constructor to prevent timeouts
- Add comprehensive tests for timeout functionality
- Maintain backward compatibility with existing code
- Fixes issue #3326 where get_mcp_tools hits timeout with multiple MCP servers

Co-Authored-By: João <joao@crewai.com>
This commit is contained in:
Devin AI
2025-08-15 18:38:10 +00:00
parent 992e093610
commit 7c70cb493c
2 changed files with 34 additions and 4 deletions

View File

@@ -1,7 +1,7 @@
import inspect import inspect
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Dict, TypeVar, cast, List from typing import Any, Callable, Dict, TypeVar, cast, List, Optional
from crewai.tools import BaseTool from crewai.tools import BaseTool
import yaml import yaml
@@ -86,7 +86,7 @@ def CrewBase(cls: T) -> T:
import types import types
return types.MethodType(_close_mcp_server, self) return types.MethodType(_close_mcp_server, self)
def get_mcp_tools(self, *tool_names: list[str]) -> List[BaseTool]: def get_mcp_tools(self, *tool_names: list[str], connect_timeout: Optional[int] = 30) -> List[BaseTool]:
if not self.mcp_server_params: if not self.mcp_server_params:
return [] return []
@@ -94,7 +94,7 @@ def CrewBase(cls: T) -> T:
adapter = getattr(self, '_mcp_server_adapter', None) adapter = getattr(self, '_mcp_server_adapter', None)
if not adapter: if not adapter:
self._mcp_server_adapter = MCPServerAdapter(self.mcp_server_params) self._mcp_server_adapter = MCPServerAdapter(self.mcp_server_params, connect_timeout=connect_timeout)
return self._mcp_server_adapter.tools.filter_by_names(tool_names or None) return self._mcp_server_adapter.tools.filter_by_names(tool_names or None)

View File

@@ -270,4 +270,34 @@ def test_internal_crew_with_mcp():
assert crew.reporting_analyst().tools == [simple_tool, another_simple_tool] assert crew.reporting_analyst().tools == [simple_tool, another_simple_tool]
assert crew.researcher().tools == [simple_tool] assert crew.researcher().tools == [simple_tool]
adapter_mock.assert_called_once_with({"host": "localhost", "port": 8000}) adapter_mock.assert_called_once_with({"host": "localhost", "port": 8000}, connect_timeout=30)
def test_internal_crew_with_mcp_connect_timeout():
from crewai_tools import MCPServerAdapter
from crewai_tools.adapters.mcp_adapter import ToolCollection
@CrewBase
class TestCrewWithMCP:
mcp_server_params = {"host": "localhost", "port": 8000}
agents_config = None
tasks_config = None
mock = Mock(spec=MCPServerAdapter)
mock.tools = ToolCollection([simple_tool, another_simple_tool])
with patch("crewai_tools.MCPServerAdapter", return_value=mock) as adapter_mock:
crew1 = TestCrewWithMCP()
crew1.get_mcp_tools()
adapter_mock.assert_called_with({"host": "localhost", "port": 8000}, connect_timeout=30)
adapter_mock.reset_mock()
crew2 = TestCrewWithMCP()
crew2.get_mcp_tools(connect_timeout=60)
adapter_mock.assert_called_with({"host": "localhost", "port": 8000}, connect_timeout=60)
adapter_mock.reset_mock()
crew3 = TestCrewWithMCP()
crew3.get_mcp_tools("simple_tool", connect_timeout=45)
adapter_mock.assert_called_with({"host": "localhost", "port": 8000}, connect_timeout=45)