Skip to content

Commit 9d7ed54

Browse files
committed
feat: adds mcp-schema-jackson
1 parent c91f731 commit 9d7ed54

File tree

61 files changed

+2001
-1047
lines changed

Some content is hidden

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

61 files changed

+2001
-1047
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

+8-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
</parent>
1111
<artifactId>mcp-reactor</artifactId>
1212
<packaging>jar</packaging>
13-
<name>Java MCP Reactor SDK</name>
14-
<description>Java Reactor SDK implementation of the Model Context Protocol, enabling seamless integration with language models and AI tools</description>
13+
<name>Java SDK MCP Reactor</name>
14+
<description>Java SDK Reactor implementation of the Model Context Protocol, enabling seamless integration with language models and AI tools</description>
1515
<url>https://github.com/modelcontextprotocol/java-sdk</url>
1616

1717
<scm>
@@ -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

+56-11
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616
import java.util.function.Consumer;
1717
import java.util.function.Function;
1818

19-
import com.fasterxml.jackson.core.type.TypeReference;
2019
import com.fasterxml.jackson.databind.ObjectMapper;
2120
import io.modelcontextprotocol.client.transport.FlowSseClient.SseEvent;
21+
import io.modelcontextprotocol.schema.McpJacksonCodec;
22+
import io.modelcontextprotocol.schema.McpSchemaCodec;
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

@@ -90,8 +92,8 @@ public class HttpClientSseClientTransport implements McpClientTransport {
9092
/** HTTP request builder for building requests to send messages to the server */
9193
private final HttpRequest.Builder requestBuilder;
9294

93-
/** JSON object mapper for message serialization/deserialization */
94-
protected ObjectMapper objectMapper;
95+
/** McpSchemaCodec for message serialization/deserialization */
96+
protected McpSchemaCodec schemaCodec;
9597

9698
/** Flag indicating if the transport is in closing state */
9799
private volatile boolean isClosing = false;
@@ -184,7 +186,33 @@ 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.schemaCodec = new McpJacksonCodec(objectMapper);
190+
this.httpClient = httpClient;
191+
this.requestBuilder = requestBuilder;
192+
193+
this.sseClient = new FlowSseClient(this.httpClient, requestBuilder);
194+
}
195+
196+
/**
197+
* Creates a new transport instance with custom HTTP client builder, object mapper,
198+
* and headers.
199+
* @param httpClient the HTTP client to use
200+
* @param requestBuilder the HTTP request builder to use
201+
* @param baseUri the base URI of the MCP server
202+
* @param sseEndpoint the SSE endpoint path
203+
* @param schemaCodec the schemaCodec for JSON serialization/deserialization
204+
* @throws IllegalArgumentException if objectMapper, clientBuilder, or headers is null
205+
*/
206+
HttpClientSseClientTransport(HttpClient httpClient, HttpRequest.Builder requestBuilder, String baseUri,
207+
String sseEndpoint, McpSchemaCodec schemaCodec) {
208+
Assert.notNull(schemaCodec, "ObjectMapper must not be null");
209+
Assert.hasText(baseUri, "baseUri must not be empty");
210+
Assert.hasText(sseEndpoint, "sseEndpoint must not be empty");
211+
Assert.notNull(httpClient, "httpClient must not be null");
212+
Assert.notNull(requestBuilder, "requestBuilder must not be null");
213+
this.baseUri = URI.create(baseUri);
214+
this.sseEndpoint = sseEndpoint;
215+
this.schemaCodec = schemaCodec;
188216
this.httpClient = httpClient;
189217
this.requestBuilder = requestBuilder;
190218

@@ -215,6 +243,8 @@ public static class Builder {
215243

216244
private ObjectMapper objectMapper = new ObjectMapper();
217245

246+
private McpSchemaCodec schemaCodec;
247+
218248
private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
219249
.header("Content-Type", "application/json");
220250

@@ -315,13 +345,28 @@ public Builder objectMapper(ObjectMapper objectMapper) {
315345
return this;
316346
}
317347

348+
/**
349+
* Sets the schema codec for JSON serialization/deserialization.
350+
* @param schemaCodec the McpSchemaCodec implementation
351+
* @return this builder
352+
*/
353+
public Builder withSchemaCodec(final McpSchemaCodec schemaCodec) {
354+
Assert.notNull(schemaCodec, "McpSchemaCodec must not be null");
355+
this.schemaCodec = schemaCodec;
356+
return this;
357+
}
358+
318359
/**
319360
* Builds a new {@link HttpClientSseClientTransport} instance.
320361
* @return a new transport instance
321362
*/
322363
public HttpClientSseClientTransport build() {
364+
if (schemaCodec == null) {
365+
schemaCodec = new McpJacksonCodec(objectMapper);
366+
}
367+
323368
return new HttpClientSseClientTransport(clientBuilder.build(), requestBuilder, baseUri, sseEndpoint,
324-
objectMapper);
369+
schemaCodec);
325370
}
326371

327372
}
@@ -360,7 +405,7 @@ public void onEvent(SseEvent event) {
360405
future.complete(null);
361406
}
362407
else if (MESSAGE_EVENT_TYPE.equals(event.type())) {
363-
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, event.data());
408+
JSONRPCMessage message = schemaCodec.decodeFromString(event.data());
364409
Publisher<McpSchema.JSONRPCMessage> result = handler.apply(Mono.just(message));
365410
Mono.from(result).subscribe();
366411
}
@@ -417,7 +462,7 @@ public Mono<Void> sendMessage(JSONRPCMessage message) {
417462
}
418463

419464
try {
420-
String jsonText = this.objectMapper.writeValueAsString(message);
465+
String jsonText = this.schemaCodec.encodeAsString(message);
421466
URI requestUri = Utils.resolveUri(baseUri, endpoint);
422467
HttpRequest request = this.requestBuilder.uri(requestUri)
423468
.POST(HttpRequest.BodyPublishers.ofString(jsonText))
@@ -471,8 +516,8 @@ public Mono<Void> closeGracefully() {
471516
* @return the unmarshalled object
472517
*/
473518
@Override
474-
public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
475-
return this.objectMapper.convertValue(data, typeRef);
519+
public <T> T unmarshalFrom(Object data, McpType<T> typeRef) {
520+
return schemaCodec.decodeResult(data, typeRef);
476521
}
477522

478523
}

0 commit comments

Comments
 (0)