Skip to content

Commit 9f50bcb

Browse files
committed
feat: adds mcp-schema-jackson
1 parent 8dcd630 commit 9f50bcb

File tree

60 files changed

+1787
-1011
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1787
-1011
lines changed

mcp-bom/pom.xml

+8-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,14 @@
2929
<!-- MCP Spec -->
3030
<dependency>
3131
<groupId>io.modelcontextprotocol.sdk</groupId>
32-
<artifactId>mcp-reactor</artifactId>
32+
<artifactId>mcp-spi</artifactId>
33+
<version>${project.version}</version>
34+
</dependency>
35+
36+
<!-- MCP Jacson Schema -->
37+
<dependency>
38+
<groupId>io.modelcontextprotocol.sdk</groupId>
39+
<artifactId>mcp-schema-jackson</artifactId>
3340
<version>${project.version}</version>
3441
</dependency>
3542

mcp-reactor/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@
7171
<version>${project.version}</version>
7272
</dependency>
7373

74+
<dependency>
75+
<groupId>io.modelcontextprotocol.sdk</groupId>
76+
<artifactId>mcp-schema-jackson</artifactId>
77+
<version>${project.version}</version>
78+
</dependency>
79+
7480
<dependency>
7581
<groupId>org.slf4j</groupId>
7682
<artifactId>slf4j-api</artifactId>

mcp-reactor/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java

+37-42
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,23 @@
1313
import java.util.concurrent.atomic.AtomicBoolean;
1414
import java.util.function.Function;
1515

16-
import com.fasterxml.jackson.core.type.TypeReference;
16+
import io.modelcontextprotocol.schema.McpType;
1717
import io.modelcontextprotocol.session.McpClientSession;
1818
import io.modelcontextprotocol.session.McpClientSession.NotificationHandler;
1919
import io.modelcontextprotocol.session.McpClientSession.RequestHandler;
2020
import io.modelcontextprotocol.spec.McpClientTransport;
2121
import io.modelcontextprotocol.spec.McpError;
22-
import io.modelcontextprotocol.spec.McpSchema;
23-
import io.modelcontextprotocol.spec.McpSchema.ClientCapabilities;
24-
import io.modelcontextprotocol.spec.McpSchema.CreateMessageRequest;
25-
import io.modelcontextprotocol.spec.McpSchema.CreateMessageResult;
26-
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
27-
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
28-
import io.modelcontextprotocol.spec.McpSchema.ListPromptsResult;
29-
import io.modelcontextprotocol.spec.McpSchema.LoggingLevel;
30-
import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
31-
import io.modelcontextprotocol.spec.McpSchema.PaginatedRequest;
32-
import io.modelcontextprotocol.spec.McpSchema.Root;
22+
import io.modelcontextprotocol.schema.McpSchema;
23+
import io.modelcontextprotocol.schema.McpSchema.ClientCapabilities;
24+
import io.modelcontextprotocol.schema.McpSchema.CreateMessageRequest;
25+
import io.modelcontextprotocol.schema.McpSchema.CreateMessageResult;
26+
import io.modelcontextprotocol.schema.McpSchema.GetPromptRequest;
27+
import io.modelcontextprotocol.schema.McpSchema.GetPromptResult;
28+
import io.modelcontextprotocol.schema.McpSchema.ListPromptsResult;
29+
import io.modelcontextprotocol.schema.McpSchema.LoggingLevel;
30+
import io.modelcontextprotocol.schema.McpSchema.LoggingMessageNotification;
31+
import io.modelcontextprotocol.schema.McpSchema.PaginatedRequest;
32+
import io.modelcontextprotocol.schema.McpSchema.Root;
3333
import io.modelcontextprotocol.spec.McpTransport;
3434
import io.modelcontextprotocol.util.Assert;
3535
import io.modelcontextprotocol.util.Utils;
@@ -80,8 +80,7 @@ public class McpAsyncClient {
8080

8181
private static final Logger logger = LoggerFactory.getLogger(McpAsyncClient.class);
8282

83-
private static TypeReference<Void> VOID_TYPE_REFERENCE = new TypeReference<>() {
84-
};
83+
private static final McpType<Void> VOID_TYPE_REFERENCE = McpType.of(Void.class);
8584

8685
protected final Sinks.One<McpSchema.InitializeResult> initializedSink = Sinks.one();
8786

@@ -337,8 +336,7 @@ public Mono<McpSchema.InitializeResult> initialize() {
337336
this.clientInfo); // @formatter:on
338337

339338
Mono<McpSchema.InitializeResult> result = this.mcpSession.sendRequest(McpSchema.METHOD_INITIALIZE,
340-
initializeRequest, new TypeReference<McpSchema.InitializeResult>() {
341-
});
339+
initializeRequest, McpType.of(McpSchema.InitializeResult.class));
342340

343341
return result.flatMap(initializeResult -> {
344342

@@ -389,8 +387,7 @@ private <T> Mono<T> withInitializationCheck(String actionName,
389387
*/
390388
public Mono<Object> ping() {
391389
return this.withInitializationCheck("pinging the server", initializedResult -> this.mcpSession
392-
.sendRequest(McpSchema.METHOD_PING, null, new TypeReference<Object>() {
393-
}));
390+
.sendRequest(McpSchema.METHOD_PING, null, McpType.of(Object.class)));
394391
}
395392

396393
// --------------------------
@@ -479,8 +476,7 @@ private RequestHandler<McpSchema.ListRootsResult> rootsListRequestHandler() {
479476
return params -> {
480477
@SuppressWarnings("unused")
481478
McpSchema.PaginatedRequest request = transport.unmarshalFrom(params,
482-
new TypeReference<McpSchema.PaginatedRequest>() {
483-
});
479+
McpType.of(McpSchema.PaginatedRequest.class));
484480

485481
List<Root> roots = this.roots.values().stream().toList();
486482

@@ -494,8 +490,7 @@ private RequestHandler<McpSchema.ListRootsResult> rootsListRequestHandler() {
494490
private RequestHandler<CreateMessageResult> samplingCreateMessageHandler() {
495491
return params -> {
496492
McpSchema.CreateMessageRequest request = transport.unmarshalFrom(params,
497-
new TypeReference<McpSchema.CreateMessageRequest>() {
498-
});
493+
McpType.of(McpSchema.CreateMessageRequest.class));
499494

500495
return this.samplingHandler.apply(request);
501496
};
@@ -504,11 +499,11 @@ private RequestHandler<CreateMessageResult> samplingCreateMessageHandler() {
504499
// --------------------------
505500
// Tools
506501
// --------------------------
507-
private static final TypeReference<McpSchema.CallToolResult> CALL_TOOL_RESULT_TYPE_REF = new TypeReference<>() {
508-
};
502+
private static final McpType<McpSchema.CallToolResult> CALL_TOOL_RESULT_TYPE_REF = McpType
503+
.of(McpSchema.CallToolResult.class);
509504

510-
private static final TypeReference<McpSchema.ListToolsResult> LIST_TOOLS_RESULT_TYPE_REF = new TypeReference<>() {
511-
};
505+
private static final McpType<McpSchema.ListToolsResult> LIST_TOOLS_RESULT_TYPE_REF = McpType
506+
.of(McpSchema.ListToolsResult.class);
512507

513508
/**
514509
* Calls a tool provided by the server. Tools enable servers to expose executable
@@ -570,14 +565,14 @@ private NotificationHandler asyncToolsChangeNotificationHandler(
570565
// Resources
571566
// --------------------------
572567

573-
private static final TypeReference<McpSchema.ListResourcesResult> LIST_RESOURCES_RESULT_TYPE_REF = new TypeReference<>() {
574-
};
568+
private static final McpType<McpSchema.ListResourcesResult> LIST_RESOURCES_RESULT_TYPE_REF = McpType
569+
.of(McpSchema.ListResourcesResult.class);
575570

576-
private static final TypeReference<McpSchema.ReadResourceResult> READ_RESOURCE_RESULT_TYPE_REF = new TypeReference<>() {
577-
};
571+
private static final McpType<McpSchema.ReadResourceResult> READ_RESOURCE_RESULT_TYPE_REF = McpType
572+
.of(McpSchema.ReadResourceResult.class);
578573

579-
private static final TypeReference<McpSchema.ListResourceTemplatesResult> LIST_RESOURCE_TEMPLATES_RESULT_TYPE_REF = new TypeReference<>() {
580-
};
574+
private static final McpType<McpSchema.ListResourceTemplatesResult> LIST_RESOURCE_TEMPLATES_RESULT_TYPE_REF = McpType
575+
.of(McpSchema.ListResourceTemplatesResult.class);
581576

582577
/**
583578
* Retrieves the list of all resources provided by the server. Resources represent any
@@ -712,11 +707,11 @@ private NotificationHandler asyncResourcesChangeNotificationHandler(
712707
// --------------------------
713708
// Prompts
714709
// --------------------------
715-
private static final TypeReference<McpSchema.ListPromptsResult> LIST_PROMPTS_RESULT_TYPE_REF = new TypeReference<>() {
716-
};
710+
private static final McpType<McpSchema.ListPromptsResult> LIST_PROMPTS_RESULT_TYPE_REF = McpType
711+
.of(McpSchema.ListPromptsResult.class);
717712

718-
private static final TypeReference<McpSchema.GetPromptResult> GET_PROMPT_RESULT_TYPE_REF = new TypeReference<>() {
719-
};
713+
private static final McpType<McpSchema.GetPromptResult> GET_PROMPT_RESULT_TYPE_REF = McpType
714+
.of(McpSchema.GetPromptResult.class);
720715

721716
/**
722717
* Retrieves the list of all prompts provided by the server.
@@ -781,8 +776,7 @@ private NotificationHandler asyncLoggingNotificationHandler(
781776

782777
return params -> {
783778
McpSchema.LoggingMessageNotification loggingMessageNotification = transport.unmarshalFrom(params,
784-
new TypeReference<McpSchema.LoggingMessageNotification>() {
785-
});
779+
McpType.of(McpSchema.LoggingMessageNotification.class));
786780

787781
return Flux.fromIterable(loggingConsumers)
788782
.flatMap(consumer -> consumer.apply(loggingMessageNotification))
@@ -804,8 +798,8 @@ public Mono<Void> setLoggingLevel(LoggingLevel loggingLevel) {
804798

805799
return this.withInitializationCheck("setting logging level", initializedResult -> {
806800
var params = new McpSchema.SetLevelRequest(loggingLevel);
807-
return this.mcpSession.sendRequest(McpSchema.METHOD_LOGGING_SET_LEVEL, params, new TypeReference<Object>() {
808-
}).then();
801+
return this.mcpSession.sendRequest(McpSchema.METHOD_LOGGING_SET_LEVEL, params, McpType.of(Object.class))
802+
.then();
809803
});
810804
}
811805

@@ -816,13 +810,14 @@ public Mono<Void> setLoggingLevel(LoggingLevel loggingLevel) {
816810
*/
817811
void setProtocolVersions(List<String> protocolVersions) {
818812
this.protocolVersions = protocolVersions;
813+
819814
}
820815

821816
// --------------------------
822817
// Completions
823818
// --------------------------
824-
private static final TypeReference<McpSchema.CompleteResult> COMPLETION_COMPLETE_RESULT_TYPE_REF = new TypeReference<>() {
825-
};
819+
private static final McpType<McpSchema.CompleteResult> COMPLETION_COMPLETE_RESULT_TYPE_REF = McpType
820+
.of(McpSchema.CompleteResult.class);
826821

827822
/**
828823
* Sends a completion/complete request to generate value suggestions based on a given

mcp-reactor/src/main/java/io/modelcontextprotocol/client/McpClient.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
import java.util.function.Function;
1414

1515
import io.modelcontextprotocol.spec.McpClientTransport;
16-
import io.modelcontextprotocol.spec.McpSchema;
16+
import io.modelcontextprotocol.schema.McpSchema;
1717
import io.modelcontextprotocol.spec.McpTransport;
18-
import io.modelcontextprotocol.spec.McpSchema.ClientCapabilities;
19-
import io.modelcontextprotocol.spec.McpSchema.CreateMessageRequest;
20-
import io.modelcontextprotocol.spec.McpSchema.CreateMessageResult;
21-
import io.modelcontextprotocol.spec.McpSchema.Implementation;
22-
import io.modelcontextprotocol.spec.McpSchema.Root;
18+
import io.modelcontextprotocol.schema.McpSchema.ClientCapabilities;
19+
import io.modelcontextprotocol.schema.McpSchema.CreateMessageRequest;
20+
import io.modelcontextprotocol.schema.McpSchema.CreateMessageResult;
21+
import io.modelcontextprotocol.schema.McpSchema.Implementation;
22+
import io.modelcontextprotocol.schema.McpSchema.Root;
2323
import io.modelcontextprotocol.util.Assert;
2424
import reactor.core.publisher.Mono;
2525

mcp-reactor/src/main/java/io/modelcontextprotocol/client/McpClientFeatures.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import java.util.function.Consumer;
1313
import java.util.function.Function;
1414

15-
import io.modelcontextprotocol.spec.McpSchema;
15+
import io.modelcontextprotocol.schema.McpSchema;
1616
import io.modelcontextprotocol.util.Assert;
1717
import io.modelcontextprotocol.util.Utils;
1818
import reactor.core.publisher.Mono;

mcp-reactor/src/main/java/io/modelcontextprotocol/client/McpSyncClient.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
import java.time.Duration;
88

9-
import io.modelcontextprotocol.spec.McpSchema;
10-
import io.modelcontextprotocol.spec.McpSchema.ClientCapabilities;
11-
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
12-
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
13-
import io.modelcontextprotocol.spec.McpSchema.ListPromptsResult;
9+
import io.modelcontextprotocol.schema.McpSchema;
10+
import io.modelcontextprotocol.schema.McpSchema.ClientCapabilities;
11+
import io.modelcontextprotocol.schema.McpSchema.GetPromptRequest;
12+
import io.modelcontextprotocol.schema.McpSchema.GetPromptResult;
13+
import io.modelcontextprotocol.schema.McpSchema.ListPromptsResult;
1414
import io.modelcontextprotocol.util.Assert;
1515
import org.slf4j.Logger;
1616
import org.slf4j.LoggerFactory;

mcp-reactor/src/main/java/io/modelcontextprotocol/client/transport/HttpClientSseClientTransport.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
import com.fasterxml.jackson.core.type.TypeReference;
2020
import com.fasterxml.jackson.databind.ObjectMapper;
2121
import io.modelcontextprotocol.client.transport.FlowSseClient.SseEvent;
22+
import io.modelcontextprotocol.schema.McpJacksonCodec;
23+
import io.modelcontextprotocol.schema.McpType;
2224
import io.modelcontextprotocol.spec.McpClientTransport;
2325
import io.modelcontextprotocol.spec.McpError;
24-
import io.modelcontextprotocol.spec.McpSchema;
26+
import io.modelcontextprotocol.schema.McpSchema;
2527
import io.modelcontextprotocol.spec.McpTransport;
26-
import io.modelcontextprotocol.spec.McpSchema.JSONRPCMessage;
28+
import io.modelcontextprotocol.schema.McpSchema.JSONRPCMessage;
2729
import io.modelcontextprotocol.util.Assert;
2830
import io.modelcontextprotocol.util.Utils;
2931

@@ -91,7 +93,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
9193
private final HttpRequest.Builder requestBuilder;
9294

9395
/** JSON object mapper for message serialization/deserialization */
94-
protected ObjectMapper objectMapper;
96+
protected McpJacksonCodec jacksonCodec;
9597

9698
/** Flag indicating if the transport is in closing state */
9799
private volatile boolean isClosing = false;
@@ -184,7 +186,7 @@ public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, HttpReques
184186
Assert.notNull(requestBuilder, "requestBuilder must not be null");
185187
this.baseUri = URI.create(baseUri);
186188
this.sseEndpoint = sseEndpoint;
187-
this.objectMapper = objectMapper;
189+
this.jacksonCodec = new McpJacksonCodec(objectMapper);
188190
this.httpClient = httpClient;
189191
this.requestBuilder = requestBuilder;
190192

@@ -360,7 +362,7 @@ public void onEvent(SseEvent event) {
360362
future.complete(null);
361363
}
362364
else if (MESSAGE_EVENT_TYPE.equals(event.type())) {
363-
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, event.data());
365+
JSONRPCMessage message = jacksonCodec.deserializeJsonRpcMessage(event.data());
364366
Publisher<McpSchema.JSONRPCMessage> result = handler.apply(Mono.just(message));
365367
Mono.from(result).subscribe();
366368
}
@@ -417,7 +419,7 @@ public Mono<Void> sendMessage(JSONRPCMessage message) {
417419
}
418420

419421
try {
420-
String jsonText = this.objectMapper.writeValueAsString(message);
422+
String jsonText = this.jacksonCodec.getMapper().writeValueAsString(message);
421423
URI requestUri = Utils.resolveUri(baseUri, endpoint);
422424
HttpRequest request = this.requestBuilder.uri(requestUri)
423425
.POST(HttpRequest.BodyPublishers.ofString(jsonText))
@@ -471,8 +473,8 @@ public Mono<Void> closeGracefully() {
471473
* @return the unmarshalled object
472474
*/
473475
@Override
474-
public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
475-
return this.objectMapper.convertValue(data, typeRef);
476+
public <T> T unmarshalFrom(Object data, McpType<T> typeRef) {
477+
return jacksonCodec.decodeResult(data, typeRef);
476478
}
477479

478480
}

mcp-reactor/src/main/java/io/modelcontextprotocol/client/transport/StdioClientTransport.java

+11-8
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717

1818
import com.fasterxml.jackson.core.type.TypeReference;
1919
import com.fasterxml.jackson.databind.ObjectMapper;
20+
21+
import io.modelcontextprotocol.schema.McpJacksonCodec;
22+
import io.modelcontextprotocol.schema.McpType;
2023
import io.modelcontextprotocol.spec.McpClientTransport;
21-
import io.modelcontextprotocol.spec.McpSchema;
22-
import io.modelcontextprotocol.spec.McpSchema.JSONRPCMessage;
24+
import io.modelcontextprotocol.schema.McpSchema;
25+
import io.modelcontextprotocol.schema.McpSchema.JSONRPCMessage;
2326
import io.modelcontextprotocol.util.Assert;
2427

2528
import org.reactivestreams.Publisher;
@@ -50,7 +53,7 @@ public class StdioClientTransport implements McpClientTransport {
5053
/** The server process being communicated with */
5154
private Process process;
5255

53-
private ObjectMapper objectMapper;
56+
private McpJacksonCodec jacksonCodec;
5457

5558
/** Scheduler for handling inbound messages from the server process */
5659
private Scheduler inboundScheduler;
@@ -94,7 +97,7 @@ public StdioClientTransport(ServerParameters params, ObjectMapper objectMapper)
9497

9598
this.params = params;
9699

97-
this.objectMapper = objectMapper;
100+
this.jacksonCodec = new McpJacksonCodec(objectMapper);
98101

99102
this.errorSink = Sinks.many().unicast().onBackpressureBuffer();
100103

@@ -260,7 +263,7 @@ private void startInboundProcessing() {
260263
String line;
261264
while (!isClosing && (line = processReader.readLine()) != null) {
262265
try {
263-
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(this.objectMapper, line);
266+
JSONRPCMessage message = jacksonCodec.deserializeJsonRpcMessage(line);
264267
if (!this.inboundSink.tryEmitNext(message).isSuccess()) {
265268
if (!isClosing) {
266269
logger.error("Failed to enqueue inbound message: {}", message);
@@ -301,7 +304,7 @@ private void startOutboundProcessing() {
301304
.handle((message, s) -> {
302305
if (message != null && !isClosing) {
303306
try {
304-
String jsonMessage = objectMapper.writeValueAsString(message);
307+
String jsonMessage = jacksonCodec.getMapper().writeValueAsString(message);
305308
// Escape any embedded newlines in the JSON message as per spec:
306309
// https://spec.modelcontextprotocol.io/specification/basic/transports/#stdio
307310
// - Messages are delimited by newlines, and MUST NOT contain
@@ -395,8 +398,8 @@ public Sinks.Many<String> getErrorSink() {
395398
}
396399

397400
@Override
398-
public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
399-
return this.objectMapper.convertValue(data, typeRef);
401+
public <T> T unmarshalFrom(Object data, McpType<T> typeRef) {
402+
return jacksonCodec.decodeResult(data, typeRef);
400403
}
401404

402405
}

0 commit comments

Comments
 (0)