Skip to content

Commit 11ae729

Browse files
committed
Fix NPE caused by response without id
Close GH-506 Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
1 parent 713ee1a commit 11ae729

4 files changed

Lines changed: 42 additions & 22 deletions

File tree

‎mcp/src/main/java/io/modelcontextprotocol/spec/McpClientSession.java‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
*
3636
* @author Christian Tzolov
3737
* @author Dariusz Jędrzejczyk
38+
* @author Yanming Zhou
3839
*/
3940
public class McpClientSession implements McpSession {
4041

@@ -146,13 +147,18 @@ private void dismissPendingResponses() {
146147

147148
private void handle(McpSchema.JSONRPCMessage message) {
148149
if (message instanceof McpSchema.JSONRPCResponse response) {
149-
logger.debug("Received Response: {}", response);
150-
var sink = pendingResponses.remove(response.id());
151-
if (sink == null) {
152-
logger.warn("Unexpected response for unknown id {}", response.id());
150+
logger.debug("Received response: {}", response);
151+
if (response.id() != null) {
152+
var sink = pendingResponses.remove(response.id());
153+
if (sink == null) {
154+
logger.warn("Unexpected response for unknown id {}", response.id());
155+
}
156+
else {
157+
sink.success(response);
158+
}
153159
}
154160
else {
155-
sink.success(response);
161+
logger.debug("Discarded response without id");
156162
}
157163
}
158164
else if (message instanceof McpSchema.JSONRPCRequest request) {

‎mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.fasterxml.jackson.databind.ObjectMapper;
2626

2727
import io.modelcontextprotocol.util.Assert;
28+
import reactor.util.annotation.Nullable;
2829

2930
/**
3031
* Based on the <a href="http://www.jsonrpc.org/specification">JSON-RPC 2.0
@@ -36,6 +37,7 @@
3637
* @author Luca Chang
3738
* @author Surbhi Bansal
3839
* @author Anurag Pant
40+
* @author Yanming Zhou
3941
*/
4042
public final class McpSchema {
4143

@@ -281,7 +283,7 @@ public record JSONRPCNotification( // @formatter:off
281283
// @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
282284
public record JSONRPCResponse( // @formatter:off
283285
@JsonProperty("jsonrpc") String jsonrpc,
284-
@JsonProperty("id") Object id,
286+
@JsonProperty("id") @Nullable Object id,
285287
@JsonProperty("result") Object result,
286288
@JsonProperty("error") JSONRPCError error) implements JSONRPCMessage { // @formatter:on
287289

‎mcp/src/main/java/io/modelcontextprotocol/spec/McpServerSession.java‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,13 +202,18 @@ public Mono<Void> handle(McpSchema.JSONRPCMessage message) {
202202
// TODO handle errors for communication to without initialization happening
203203
// first
204204
if (message instanceof McpSchema.JSONRPCResponse response) {
205-
logger.debug("Received Response: {}", response);
206-
var sink = pendingResponses.remove(response.id());
207-
if (sink == null) {
208-
logger.warn("Unexpected response for unknown id {}", response.id());
205+
logger.debug("Received response: {}", response);
206+
if (response.id() != null) {
207+
var sink = pendingResponses.remove(response.id());
208+
if (sink == null) {
209+
logger.warn("Unexpected response for unknown id {}", response.id());
210+
}
211+
else {
212+
sink.success(response);
213+
}
209214
}
210215
else {
211-
sink.success(response);
216+
logger.debug("Discarded response without id");
212217
}
213218
return Mono.empty();
214219
}

‎mcp/src/main/java/io/modelcontextprotocol/spec/McpStreamableServerSession.java‎

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
* capability without the insight into the transport-specific details of HTTP handling.
3434
*
3535
* @author Dariusz Jędrzejczyk
36+
* @author Yanming Zhou
3637
*/
3738
public class McpStreamableServerSession implements McpLoggableSession {
3839

@@ -214,19 +215,25 @@ public Mono<Void> accept(McpSchema.JSONRPCNotification notification) {
214215
*/
215216
public Mono<Void> accept(McpSchema.JSONRPCResponse response) {
216217
return Mono.defer(() -> {
217-
var stream = this.requestIdToStream.get(response.id());
218-
if (stream == null) {
219-
return Mono.error(new McpError("Unexpected response for unknown id " + response.id())); // TODO
220-
// JSONize
221-
}
222-
// TODO: encapsulate this inside the stream itself
223-
var sink = stream.pendingResponses.remove(response.id());
224-
if (sink == null) {
225-
return Mono.error(new McpError("Unexpected response for unknown id " + response.id())); // TODO
226-
// JSONize
218+
logger.debug("Received response: {}", response);
219+
if (response.id() != null) {
220+
var stream = this.requestIdToStream.get(response.id());
221+
if (stream == null) {
222+
return Mono.error(new McpError("Unexpected response for unknown id " + response.id())); // TODO
223+
// JSONize
224+
}
225+
// TODO: encapsulate this inside the stream itself
226+
var sink = stream.pendingResponses.remove(response.id());
227+
if (sink == null) {
228+
return Mono.error(new McpError("Unexpected response for unknown id " + response.id())); // TODO
229+
// JSONize
230+
}
231+
else {
232+
sink.success(response);
233+
}
227234
}
228235
else {
229-
sink.success(response);
236+
logger.debug("Discarded response without id");
230237
}
231238
return Mono.empty();
232239
});

0 commit comments

Comments
 (0)