Skip to content

Commit 5895b2e

Browse files
authored
fix: Return empty prompt completion result when prompt has no arguments (#934)
Recent changes don't coerce null completion arguments to empty lists so we have to check for null when handling prompt completions. Resolves #932 Signed-off-by: Dariusz Jędrzejczyk <2554306+chemicL@users.noreply.github.com>
1 parent 4c85963 commit 5895b2e

4 files changed

Lines changed: 45 additions & 19 deletions

File tree

mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -999,12 +999,9 @@ private McpRequestHandler<McpSchema.CompleteResult> completionCompleteRequestHan
999999
.message("Prompt not found: " + promptReference.name())
10001000
.build());
10011001
}
1002-
if (!promptSpec.prompt()
1003-
.arguments()
1004-
.stream()
1005-
.filter(arg -> arg.name().equals(argumentName))
1006-
.findFirst()
1007-
.isPresent()) {
1002+
List<McpSchema.PromptArgument> arguments = promptSpec.prompt().arguments();
1003+
if (arguments == null
1004+
|| !arguments.stream().filter(arg -> arg.name().equals(argumentName)).findFirst().isPresent()) {
10081005

10091006
logger.warn("Argument not found: {} in prompt: {}", argumentName, promptReference.name());
10101007

mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -744,12 +744,9 @@ private McpStatelessRequestHandler<McpSchema.CompleteResult> completionCompleteR
744744
.message("Prompt not found: " + promptReference.name())
745745
.build());
746746
}
747-
if (!promptSpec.prompt()
748-
.arguments()
749-
.stream()
750-
.filter(arg -> arg.name().equals(argumentName))
751-
.findFirst()
752-
.isPresent()) {
747+
List<McpSchema.PromptArgument> arguments = promptSpec.prompt().arguments();
748+
if (arguments == null
749+
|| !arguments.stream().filter(arg -> arg.name().equals(argumentName)).findFirst().isPresent()) {
753750

754751
logger.warn("Argument not found: {} in prompt: {}", argumentName, promptReference.name());
755752

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,10 @@ void testCompletionShouldReturnExpectedSuggestions(String clientType) {
184184
true // hasMore
185185
));
186186

187-
AtomicReference<CompleteRequest> samplingRequest = new AtomicReference<>();
187+
AtomicReference<CompleteRequest> completeRequest = new AtomicReference<>();
188188
BiFunction<McpTransportContext, CompleteRequest, CompleteResult> completionHandler = (transportContext,
189189
request) -> {
190-
samplingRequest.set(request);
190+
completeRequest.set(request);
191191
return completionResponse;
192192
};
193193

@@ -214,9 +214,9 @@ void testCompletionShouldReturnExpectedSuggestions(String clientType) {
214214

215215
assertThat(result).isNotNull();
216216

217-
assertThat(samplingRequest.get().argument().name()).isEqualTo("language");
218-
assertThat(samplingRequest.get().argument().value()).isEqualTo("py");
219-
assertThat(samplingRequest.get().ref().type()).isEqualTo(PromptReference.TYPE);
217+
assertThat(completeRequest.get().argument().name()).isEqualTo("language");
218+
assertThat(completeRequest.get().argument().value()).isEqualTo("py");
219+
assertThat(completeRequest.get().ref().type()).isEqualTo(PromptReference.TYPE);
220220
}
221221
finally {
222222
mcpServer.close();

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

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@
1313
import org.apache.catalina.LifecycleState;
1414
import org.apache.catalina.startup.Tomcat;
1515

16-
import static org.assertj.core.api.Assertions.assertThat;
1716
import org.junit.jupiter.api.AfterEach;
1817
import org.junit.jupiter.api.BeforeEach;
1918
import org.junit.jupiter.api.Test;
20-
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
2119

2220
import io.modelcontextprotocol.client.McpClient;
2321
import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
@@ -37,6 +35,9 @@
3735
import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities;
3836
import io.modelcontextprotocol.spec.McpError;
3937

38+
import static org.assertj.core.api.Assertions.assertThat;
39+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
40+
4041
/**
4142
* Tests for completion functionality with context support.
4243
*
@@ -324,4 +325,35 @@ void testCompletionErrorOnMissingContext() {
324325
mcpServer.close();
325326
}
326327

328+
@Test
329+
void testPromptWithoutArgumentsCompletionForArgument() {
330+
BiFunction<McpSyncServerExchange, CompleteRequest, CompleteResult> completionHandler = (exchange,
331+
request) -> new CompleteResult(new CompleteResult.CompleteCompletion(List.of("test"), 1, false));
332+
333+
McpSchema.Prompt prompt = new Prompt("test-prompt", "this is a test prompt", null);
334+
335+
var mcpServer = McpServer.sync(mcpServerTransportProvider)
336+
.capabilities(ServerCapabilities.builder().completions().build())
337+
.prompts(new McpServerFeatures.SyncPromptSpecification(prompt,
338+
(mcpSyncServerExchange, getPromptRequest) -> null))
339+
.completions(new McpServerFeatures.SyncCompletionSpecification(
340+
new PromptReference(PromptReference.TYPE, "test-prompt"), completionHandler))
341+
.build();
342+
343+
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
344+
.build()) {
345+
InitializeResult initResult = mcpClient.initialize();
346+
assertThat(initResult).isNotNull();
347+
348+
// try completing an argument knowing that the prompt is not parameterized
349+
CompleteRequest request = new CompleteRequest(new PromptReference(PromptReference.TYPE, "test-prompt"),
350+
new CompleteRequest.CompleteArgument("arg", "val"));
351+
352+
CompleteResult completeResult = mcpClient.completeCompletion(request);
353+
assertThat(completeResult.completion().values()).isEmpty();
354+
}
355+
356+
mcpServer.close();
357+
}
358+
327359
}

0 commit comments

Comments
 (0)