mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-18 20:14:44 +08:00
fix(config): Add support for MCP server configuration parameters (#812)
* fix(config): Add support for MCP server configuration parameters * refact: rename the sse_readtimeout to sse_read_timeout * update the code with review comments * update the MCP document for the latest change
This commit is contained in:
@@ -376,13 +376,41 @@ class TestMCPEndpoint:
|
||||
request_data = {
|
||||
"transport": "stdio",
|
||||
"command": "test_command",
|
||||
"timeout_seconds": 600,
|
||||
"timeout_seconds": 60,
|
||||
}
|
||||
|
||||
response = client.post("/api/mcp/server/metadata", json=request_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
mock_load_tools.assert_called_once()
|
||||
# Verify timeout_seconds is passed to load_mcp_tools
|
||||
call_kwargs = mock_load_tools.call_args[1]
|
||||
assert call_kwargs["timeout_seconds"] == 60
|
||||
|
||||
@patch("src.server.app.load_mcp_tools")
|
||||
@patch.dict(
|
||||
os.environ,
|
||||
{"ENABLE_MCP_SERVER_CONFIGURATION": "true"},
|
||||
)
|
||||
def test_mcp_server_metadata_with_sse_read_timeout(self, mock_load_tools, client):
|
||||
"""Test that sse_read_timeout is passed to load_mcp_tools."""
|
||||
mock_load_tools.return_value = []
|
||||
|
||||
request_data = {
|
||||
"transport": "sse",
|
||||
"url": "http://localhost:3000/sse",
|
||||
"timeout_seconds": 30,
|
||||
"sse_read_timeout": 15,
|
||||
}
|
||||
|
||||
response = client.post("/api/mcp/server/metadata", json=request_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
mock_load_tools.assert_called_once()
|
||||
# Verify both timeout_seconds and sse_read_timeout are passed
|
||||
call_kwargs = mock_load_tools.call_args[1]
|
||||
assert call_kwargs["timeout_seconds"] == 30
|
||||
assert call_kwargs["sse_read_timeout"] == 15
|
||||
|
||||
@patch("src.server.app.load_mcp_tools")
|
||||
@patch.dict(
|
||||
|
||||
@@ -16,6 +16,7 @@ def test_mcp_server_metadata_request_required_fields():
|
||||
assert req.url is None
|
||||
assert req.env is None
|
||||
assert req.timeout_seconds is None
|
||||
assert req.sse_read_timeout is None
|
||||
|
||||
|
||||
def test_mcp_server_metadata_request_optional_fields():
|
||||
@@ -26,6 +27,7 @@ def test_mcp_server_metadata_request_optional_fields():
|
||||
url="http://localhost:8080",
|
||||
env={"FOO": "BAR"},
|
||||
timeout_seconds=30,
|
||||
sse_read_timeout=15,
|
||||
)
|
||||
assert req.transport == "sse"
|
||||
assert req.command == "run"
|
||||
@@ -33,6 +35,7 @@ def test_mcp_server_metadata_request_optional_fields():
|
||||
assert req.url == "http://localhost:8080"
|
||||
assert req.env == {"FOO": "BAR"}
|
||||
assert req.timeout_seconds == 30
|
||||
assert req.sse_read_timeout == 15
|
||||
|
||||
|
||||
def test_mcp_server_metadata_request_missing_transport():
|
||||
|
||||
@@ -91,6 +91,7 @@ async def test_load_mcp_tools_sse_success(mock_sse_client, mock_get_tools):
|
||||
timeout_seconds=7,
|
||||
)
|
||||
assert result == ["toolB"]
|
||||
# When sse_read_timeout is None, it should not be passed
|
||||
mock_sse_client.assert_called_once_with(
|
||||
url="http://localhost:1234",
|
||||
headers={"Authorization": "Bearer 1234567890"},
|
||||
@@ -99,6 +100,58 @@ async def test_load_mcp_tools_sse_success(mock_sse_client, mock_get_tools):
|
||||
mock_get_tools.assert_awaited_once_with(mock_client, 7)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("src.server.mcp_utils._get_tools_from_client_session", new_callable=AsyncMock)
|
||||
@patch("src.server.mcp_utils.sse_client")
|
||||
async def test_load_mcp_tools_sse_with_sse_read_timeout(mock_sse_client, mock_get_tools):
|
||||
"""Test that sse_read_timeout parameter is used when provided."""
|
||||
mock_get_tools.return_value = ["toolC"]
|
||||
mock_client = MagicMock()
|
||||
mock_sse_client.return_value = mock_client
|
||||
|
||||
result = await mcp_utils.load_mcp_tools(
|
||||
server_type="sse",
|
||||
url="http://localhost:1234",
|
||||
headers={"Authorization": "Bearer token"},
|
||||
timeout_seconds=10,
|
||||
sse_read_timeout=5,
|
||||
)
|
||||
assert result == ["toolC"]
|
||||
# Both timeout_seconds and sse_read_timeout should be passed
|
||||
mock_sse_client.assert_called_once_with(
|
||||
url="http://localhost:1234",
|
||||
headers={"Authorization": "Bearer token"},
|
||||
timeout=10,
|
||||
sse_read_timeout=5,
|
||||
)
|
||||
# But timeout_seconds should be used for the session timeout
|
||||
mock_get_tools.assert_awaited_once_with(mock_client, 10)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("src.server.mcp_utils._get_tools_from_client_session", new_callable=AsyncMock)
|
||||
@patch("src.server.mcp_utils.sse_client")
|
||||
async def test_load_mcp_tools_sse_without_sse_read_timeout(mock_sse_client, mock_get_tools):
|
||||
"""Test that timeout_seconds is used when sse_read_timeout is not provided."""
|
||||
mock_get_tools.return_value = ["toolD"]
|
||||
mock_client = MagicMock()
|
||||
mock_sse_client.return_value = mock_client
|
||||
|
||||
result = await mcp_utils.load_mcp_tools(
|
||||
server_type="sse",
|
||||
url="http://localhost:1234",
|
||||
timeout_seconds=20,
|
||||
)
|
||||
assert result == ["toolD"]
|
||||
# When sse_read_timeout is not provided, it should not be passed
|
||||
mock_sse_client.assert_called_once_with(
|
||||
url="http://localhost:1234",
|
||||
headers=None,
|
||||
timeout=20,
|
||||
)
|
||||
mock_get_tools.assert_awaited_once_with(mock_client, 20)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_mcp_tools_sse_missing_url():
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
|
||||
Reference in New Issue
Block a user