|
4 | 4 |
|
5 | 5 | package io.modelcontextprotocol.server; |
6 | 6 |
|
7 | | -import java.net.URI; |
8 | | -import java.net.http.HttpClient; |
9 | | -import java.net.http.HttpRequest; |
10 | | -import java.net.http.HttpResponse; |
11 | 7 | import java.time.Duration; |
12 | 8 | import java.util.List; |
13 | 9 | import java.util.Map; |
14 | 10 | import java.util.concurrent.atomic.AtomicReference; |
15 | 11 | import java.util.function.BiFunction; |
| 12 | +import java.util.function.Function; |
16 | 13 |
|
17 | 14 | import io.modelcontextprotocol.client.McpClient; |
18 | 15 | import io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport; |
|
49 | 46 | import org.springframework.mock.web.MockHttpServletRequest; |
50 | 47 | import org.springframework.mock.web.MockHttpServletResponse; |
51 | 48 | import org.springframework.web.client.RestClient; |
| 49 | +import reactor.core.publisher.Mono; |
| 50 | +import reactor.test.StepVerifier; |
52 | 51 |
|
53 | 52 | import static io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport.APPLICATION_JSON; |
54 | 53 | import static io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport.TEXT_EVENT_STREAM; |
@@ -769,40 +768,46 @@ void testThrownMcpErrorAndJsonRpcError() throws Exception { |
769 | 768 | mcpServer.close(); |
770 | 769 | } |
771 | 770 |
|
772 | | - @ParameterizedTest |
773 | | - @ValueSource(strings = { "tools/list", "resources/list", "prompts/list" }) |
774 | | - void testMissingHandlerReturnsMethodNotFoundError(String method) throws Exception { |
| 771 | + @Test |
| 772 | + void testMissingHandlerReturnsMethodNotFoundError() { |
775 | 773 | var mcpServer = McpServer.sync(mcpStatelessServerTransport) |
776 | 774 | .serverInfo("test-server", "1.0.0") |
777 | 775 | .capabilities(ServerCapabilities.builder().build()) |
778 | 776 | .build(); |
| 777 | + var clientTransport = HttpClientStreamableHttpTransport.builder("http://localhost:" + PORT) |
| 778 | + .endpoint(CUSTOM_MESSAGE_ENDPOINT) |
| 779 | + .build(); |
779 | 780 |
|
780 | | - HttpResponse<String> response; |
| 781 | + try (var mcpClient = McpClient.sync(clientTransport).build()) { |
| 782 | + // Create a session using an MCP client |
| 783 | + McpSchema.InitializeResult initResult = mcpClient.initialize(); |
| 784 | + assertThat(initResult).isNotNull(); |
781 | 785 |
|
782 | | - try { |
783 | | - HttpRequest request = HttpRequest.newBuilder() |
784 | | - .uri(URI.create("http://localhost:" + PORT + CUSTOM_MESSAGE_ENDPOINT)) |
785 | | - .header("Content-Type", "application/json") |
786 | | - .header("Accept", "application/json, text/event-stream") |
787 | | - .POST(HttpRequest.BodyPublishers.ofString(""" |
788 | | - { |
789 | | - "jsonrpc": "2.0", |
790 | | - "method": "%s", |
791 | | - "id": "test-request-123", |
792 | | - "params": {} |
| 786 | + // Override the response handler in the client to capture responses |
| 787 | + AtomicReference<McpSchema.JSONRPCResponse> response = new AtomicReference<>(); |
| 788 | + var handler = (Function<Mono<McpSchema.JSONRPCMessage>, Mono<McpSchema.JSONRPCMessage>>) ( |
| 789 | + message) -> message.doOnNext(r -> { |
| 790 | + if (r instanceof McpSchema.JSONRPCResponse resp) { |
| 791 | + response.set(resp); |
793 | 792 | } |
794 | | - """.formatted(method))) |
795 | | - .build(); |
| 793 | + }); |
| 794 | + StepVerifier.create(clientTransport.connect(handler)).verifyComplete(); |
| 795 | + |
| 796 | + // Send a request for a non-existent method through the transport, bypassing |
| 797 | + // the client's capability checks |
| 798 | + StepVerifier |
| 799 | + .create(clientTransport.sendMessage(new McpSchema.JSONRPCRequest("foo/bar", "test-request-123"))) |
| 800 | + .verifyComplete(); |
796 | 801 |
|
797 | | - response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); |
| 802 | + // Wait until we've received the response |
| 803 | + await().atMost(Duration.ofSeconds(1)).until(() -> response.get() != null); |
| 804 | + |
| 805 | + assertThat(response.get().error().code()).isEqualTo(McpSchema.ErrorCodes.METHOD_NOT_FOUND); |
| 806 | + assertThat(response.get().error().message()).isEqualTo("Method not found: foo/bar"); |
798 | 807 | } |
799 | 808 | finally { |
800 | 809 | mcpServer.closeGracefully(); |
801 | 810 | } |
802 | | - |
803 | | - final var responseBody = response.body(); |
804 | | - assertThatJson(responseBody).inPath("error.code").isEqualTo(McpSchema.ErrorCodes.METHOD_NOT_FOUND); |
805 | | - assertThatJson(responseBody).inPath("error.message").isEqualTo("Method not found: " + method); |
806 | 811 | } |
807 | 812 |
|
808 | 813 | private double evaluateExpression(String expression) { |
|
0 commit comments