Skip to content

Commit 5634d89

Browse files
committed
Add tests for McpToolUtils.getToolCallbacksFromSyncClients method
- Tests empty client list handling returns empty result - Tests single client with multiple tools correctly generates tool callbacks with prefixed names - Tests multiple clients properly combine their tool callbacks - Tests duplicate tool names across clients throw appropriate exceptions Signed-off-by: Christian Tzolov <[email protected]>
1 parent e05552f commit 5634d89

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

mcp/common/src/test/java/org/springframework/ai/mcp/ToolUtilsTests.java

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@
2121
import java.util.List;
2222
import java.util.Map;
2323

24+
import io.modelcontextprotocol.client.McpSyncClient;
2425
import io.modelcontextprotocol.server.McpAsyncServerExchange;
2526
import io.modelcontextprotocol.server.McpServerFeatures.AsyncToolSpecification;
2627
import io.modelcontextprotocol.server.McpServerFeatures.SyncToolSpecification;
2728
import io.modelcontextprotocol.server.McpSyncServerExchange;
2829
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
30+
import io.modelcontextprotocol.spec.McpSchema.Implementation;
31+
import io.modelcontextprotocol.spec.McpSchema.ListToolsResult;
2932
import io.modelcontextprotocol.spec.McpSchema.TextContent;
33+
import io.modelcontextprotocol.spec.McpSchema.Tool;
3034
import org.junit.jupiter.api.Test;
3135
import reactor.test.StepVerifier;
3236

@@ -211,4 +215,118 @@ private ToolCallback createMockToolCallback(String name, RuntimeException error)
211215
return callback;
212216
}
213217

218+
@Test
219+
void getToolCallbacksFromSyncClientsWithEmptyListShouldReturnEmptyList() {
220+
List<ToolCallback> result = McpToolUtils.getToolCallbacksFromSyncClients(List.of());
221+
assertThat(result).isEmpty();
222+
}
223+
224+
@Test
225+
void getToolCallbacksFromSyncClientsWithSingleClientShouldReturnToolCallbacks() {
226+
McpSyncClient mockClient = mock(McpSyncClient.class);
227+
Implementation clientInfo = new Implementation("test-client", "1.0.0");
228+
229+
Tool tool1 = mock(Tool.class);
230+
when(tool1.name()).thenReturn("tool1");
231+
when(tool1.description()).thenReturn("Test Tool 1");
232+
233+
Tool tool2 = mock(Tool.class);
234+
when(tool2.name()).thenReturn("tool2");
235+
when(tool2.description()).thenReturn("Test Tool 2");
236+
237+
when(mockClient.getClientInfo()).thenReturn(clientInfo);
238+
239+
ListToolsResult listToolsResult = mock(ListToolsResult.class);
240+
when(listToolsResult.tools()).thenReturn(List.of(tool1, tool2));
241+
when(mockClient.listTools()).thenReturn(listToolsResult);
242+
243+
List<ToolCallback> result = McpToolUtils.getToolCallbacksFromSyncClients(mockClient);
244+
245+
assertThat(result).hasSize(2);
246+
assertThat(result.get(0).getToolDefinition().name()).isEqualTo("test_client_tool1");
247+
assertThat(result.get(1).getToolDefinition().name()).isEqualTo("test_client_tool2");
248+
249+
List<ToolCallback> result2 = McpToolUtils.getToolCallbacksFromSyncClients(List.of(mockClient));
250+
251+
assertThat(result2).hasSize(2);
252+
assertThat(result2.get(0).getToolDefinition().name()).isEqualTo("test_client_tool1");
253+
assertThat(result2.get(1).getToolDefinition().name()).isEqualTo("test_client_tool2");
254+
}
255+
256+
@Test
257+
void getToolCallbacksFromSyncClientsWithMultipleClientsShouldReturnCombinedToolCallbacks() {
258+
259+
McpSyncClient mockClient1 = mock(McpSyncClient.class);
260+
Implementation clientInfo1 = new Implementation("client1", "1.0.0");
261+
262+
Tool tool1 = mock(Tool.class);
263+
when(tool1.name()).thenReturn("tool1");
264+
when(tool1.description()).thenReturn("Test Tool 1");
265+
266+
McpSyncClient mockClient2 = mock(McpSyncClient.class);
267+
Implementation clientInfo2 = new Implementation("client2", "1.0.0");
268+
269+
Tool tool2 = mock(Tool.class);
270+
when(tool2.name()).thenReturn("tool2");
271+
when(tool2.description()).thenReturn("Test Tool 2");
272+
273+
when(mockClient1.getClientInfo()).thenReturn(clientInfo1);
274+
275+
ListToolsResult listToolsResult1 = mock(ListToolsResult.class);
276+
when(listToolsResult1.tools()).thenReturn(List.of(tool1));
277+
when(mockClient1.listTools()).thenReturn(listToolsResult1);
278+
279+
when(mockClient2.getClientInfo()).thenReturn(clientInfo2);
280+
281+
ListToolsResult listToolsResult2 = mock(ListToolsResult.class);
282+
when(listToolsResult2.tools()).thenReturn(List.of(tool2));
283+
when(mockClient2.listTools()).thenReturn(listToolsResult2);
284+
285+
List<ToolCallback> result = McpToolUtils.getToolCallbacksFromSyncClients(mockClient1, mockClient2);
286+
287+
assertThat(result).hasSize(2);
288+
assertThat(result.get(0).getToolDefinition().name()).isEqualTo("client1_tool1");
289+
assertThat(result.get(1).getToolDefinition().name()).isEqualTo("client2_tool2");
290+
291+
List<ToolCallback> result2 = McpToolUtils.getToolCallbacksFromSyncClients(List.of(mockClient1, mockClient2));
292+
293+
assertThat(result2).hasSize(2);
294+
assertThat(result2.get(0).getToolDefinition().name()).isEqualTo("client1_tool1");
295+
assertThat(result2.get(1).getToolDefinition().name()).isEqualTo("client2_tool2");
296+
}
297+
298+
@Test
299+
void getToolCallbacksFromSyncClientsShouldHandleDuplicateToolNames() {
300+
301+
McpSyncClient mockClient1 = mock(McpSyncClient.class);
302+
Implementation clientInfo1 = new Implementation("client", "1.0.0");
303+
304+
Tool tool1 = mock(Tool.class);
305+
when(tool1.name()).thenReturn("tool");
306+
when(tool1.description()).thenReturn("Test Tool 1");
307+
308+
McpSyncClient mockClient2 = mock(McpSyncClient.class);
309+
Implementation clientInfo2 = new Implementation("client", "1.0.0");
310+
311+
Tool tool2 = mock(Tool.class);
312+
when(tool2.name()).thenReturn("tool");
313+
when(tool2.description()).thenReturn("Test Tool 2");
314+
315+
when(mockClient1.getClientInfo()).thenReturn(clientInfo1);
316+
317+
ListToolsResult listToolsResult1 = mock(ListToolsResult.class);
318+
when(listToolsResult1.tools()).thenReturn(List.of(tool1));
319+
when(mockClient1.listTools()).thenReturn(listToolsResult1);
320+
321+
when(mockClient2.getClientInfo()).thenReturn(clientInfo2);
322+
323+
ListToolsResult listToolsResult2 = mock(ListToolsResult.class);
324+
when(listToolsResult2.tools()).thenReturn(List.of(tool2));
325+
when(mockClient2.listTools()).thenReturn(listToolsResult2);
326+
327+
assertThatThrownBy(() -> McpToolUtils.getToolCallbacksFromSyncClients(mockClient1, mockClient2))
328+
.isInstanceOf(IllegalStateException.class)
329+
.hasMessageContaining("Multiple tools with the same name");
330+
}
331+
214332
}

0 commit comments

Comments
 (0)