|
2 | 2 | import tempfile
|
3 | 3 | import unittest
|
4 | 4 | from pathlib import Path
|
5 |
| -from unittest.mock import MagicMock, patch |
| 5 | +from unittest.mock import AsyncMock, MagicMock, patch |
6 | 6 |
|
7 | 7 | import git
|
8 | 8 |
|
@@ -575,6 +575,7 @@ def test_new_file_edit_one_commit(self):
|
575 | 575 | fname = Path("file.txt")
|
576 | 576 |
|
577 | 577 | io = InputOutput(yes=True)
|
| 578 | + io.tool_warning = MagicMock() |
578 | 579 | coder = Coder.create(self.GPT35, "diff", io=io, fnames=[str(fname)])
|
579 | 580 |
|
580 | 581 | self.assertTrue(fname.exists())
|
@@ -1351,6 +1352,60 @@ def test_mcp_server_connection(self, mock_mcp_client):
|
1351 | 1352 | self.assertEqual(tool_responses[0]["tool_call_id"], "test_id")
|
1352 | 1353 | self.assertEqual(tool_responses[0]["content"], "Tool execution result")
|
1353 | 1354 |
|
| 1355 | + @patch("aider.coders.base_coder.experimental_mcp_client") |
| 1356 | + def test_coder_creation_with_failed_mcp_server(self, mock_mcp_client): |
| 1357 | + """Test that a coder can still be created even if an MCP server fails to initialize.""" |
| 1358 | + with GitTemporaryDirectory(): |
| 1359 | + io = InputOutput(yes=True) |
| 1360 | + io.tool_warning = MagicMock() |
| 1361 | + |
| 1362 | + # Create mock MCP servers - one working, one failing |
| 1363 | + working_server = AsyncMock() |
| 1364 | + working_server.name = "working_server" |
| 1365 | + working_server.connect = AsyncMock() |
| 1366 | + working_server.disconnect = AsyncMock() |
| 1367 | + |
| 1368 | + failing_server = AsyncMock() |
| 1369 | + failing_server.name = "failing_server" |
| 1370 | + failing_server.connect = AsyncMock() |
| 1371 | + failing_server.disconnect = AsyncMock() |
| 1372 | + |
| 1373 | + # Mock load_mcp_tools to succeed for working_server and fail for failing_server |
| 1374 | + async def mock_load_mcp_tools(session, format): |
| 1375 | + if session == await working_server.connect(): |
| 1376 | + return [{"function": {"name": "working_tool"}}] |
| 1377 | + else: |
| 1378 | + raise Exception("Failed to load tools") |
| 1379 | + |
| 1380 | + mock_mcp_client.load_mcp_tools = AsyncMock(side_effect=mock_load_mcp_tools) |
| 1381 | + |
| 1382 | + # Create coder with both servers |
| 1383 | + coder = Coder.create( |
| 1384 | + self.GPT35, |
| 1385 | + "diff", |
| 1386 | + io=io, |
| 1387 | + mcp_servers=[working_server, failing_server], |
| 1388 | + verbose=True, |
| 1389 | + ) |
| 1390 | + |
| 1391 | + # Verify that coder was created successfully |
| 1392 | + self.assertIsInstance(coder, Coder) |
| 1393 | + |
| 1394 | + # Verify that only the working server's tools were added |
| 1395 | + self.assertIsNotNone(coder.mcp_tools) |
| 1396 | + self.assertEqual(len(coder.mcp_tools), 1) |
| 1397 | + self.assertEqual(coder.mcp_tools[0][0], "working_server") |
| 1398 | + |
| 1399 | + # Verify that the tool list contains only working tools |
| 1400 | + tool_list = coder.get_tool_list() |
| 1401 | + self.assertEqual(len(tool_list), 1) |
| 1402 | + self.assertEqual(tool_list[0]["function"]["name"], "working_tool") |
| 1403 | + |
| 1404 | + # Verify that the warning was logged for the failing server |
| 1405 | + io.tool_warning.assert_called_with( |
| 1406 | + "Error initializing MCP server failing_server. A message has been logged." |
| 1407 | + ) |
| 1408 | + |
1354 | 1409 | @patch("aider.coders.base_coder.experimental_mcp_client")
|
1355 | 1410 | def test_initialize_mcp_tools(self, mock_mcp_client):
|
1356 | 1411 | """Test that the coder initializes MCP tools correctly."""
|
|
0 commit comments