Skip to content

Commit d015b4e

Browse files
committed
Add tests for completion requests targeting missing prompt or resource
Polish gh-996 Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
1 parent 301f8b0 commit d015b4e

2 files changed

Lines changed: 118 additions & 4 deletions

File tree

mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStatelessIntegrationTests.java

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
package io.modelcontextprotocol.server;
66

7-
import static io.modelcontextprotocol.util.ToolsUtils.EMPTY_JSON_SCHEMA;
8-
97
import java.time.Duration;
108
import java.util.List;
119
import java.util.Map;
@@ -19,6 +17,7 @@
1917
import io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport;
2018
import io.modelcontextprotocol.server.transport.TomcatTestUtil;
2119
import io.modelcontextprotocol.spec.HttpHeaders;
20+
import io.modelcontextprotocol.spec.McpError;
2221
import io.modelcontextprotocol.spec.McpSchema;
2322
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
2423
import io.modelcontextprotocol.spec.McpSchema.CompleteRequest;
@@ -53,9 +52,12 @@
5352
import static io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport.APPLICATION_JSON;
5453
import static io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport.TEXT_EVENT_STREAM;
5554
import static io.modelcontextprotocol.util.McpJsonMapperUtils.JSON_MAPPER;
55+
import static io.modelcontextprotocol.util.ToolsUtils.EMPTY_JSON_SCHEMA;
5656
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
5757
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json;
5858
import static org.assertj.core.api.Assertions.assertThat;
59+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
60+
import static org.assertj.core.api.InstanceOfAssertFactories.type;
5961
import static org.awaitility.Awaitility.await;
6062

6163
@Timeout(15)
@@ -337,6 +339,63 @@ void testResourceTemplateCompletionWithoutMatchingHandlerReturnsEmptyResult(Stri
337339
}
338340
}
339341

342+
@ParameterizedTest(name = "{0} : Completion call for non-existent prompt")
343+
@ValueSource(strings = { "httpclient" })
344+
void testCompletionForNonExistentPromptReturnsInvalidParams(String clientType) {
345+
var clientBuilder = clientBuilders.get(clientType);
346+
347+
var mcpServer = McpServer.sync(mcpStatelessServerTransport)
348+
.capabilities(ServerCapabilities.builder().completions().build())
349+
.build();
350+
351+
try (var mcpClient = clientBuilder.build()) {
352+
InitializeResult initResult = mcpClient.initialize();
353+
assertThat(initResult).isNotNull();
354+
355+
CompleteRequest request = CompleteRequest
356+
.builder(new PromptReference("nonexistent-prompt"), new CompleteRequest.CompleteArgument("arg", "val"))
357+
.build();
358+
359+
assertThatThrownBy(() -> mcpClient.completeCompletion(request)).isInstanceOf(McpError.class)
360+
.asInstanceOf(type(McpError.class))
361+
.extracting(McpError::getJsonRpcError)
362+
.extracting(McpSchema.JSONRPCResponse.JSONRPCError::code)
363+
.isEqualTo(McpSchema.ErrorCodes.RESOURCE_NOT_FOUND);
364+
}
365+
finally {
366+
mcpServer.close();
367+
}
368+
}
369+
370+
@ParameterizedTest(name = "{0} : Completion call for non-existent resource")
371+
@ValueSource(strings = { "httpclient" })
372+
void testCompletionForNonExistentResourceReturnsResourceNotFound(String clientType) {
373+
var clientBuilder = clientBuilders.get(clientType);
374+
375+
var mcpServer = McpServer.sync(mcpStatelessServerTransport)
376+
.capabilities(ServerCapabilities.builder().completions().build())
377+
.build();
378+
379+
try (var mcpClient = clientBuilder.build()) {
380+
InitializeResult initResult = mcpClient.initialize();
381+
assertThat(initResult).isNotNull();
382+
383+
CompleteRequest request = CompleteRequest
384+
.builder(new ResourceReference("test://nonexistent/{param}"),
385+
new CompleteRequest.CompleteArgument("param", "val"))
386+
.build();
387+
388+
assertThatThrownBy(() -> mcpClient.completeCompletion(request)).isInstanceOf(McpError.class)
389+
.asInstanceOf(type(McpError.class))
390+
.extracting(McpError::getJsonRpcError)
391+
.extracting(McpSchema.JSONRPCResponse.JSONRPCError::code)
392+
.isEqualTo(McpSchema.ErrorCodes.RESOURCE_NOT_FOUND);
393+
}
394+
finally {
395+
mcpServer.close();
396+
}
397+
}
398+
340399
// ---------------------------------------
341400
// Tool Structured Output Schema Tests
342401
// ---------------------------------------

mcp-test/src/test/java/io/modelcontextprotocol/server/McpCompletionTests.java

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,25 @@
2121
import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
2222
import io.modelcontextprotocol.server.transport.HttpServletSseServerTransportProvider;
2323
import io.modelcontextprotocol.server.transport.TomcatTestUtil;
24+
import io.modelcontextprotocol.spec.McpError;
2425
import io.modelcontextprotocol.spec.McpSchema;
2526
import io.modelcontextprotocol.spec.McpSchema.CompleteRequest;
2627
import io.modelcontextprotocol.spec.McpSchema.CompleteResult;
2728
import io.modelcontextprotocol.spec.McpSchema.ErrorCodes;
2829
import io.modelcontextprotocol.spec.McpSchema.InitializeResult;
2930
import io.modelcontextprotocol.spec.McpSchema.Prompt;
3031
import io.modelcontextprotocol.spec.McpSchema.PromptArgument;
32+
import io.modelcontextprotocol.spec.McpSchema.PromptReference;
3133
import io.modelcontextprotocol.spec.McpSchema.ReadResourceResult;
3234
import io.modelcontextprotocol.spec.McpSchema.Resource;
3335
import io.modelcontextprotocol.spec.McpSchema.ResourceReference;
3436
import io.modelcontextprotocol.spec.McpSchema.ResourceTemplate;
35-
import io.modelcontextprotocol.spec.McpSchema.PromptReference;
3637
import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities;
37-
import io.modelcontextprotocol.spec.McpError;
3838

3939
import static org.assertj.core.api.Assertions.assertThat;
4040
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
41+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
42+
import static org.assertj.core.api.InstanceOfAssertFactories.type;
4143

4244
/**
4345
* Tests for completion functionality with context support.
@@ -273,6 +275,59 @@ void testResourceTemplateCompletionWithoutMatchingHandlerReturnsEmptyResult() {
273275
mcpServer.close();
274276
}
275277

278+
@Test
279+
void testCompletionForNonExistentPromptReturnsInvalidParams() {
280+
var mcpServer = McpServer.sync(mcpServerTransportProvider)
281+
.capabilities(ServerCapabilities.builder().completions().build())
282+
.build();
283+
284+
try (var mcpClient = clientBuilder
285+
.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build())
286+
.build()) {
287+
InitializeResult initResult = mcpClient.initialize();
288+
assertThat(initResult).isNotNull();
289+
290+
CompleteRequest request = CompleteRequest
291+
.builder(new PromptReference("nonexistent-prompt"), new CompleteRequest.CompleteArgument("arg", "val"))
292+
.build();
293+
294+
assertThatThrownBy(() -> mcpClient.completeCompletion(request)).isInstanceOf(McpError.class)
295+
.asInstanceOf(type(McpError.class))
296+
.extracting(McpError::getJsonRpcError)
297+
.extracting(McpSchema.JSONRPCResponse.JSONRPCError::code)
298+
.isEqualTo(ErrorCodes.INVALID_PARAMS);
299+
}
300+
301+
mcpServer.close();
302+
}
303+
304+
@Test
305+
void testCompletionForNonExistentResourceReturnsResourceNotFound() {
306+
var mcpServer = McpServer.sync(mcpServerTransportProvider)
307+
.capabilities(ServerCapabilities.builder().completions().build())
308+
.build();
309+
310+
try (var mcpClient = clientBuilder
311+
.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build())
312+
.build()) {
313+
InitializeResult initResult = mcpClient.initialize();
314+
assertThat(initResult).isNotNull();
315+
316+
CompleteRequest request = CompleteRequest
317+
.builder(new ResourceReference("test://nonexistent/{param}"),
318+
new CompleteRequest.CompleteArgument("param", "val"))
319+
.build();
320+
321+
assertThatThrownBy(() -> mcpClient.completeCompletion(request)).isInstanceOf(McpError.class)
322+
.asInstanceOf(type(McpError.class))
323+
.extracting(McpError::getJsonRpcError)
324+
.extracting(McpSchema.JSONRPCResponse.JSONRPCError::code)
325+
.isEqualTo(McpSchema.ErrorCodes.RESOURCE_NOT_FOUND);
326+
}
327+
328+
mcpServer.close();
329+
}
330+
276331
@Test
277332
void testDependentCompletionScenario() {
278333
BiFunction<McpSyncServerExchange, CompleteRequest, CompleteResult> completionHandler = (exchange, request) -> {

0 commit comments

Comments
 (0)