Bug description
The completion validation code in McpAsyncServer and McpStatelessAsyncServer throws a NullPointerException when a Prompt is registered with null arguments and a completion/complete request is received for that prompt.
This was introduced in commit 4c85963 (#972, the 2.0 forward-compat refactor), which changed Prompt constructors to stop coercing null arguments to an empty list — but did not update the SDK's own completion handler code that calls .arguments().stream() without a null guard.
Additionally, MIGRATION-2.0.md references a Prompt.withDefaults() factory method as the migration path, but this method was never implemented.
Environment
- MCP Java SDK:
main branch, commit 4c85963
- Java: 17+
- Transport: stdio (also affects servlet-based transports)
Steps to reproduce
- Create a server with a prompt that has null arguments:
Prompt prompt = new Prompt("summarize", "Summarize a document", (List<PromptArgument>) null);
- Register a completion handler for that prompt
- Send a
completion/complete request:
{"jsonrpc":"2.0","id":2,"method":"completion/complete","params":{"ref":{"type":"ref/prompt","name":"summarize"},"argument":{"name":"query","value":"sum"}}}
Expected behavior
An empty completion result or a proper error response.
Actual behavior
{"jsonrpc":"2.0","id":2,"error":{"code":-32603,"message":"Cannot invoke \"java.util.List.stream()\" because the return value of \"io.modelcontextprotocol.spec.McpSchema$Prompt.arguments()\" is null"}}
Minimal Complete Reproducible example
https://github.com/sainathreddyb/mcp-test-servers/tree/main/bug-repro-server
Root cause
McpAsyncServer.java ~line 1002 and McpStatelessAsyncServer.java ~line 747:
if (!promptSpec.prompt()
.arguments() // returns null since 2.0
.stream() // NPE
...
Fix
- Add null guard before
.stream() in both server classes
- Implement the
Prompt.withDefaults() factory referenced in MIGRATION-2.0.md
Bug description
The completion validation code in
McpAsyncServerandMcpStatelessAsyncServerthrows aNullPointerExceptionwhen aPromptis registered withnullarguments and acompletion/completerequest is received for that prompt.This was introduced in commit
4c85963(#972, the 2.0 forward-compat refactor), which changedPromptconstructors to stop coercingnullarguments to an empty list — but did not update the SDK's own completion handler code that calls.arguments().stream()without a null guard.Additionally,
MIGRATION-2.0.mdreferences aPrompt.withDefaults()factory method as the migration path, but this method was never implemented.Environment
mainbranch, commit4c85963Steps to reproduce
completion/completerequest:{"jsonrpc":"2.0","id":2,"method":"completion/complete","params":{"ref":{"type":"ref/prompt","name":"summarize"},"argument":{"name":"query","value":"sum"}}}Expected behavior
An empty completion result or a proper error response.
Actual behavior
{"jsonrpc":"2.0","id":2,"error":{"code":-32603,"message":"Cannot invoke \"java.util.List.stream()\" because the return value of \"io.modelcontextprotocol.spec.McpSchema$Prompt.arguments()\" is null"}}Minimal Complete Reproducible example
https://github.com/sainathreddyb/mcp-test-servers/tree/main/bug-repro-server
Root cause
McpAsyncServer.java~line 1002 andMcpStatelessAsyncServer.java~line 747:Fix
.stream()in both server classesPrompt.withDefaults()factory referenced inMIGRATION-2.0.md