|
4 | 4 |
|
5 | 5 | package io.modelcontextprotocol.server;
|
6 | 6 |
|
7 |
| -import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; |
8 |
| -import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json; |
9 |
| -import static org.assertj.core.api.Assertions.assertThat; |
10 |
| -import static org.awaitility.Awaitility.await; |
11 |
| - |
12 |
| -import java.time.Duration; |
13 |
| -import java.util.List; |
14 |
| -import java.util.Map; |
15 |
| -import java.util.concurrent.ConcurrentHashMap; |
16 |
| -import java.util.concurrent.atomic.AtomicReference; |
17 |
| -import java.util.function.BiFunction; |
18 |
| - |
19 |
| -import org.apache.catalina.LifecycleException; |
20 |
| -import org.apache.catalina.LifecycleState; |
21 |
| -import org.apache.catalina.startup.Tomcat; |
22 |
| -import org.junit.jupiter.api.AfterEach; |
23 |
| -import org.junit.jupiter.api.BeforeEach; |
24 |
| -import org.junit.jupiter.params.ParameterizedTest; |
25 |
| -import org.junit.jupiter.params.provider.ValueSource; |
26 |
| -import org.springframework.web.client.RestClient; |
27 |
| - |
28 | 7 | import com.fasterxml.jackson.databind.ObjectMapper;
|
29 |
| - |
30 | 8 | import io.modelcontextprotocol.client.McpClient;
|
31 | 9 | import io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport;
|
32 | 10 | import io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport;
|
33 | 11 | import io.modelcontextprotocol.server.transport.TomcatTestUtil;
|
| 12 | +import io.modelcontextprotocol.spec.HttpHeaders; |
| 13 | +import io.modelcontextprotocol.spec.McpError; |
34 | 14 | import io.modelcontextprotocol.spec.McpSchema;
|
35 | 15 | import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
|
36 | 16 | import io.modelcontextprotocol.spec.McpSchema.CompleteRequest;
|
|
41 | 21 | import io.modelcontextprotocol.spec.McpSchema.PromptReference;
|
42 | 22 | import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities;
|
43 | 23 | import io.modelcontextprotocol.spec.McpSchema.Tool;
|
| 24 | +import io.modelcontextprotocol.spec.ProtocolVersions; |
44 | 25 | import net.javacrumbs.jsonunit.core.Option;
|
| 26 | +import org.apache.catalina.LifecycleException; |
| 27 | +import org.apache.catalina.LifecycleState; |
| 28 | +import org.apache.catalina.startup.Tomcat; |
| 29 | +import org.junit.jupiter.api.AfterEach; |
| 30 | +import org.junit.jupiter.api.BeforeEach; |
| 31 | +import org.junit.jupiter.api.Test; |
| 32 | +import org.junit.jupiter.params.ParameterizedTest; |
| 33 | +import org.junit.jupiter.params.provider.ValueSource; |
| 34 | +import org.springframework.mock.web.MockHttpServletRequest; |
| 35 | +import org.springframework.mock.web.MockHttpServletResponse; |
| 36 | +import org.springframework.web.client.RestClient; |
| 37 | + |
| 38 | +import java.time.Duration; |
| 39 | +import java.util.List; |
| 40 | +import java.util.Map; |
| 41 | +import java.util.concurrent.ConcurrentHashMap; |
| 42 | +import java.util.concurrent.atomic.AtomicReference; |
| 43 | +import java.util.function.BiFunction; |
| 44 | + |
| 45 | +import static io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport.APPLICATION_JSON; |
| 46 | +import static io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport.TEXT_EVENT_STREAM; |
| 47 | +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; |
| 48 | +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json; |
| 49 | +import static org.assertj.core.api.Assertions.assertThat; |
| 50 | +import static org.awaitility.Awaitility.await; |
45 | 51 |
|
46 | 52 | class HttpServletStatelessIntegrationTests {
|
47 | 53 |
|
@@ -460,6 +466,49 @@ void testStructuredOutputRuntimeToolAddition(String clientType) {
|
460 | 466 | mcpServer.close();
|
461 | 467 | }
|
462 | 468 |
|
| 469 | + @Test |
| 470 | + void testThrownMcpError() throws Exception { |
| 471 | + var mcpServer = McpServer.sync(mcpStatelessServerTransport) |
| 472 | + .serverInfo("test-server", "1.0.0") |
| 473 | + .capabilities(ServerCapabilities.builder().tools(true).build()) |
| 474 | + .build(); |
| 475 | + |
| 476 | + Tool testTool = Tool.builder().name("test").description("test").build(); |
| 477 | + |
| 478 | + McpStatelessServerFeatures.SyncToolSpecification toolSpec = new McpStatelessServerFeatures.SyncToolSpecification( |
| 479 | + testTool, (transportContext, request) -> { |
| 480 | + throw new McpError(new McpSchema.JSONRPCResponse.JSONRPCError(12345, "testing", Map.of("a", "b"))); |
| 481 | + }); |
| 482 | + |
| 483 | + mcpServer.addTool(toolSpec); |
| 484 | + |
| 485 | + McpSchema.CallToolRequest callToolRequest = new McpSchema.CallToolRequest("test", Map.of()); |
| 486 | + McpSchema.JSONRPCRequest jsonrpcRequest = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, |
| 487 | + McpSchema.METHOD_TOOLS_CALL, "test", callToolRequest); |
| 488 | + |
| 489 | + MockHttpServletRequest request = new MockHttpServletRequest("POST", CUSTOM_MESSAGE_ENDPOINT); |
| 490 | + MockHttpServletResponse response = new MockHttpServletResponse(); |
| 491 | + |
| 492 | + byte[] content = new ObjectMapper().writeValueAsBytes(jsonrpcRequest); |
| 493 | + request.setContent(content); |
| 494 | + request.addHeader("Content-Type", "application/json"); |
| 495 | + request.addHeader("Content-Length", Integer.toString(content.length)); |
| 496 | + request.addHeader("Content-Length", Integer.toString(content.length)); |
| 497 | + request.addHeader("Accept", APPLICATION_JSON + ", " + TEXT_EVENT_STREAM); |
| 498 | + request.addHeader("Content-Type", APPLICATION_JSON); |
| 499 | + request.addHeader("Cache-Control", "no-cache"); |
| 500 | + request.addHeader(HttpHeaders.PROTOCOL_VERSION, ProtocolVersions.MCP_2025_03_26); |
| 501 | + mcpStatelessServerTransport.service(request, response); |
| 502 | + |
| 503 | + McpSchema.JSONRPCResponse jsonrpcResponse = new ObjectMapper().readValue(response.getContentAsByteArray(), |
| 504 | + McpSchema.JSONRPCResponse.class); |
| 505 | + |
| 506 | + assertThat(jsonrpcResponse.error()) |
| 507 | + .isEqualTo(new McpSchema.JSONRPCResponse.JSONRPCError(12345, "testing", Map.of("a", "b"))); |
| 508 | + |
| 509 | + mcpServer.close(); |
| 510 | + } |
| 511 | + |
463 | 512 | private double evaluateExpression(String expression) {
|
464 | 513 | // Simple expression evaluator for testing
|
465 | 514 | return switch (expression) {
|
|
0 commit comments