feat: Introduce McpJsonMapper interface to decouple from Jackson (#543)
This pull request creates two modules, `mcp-json` and `mcp-json-jackson`. It removes the `com.fasterxml.jackson.core:jackson-databind` and `com.networknt:json-schema-validator` dependencies from the `mcp` module. The `mcp` module now only depends on `com.fasterxml.jackson.core:jackson-annotations`. To use Jackson, you have to add `mcp-jackson` to your dependencies in addition to `mcp`. I added the dependency `mcp-jackson` to both `mcp-spring-mvc` and `mcp-spring-webflux` to avoid a breaking change in those modules. It provides two [SPI](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html) `JsonSchemaValidatorSupplier` and `JacksonJsonSchemaValidatorSupplier` to allow easy replacement for consumers who don't want to use Jackson. This pull request also ensures no `McpJsonMapper` is instantiated if one is provided via a builder method. Only if the builders don't receive a `McpJsonMapper` mapper, one is instantiated in the `build` method of the builder. The logic behind this is to allow frameworks to provide a `McpJsonMapper` mapper singleton implementation and feed it to the builders without paying the price of instantiating `McpJsonMappers`, which will not be used. The goal is to be able to use the `ObjectMapper` singleton of an application also for the MCP code. Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
parent
d8959ef854
commit
80d0ad82a6
18 changed files with 2043 additions and 1421 deletions
|
|
@ -22,7 +22,13 @@
|
|||
</scm>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>io.modelcontextprotocol.sdk</groupId>
|
||||
<artifactId>mcp-json-jackson2</artifactId>
|
||||
<version>0.13.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.modelcontextprotocol.sdk</groupId>
|
||||
<artifactId>mcp</artifactId>
|
||||
<version>0.13.0-SNAPSHOT</version>
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ import org.springframework.web.reactive.function.client.ClientResponse;
|
|||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClientResponseException;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
|
||||
import io.modelcontextprotocol.spec.DefaultMcpTransportSession;
|
||||
import io.modelcontextprotocol.spec.DefaultMcpTransportStream;
|
||||
|
|
@ -88,7 +88,7 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
|
|||
private static final ParameterizedTypeReference<ServerSentEvent<String>> PARAMETERIZED_TYPE_REF = new ParameterizedTypeReference<>() {
|
||||
};
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
private final WebClient webClient;
|
||||
|
||||
|
|
@ -104,9 +104,9 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
|
|||
|
||||
private final AtomicReference<Consumer<Throwable>> exceptionHandler = new AtomicReference<>();
|
||||
|
||||
private WebClientStreamableHttpTransport(ObjectMapper objectMapper, WebClient.Builder webClientBuilder,
|
||||
private WebClientStreamableHttpTransport(McpJsonMapper jsonMapper, WebClient.Builder webClientBuilder,
|
||||
String endpoint, boolean resumableStreams, boolean openConnectionOnStartup) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.webClient = webClientBuilder.build();
|
||||
this.endpoint = endpoint;
|
||||
this.resumableStreams = resumableStreams;
|
||||
|
|
@ -366,8 +366,7 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
|
|||
McpSchema.JSONRPCResponse.JSONRPCError jsonRpcError = null;
|
||||
Exception toPropagate;
|
||||
try {
|
||||
McpSchema.JSONRPCResponse jsonRpcResponse = objectMapper.readValue(body,
|
||||
McpSchema.JSONRPCResponse.class);
|
||||
McpSchema.JSONRPCResponse jsonRpcResponse = jsonMapper.readValue(body, McpSchema.JSONRPCResponse.class);
|
||||
jsonRpcError = jsonRpcResponse.error();
|
||||
toPropagate = jsonRpcError != null ? new McpError(jsonRpcError)
|
||||
: new McpTransportException("Can't parse the jsonResponse " + jsonRpcResponse);
|
||||
|
|
@ -427,7 +426,7 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
|
|||
s.complete();
|
||||
}
|
||||
else {
|
||||
McpSchema.JSONRPCMessage jsonRpcResponse = McpSchema.deserializeJsonRpcMessage(objectMapper,
|
||||
McpSchema.JSONRPCMessage jsonRpcResponse = McpSchema.deserializeJsonRpcMessage(jsonMapper,
|
||||
responseMessage);
|
||||
s.next(List.of(jsonRpcResponse));
|
||||
}
|
||||
|
|
@ -447,8 +446,8 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
|
||||
return this.objectMapper.convertValue(data, typeRef);
|
||||
public <T> T unmarshalFrom(Object data, TypeRef<T> typeRef) {
|
||||
return this.jsonMapper.convertValue(data, typeRef);
|
||||
}
|
||||
|
||||
private Tuple2<Optional<String>, Iterable<McpSchema.JSONRPCMessage>> parse(ServerSentEvent<String> event) {
|
||||
|
|
@ -456,7 +455,7 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
|
|||
try {
|
||||
// We don't support batching ATM and probably won't since the next version
|
||||
// considers removing it.
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(this.objectMapper, event.data());
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(this.jsonMapper, event.data());
|
||||
return Tuples.of(Optional.ofNullable(event.id()), List.of(message));
|
||||
}
|
||||
catch (IOException ioException) {
|
||||
|
|
@ -474,7 +473,7 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
|
|||
*/
|
||||
public static class Builder {
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
private WebClient.Builder webClientBuilder;
|
||||
|
||||
|
|
@ -490,13 +489,13 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
|
|||
}
|
||||
|
||||
/**
|
||||
* Configure the {@link ObjectMapper} to use.
|
||||
* @param objectMapper instance to use
|
||||
* Configure the {@link McpJsonMapper} to use.
|
||||
* @param jsonMapper instance to use
|
||||
* @return the builder instance
|
||||
*/
|
||||
public Builder objectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
public Builder jsonMapper(McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -555,10 +554,8 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
|
|||
* @return a new instance of {@link WebClientStreamableHttpTransport}
|
||||
*/
|
||||
public WebClientStreamableHttpTransport build() {
|
||||
ObjectMapper objectMapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
|
||||
|
||||
return new WebClientStreamableHttpTransport(objectMapper, this.webClientBuilder, endpoint, resumableStreams,
|
||||
openConnectionOnStartup);
|
||||
return new WebClientStreamableHttpTransport(jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
webClientBuilder, endpoint, resumableStreams, openConnectionOnStartup);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import java.util.List;
|
|||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
|
||||
import io.modelcontextprotocol.spec.HttpHeaders;
|
||||
import io.modelcontextprotocol.spec.McpClientTransport;
|
||||
|
|
@ -100,10 +100,10 @@ public class WebFluxSseClientTransport implements McpClientTransport {
|
|||
private final WebClient webClient;
|
||||
|
||||
/**
|
||||
* ObjectMapper for serializing outbound messages and deserializing inbound messages.
|
||||
* JSON mapper for serializing outbound messages and deserializing inbound messages.
|
||||
* Handles conversion between JSON-RPC messages and their string representation.
|
||||
*/
|
||||
protected ObjectMapper objectMapper;
|
||||
protected McpJsonMapper jsonMapper;
|
||||
|
||||
/**
|
||||
* Subscription for the SSE connection handling inbound messages. Used for cleanup
|
||||
|
|
@ -129,27 +129,16 @@ public class WebFluxSseClientTransport implements McpClientTransport {
|
|||
*/
|
||||
private String sseEndpoint;
|
||||
|
||||
/**
|
||||
* Constructs a new SseClientTransport with the specified WebClient builder. Uses a
|
||||
* default ObjectMapper instance for JSON processing.
|
||||
* @param webClientBuilder the WebClient.Builder to use for creating the WebClient
|
||||
* instance
|
||||
* @throws IllegalArgumentException if webClientBuilder is null
|
||||
*/
|
||||
public WebFluxSseClientTransport(WebClient.Builder webClientBuilder) {
|
||||
this(webClientBuilder, new ObjectMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new SseClientTransport with the specified WebClient builder and
|
||||
* ObjectMapper. Initializes both inbound and outbound message processing pipelines.
|
||||
* @param webClientBuilder the WebClient.Builder to use for creating the WebClient
|
||||
* instance
|
||||
* @param objectMapper the ObjectMapper to use for JSON processing
|
||||
* @param jsonMapper the ObjectMapper to use for JSON processing
|
||||
* @throws IllegalArgumentException if either parameter is null
|
||||
*/
|
||||
public WebFluxSseClientTransport(WebClient.Builder webClientBuilder, ObjectMapper objectMapper) {
|
||||
this(webClientBuilder, objectMapper, DEFAULT_SSE_ENDPOINT);
|
||||
public WebFluxSseClientTransport(WebClient.Builder webClientBuilder, McpJsonMapper jsonMapper) {
|
||||
this(webClientBuilder, jsonMapper, DEFAULT_SSE_ENDPOINT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -157,17 +146,16 @@ public class WebFluxSseClientTransport implements McpClientTransport {
|
|||
* ObjectMapper. Initializes both inbound and outbound message processing pipelines.
|
||||
* @param webClientBuilder the WebClient.Builder to use for creating the WebClient
|
||||
* instance
|
||||
* @param objectMapper the ObjectMapper to use for JSON processing
|
||||
* @param jsonMapper the ObjectMapper to use for JSON processing
|
||||
* @param sseEndpoint the SSE endpoint URI to use for establishing the connection
|
||||
* @throws IllegalArgumentException if either parameter is null
|
||||
*/
|
||||
public WebFluxSseClientTransport(WebClient.Builder webClientBuilder, ObjectMapper objectMapper,
|
||||
String sseEndpoint) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
public WebFluxSseClientTransport(WebClient.Builder webClientBuilder, McpJsonMapper jsonMapper, String sseEndpoint) {
|
||||
Assert.notNull(jsonMapper, "jsonMapper must not be null");
|
||||
Assert.notNull(webClientBuilder, "WebClient.Builder must not be null");
|
||||
Assert.hasText(sseEndpoint, "SSE endpoint must not be null or empty");
|
||||
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.webClient = webClientBuilder.build();
|
||||
this.sseEndpoint = sseEndpoint;
|
||||
}
|
||||
|
|
@ -217,7 +205,7 @@ public class WebFluxSseClientTransport implements McpClientTransport {
|
|||
}
|
||||
else if (MESSAGE_EVENT_TYPE.equals(event.event())) {
|
||||
try {
|
||||
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(this.objectMapper, event.data());
|
||||
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(this.jsonMapper, event.data());
|
||||
s.next(message);
|
||||
}
|
||||
catch (IOException ioException) {
|
||||
|
|
@ -255,7 +243,7 @@ public class WebFluxSseClientTransport implements McpClientTransport {
|
|||
return Mono.empty();
|
||||
}
|
||||
try {
|
||||
String jsonText = this.objectMapper.writeValueAsString(message);
|
||||
String jsonText = this.jsonMapper.writeValueAsString(message);
|
||||
return webClient.post()
|
||||
.uri(messageEndpointUri)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -349,13 +337,13 @@ public class WebFluxSseClientTransport implements McpClientTransport {
|
|||
* type conversion capabilities to handle complex object structures.
|
||||
* @param <T> the target type to convert the data into
|
||||
* @param data the source object to convert
|
||||
* @param typeRef the TypeReference describing the target type
|
||||
* @param typeRef the TypeRef describing the target type
|
||||
* @return the unmarshalled object of type T
|
||||
* @throws IllegalArgumentException if the conversion cannot be performed
|
||||
*/
|
||||
@Override
|
||||
public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
|
||||
return this.objectMapper.convertValue(data, typeRef);
|
||||
public <T> T unmarshalFrom(Object data, TypeRef<T> typeRef) {
|
||||
return this.jsonMapper.convertValue(data, typeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -377,7 +365,7 @@ public class WebFluxSseClientTransport implements McpClientTransport {
|
|||
|
||||
private String sseEndpoint = DEFAULT_SSE_ENDPOINT;
|
||||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
/**
|
||||
* Creates a new builder with the specified WebClient.Builder.
|
||||
|
|
@ -400,13 +388,13 @@ public class WebFluxSseClientTransport implements McpClientTransport {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the object mapper for JSON serialization/deserialization.
|
||||
* @param objectMapper the object mapper
|
||||
* Sets the JSON mapper for serialization/deserialization.
|
||||
* @param jsonMapper the JsonMapper to use
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder objectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "objectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
public Builder jsonMapper(McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "jsonMapper must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -415,7 +403,8 @@ public class WebFluxSseClientTransport implements McpClientTransport {
|
|||
* @return a new transport instance
|
||||
*/
|
||||
public WebFluxSseClientTransport build() {
|
||||
return new WebFluxSseClientTransport(webClientBuilder, objectMapper, sseEndpoint);
|
||||
return new WebFluxSseClientTransport(webClientBuilder,
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, sseEndpoint);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import java.time.Duration;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
|
|
@ -97,7 +97,7 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
|
||||
public static final String DEFAULT_BASE_URL = "";
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
/**
|
||||
* Base URL for the message endpoint. This is used to construct the full URL for
|
||||
|
|
@ -131,82 +131,10 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
*/
|
||||
private KeepAliveScheduler keepAliveScheduler;
|
||||
|
||||
/**
|
||||
* Constructs a new WebFlux SSE server transport provider instance with the default
|
||||
* SSE endpoint.
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
* of MCP messages. Must not be null.
|
||||
* @param messageEndpoint The endpoint URI where clients should send their JSON-RPC
|
||||
* messages. This endpoint will be communicated to clients during SSE connection
|
||||
* setup. Must not be null.
|
||||
* @throws IllegalArgumentException if either parameter is null
|
||||
* @deprecated Use the builder {@link #builder()} instead for better configuration
|
||||
* options.
|
||||
*/
|
||||
@Deprecated
|
||||
public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint) {
|
||||
this(objectMapper, messageEndpoint, DEFAULT_SSE_ENDPOINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new WebFlux SSE server transport provider instance.
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
* of MCP messages. Must not be null.
|
||||
* @param messageEndpoint The endpoint URI where clients should send their JSON-RPC
|
||||
* messages. This endpoint will be communicated to clients during SSE connection
|
||||
* setup. Must not be null.
|
||||
* @throws IllegalArgumentException if either parameter is null
|
||||
* @deprecated Use the builder {@link #builder()} instead for better configuration
|
||||
* options.
|
||||
*/
|
||||
@Deprecated
|
||||
public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint, String sseEndpoint) {
|
||||
this(objectMapper, DEFAULT_BASE_URL, messageEndpoint, sseEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new WebFlux SSE server transport provider instance.
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
* of MCP messages. Must not be null.
|
||||
* @param baseUrl webflux message base path
|
||||
* @param messageEndpoint The endpoint URI where clients should send their JSON-RPC
|
||||
* messages. This endpoint will be communicated to clients during SSE connection
|
||||
* setup. Must not be null.
|
||||
* @throws IllegalArgumentException if either parameter is null
|
||||
* @deprecated Use the builder {@link #builder()} instead for better configuration
|
||||
* options.
|
||||
*/
|
||||
@Deprecated
|
||||
public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
|
||||
String sseEndpoint) {
|
||||
this(objectMapper, baseUrl, messageEndpoint, sseEndpoint, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new WebFlux SSE server transport provider instance.
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
* of MCP messages. Must not be null.
|
||||
* @param baseUrl webflux message base path
|
||||
* @param messageEndpoint The endpoint URI where clients should send their JSON-RPC
|
||||
* messages. This endpoint will be communicated to clients during SSE connection
|
||||
* setup. Must not be null.
|
||||
* @param sseEndpoint The SSE endpoint path. Must not be null.
|
||||
* @param keepAliveInterval The interval for sending keep-alive pings to clients.
|
||||
* @throws IllegalArgumentException if either parameter is null
|
||||
* @deprecated Use the builder {@link #builder()} instead for better configuration
|
||||
* options.
|
||||
*/
|
||||
@Deprecated
|
||||
public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
|
||||
String sseEndpoint, Duration keepAliveInterval) {
|
||||
this(objectMapper, baseUrl, messageEndpoint, sseEndpoint, keepAliveInterval,
|
||||
(serverRequest) -> McpTransportContext.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new WebFlux SSE server transport provider instance.
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
* of MCP messages. Must not be null.
|
||||
* @param jsonMapper The ObjectMapper to use for JSON serialization/deserialization of
|
||||
* MCP messages. Must not be null.
|
||||
* @param baseUrl webflux message base path
|
||||
* @param messageEndpoint The endpoint URI where clients should send their JSON-RPC
|
||||
* messages. This endpoint will be communicated to clients during SSE connection
|
||||
|
|
@ -217,16 +145,16 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
* context from HTTP requests. Must not be null.
|
||||
* @throws IllegalArgumentException if either parameter is null
|
||||
*/
|
||||
private WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
|
||||
private WebFluxSseServerTransportProvider(McpJsonMapper jsonMapper, String baseUrl, String messageEndpoint,
|
||||
String sseEndpoint, Duration keepAliveInterval,
|
||||
McpTransportContextExtractor<ServerRequest> contextExtractor) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
Assert.notNull(jsonMapper, "ObjectMapper must not be null");
|
||||
Assert.notNull(baseUrl, "Message base path must not be null");
|
||||
Assert.notNull(messageEndpoint, "Message endpoint must not be null");
|
||||
Assert.notNull(sseEndpoint, "SSE endpoint must not be null");
|
||||
Assert.notNull(contextExtractor, "Context extractor must not be null");
|
||||
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.baseUrl = baseUrl;
|
||||
this.messageEndpoint = messageEndpoint;
|
||||
this.sseEndpoint = sseEndpoint;
|
||||
|
|
@ -404,7 +332,7 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
|
||||
return request.bodyToMono(String.class).flatMap(body -> {
|
||||
try {
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, body);
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(jsonMapper, body);
|
||||
return session.handle(message).flatMap(response -> ServerResponse.ok().build()).onErrorResume(error -> {
|
||||
logger.error("Error processing message: {}", error.getMessage());
|
||||
// TODO: instead of signalling the error, just respond with 200 OK
|
||||
|
|
@ -433,7 +361,7 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
|
||||
return Mono.fromSupplier(() -> {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(message);
|
||||
return jsonMapper.writeValueAsString(message);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw Exceptions.propagate(e);
|
||||
|
|
@ -452,8 +380,8 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
|
||||
return objectMapper.convertValue(data, typeRef);
|
||||
public <T> T unmarshalFrom(Object data, TypeRef<T> typeRef) {
|
||||
return jsonMapper.convertValue(data, typeRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -480,7 +408,7 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
*/
|
||||
public static class Builder {
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
private String baseUrl = DEFAULT_BASE_URL;
|
||||
|
||||
|
|
@ -494,15 +422,15 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
serverRequest) -> McpTransportContext.EMPTY;
|
||||
|
||||
/**
|
||||
* Sets the ObjectMapper to use for JSON serialization/deserialization of MCP
|
||||
* Sets the McpJsonMapper to use for JSON serialization/deserialization of MCP
|
||||
* messages.
|
||||
* @param objectMapper The ObjectMapper instance. Must not be null.
|
||||
* @param jsonMapper The McpJsonMapper instance. Must not be null.
|
||||
* @return this builder instance
|
||||
* @throws IllegalArgumentException if objectMapper is null
|
||||
* @throws IllegalArgumentException if jsonMapper is null
|
||||
*/
|
||||
public Builder objectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
public Builder jsonMapper(McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -577,11 +505,9 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
* @throws IllegalStateException if required parameters are not set
|
||||
*/
|
||||
public WebFluxSseServerTransportProvider build() {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must be set");
|
||||
Assert.notNull(messageEndpoint, "Message endpoint must be set");
|
||||
|
||||
return new WebFluxSseServerTransportProvider(objectMapper, baseUrl, messageEndpoint, sseEndpoint,
|
||||
keepAliveInterval, contextExtractor);
|
||||
return new WebFluxSseServerTransportProvider(jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
baseUrl, messageEndpoint, sseEndpoint, keepAliveInterval, contextExtractor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package io.modelcontextprotocol.server.transport;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpStatelessServerHandler;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
|
|
@ -34,7 +34,7 @@ public class WebFluxStatelessServerTransport implements McpStatelessServerTransp
|
|||
|
||||
private static final Logger logger = LoggerFactory.getLogger(WebFluxStatelessServerTransport.class);
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
private final String mcpEndpoint;
|
||||
|
||||
|
|
@ -46,13 +46,13 @@ public class WebFluxStatelessServerTransport implements McpStatelessServerTransp
|
|||
|
||||
private volatile boolean isClosing = false;
|
||||
|
||||
private WebFluxStatelessServerTransport(ObjectMapper objectMapper, String mcpEndpoint,
|
||||
private WebFluxStatelessServerTransport(McpJsonMapper jsonMapper, String mcpEndpoint,
|
||||
McpTransportContextExtractor<ServerRequest> contextExtractor) {
|
||||
Assert.notNull(objectMapper, "objectMapper must not be null");
|
||||
Assert.notNull(jsonMapper, "jsonMapper must not be null");
|
||||
Assert.notNull(mcpEndpoint, "mcpEndpoint must not be null");
|
||||
Assert.notNull(contextExtractor, "contextExtractor must not be null");
|
||||
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.mcpEndpoint = mcpEndpoint;
|
||||
this.contextExtractor = contextExtractor;
|
||||
this.routerFunction = RouterFunctions.route()
|
||||
|
|
@ -106,13 +106,20 @@ public class WebFluxStatelessServerTransport implements McpStatelessServerTransp
|
|||
|
||||
return request.bodyToMono(String.class).<ServerResponse>flatMap(body -> {
|
||||
try {
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, body);
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(jsonMapper, body);
|
||||
|
||||
if (message instanceof McpSchema.JSONRPCRequest jsonrpcRequest) {
|
||||
return this.mcpHandler.handleRequest(transportContext, jsonrpcRequest)
|
||||
.flatMap(jsonrpcResponse -> ServerResponse.ok()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(jsonrpcResponse));
|
||||
return this.mcpHandler.handleRequest(transportContext, jsonrpcRequest).flatMap(jsonrpcResponse -> {
|
||||
try {
|
||||
String json = jsonMapper.writeValueAsString(jsonrpcResponse);
|
||||
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).bodyValue(json);
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.error("Failed to serialize response: {}", e.getMessage());
|
||||
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.bodyValue(new McpError("Failed to serialize response"));
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (message instanceof McpSchema.JSONRPCNotification jsonrpcNotification) {
|
||||
return this.mcpHandler.handleNotification(transportContext, jsonrpcNotification)
|
||||
|
|
@ -146,7 +153,7 @@ public class WebFluxStatelessServerTransport implements McpStatelessServerTransp
|
|||
*/
|
||||
public static class Builder {
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
private String mcpEndpoint = "/mcp";
|
||||
|
||||
|
|
@ -158,15 +165,15 @@ public class WebFluxStatelessServerTransport implements McpStatelessServerTransp
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the ObjectMapper to use for JSON serialization/deserialization of MCP
|
||||
* Sets the JsonMapper to use for JSON serialization/deserialization of MCP
|
||||
* messages.
|
||||
* @param objectMapper The ObjectMapper instance. Must not be null.
|
||||
* @param jsonMapper The JsonMapper instance. Must not be null.
|
||||
* @return this builder instance
|
||||
* @throws IllegalArgumentException if objectMapper is null
|
||||
* @throws IllegalArgumentException if jsonMapper is null
|
||||
*/
|
||||
public Builder objectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
public Builder jsonMapper(McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -205,10 +212,9 @@ public class WebFluxStatelessServerTransport implements McpStatelessServerTransp
|
|||
* @throws IllegalStateException if required parameters are not set
|
||||
*/
|
||||
public WebFluxStatelessServerTransport build() {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must be set");
|
||||
Assert.notNull(mcpEndpoint, "Message endpoint must be set");
|
||||
|
||||
return new WebFluxStatelessServerTransport(objectMapper, mcpEndpoint, contextExtractor);
|
||||
return new WebFluxStatelessServerTransport(jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
mcpEndpoint, contextExtractor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
package io.modelcontextprotocol.server.transport;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
import io.modelcontextprotocol.spec.HttpHeaders;
|
||||
|
|
@ -49,7 +49,7 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
|
||||
public static final String MESSAGE_EVENT_TYPE = "message";
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
private final String mcpEndpoint;
|
||||
|
||||
|
|
@ -67,14 +67,14 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
|
||||
private KeepAliveScheduler keepAliveScheduler;
|
||||
|
||||
private WebFluxStreamableServerTransportProvider(ObjectMapper objectMapper, String mcpEndpoint,
|
||||
private WebFluxStreamableServerTransportProvider(McpJsonMapper jsonMapper, String mcpEndpoint,
|
||||
McpTransportContextExtractor<ServerRequest> contextExtractor, boolean disallowDelete,
|
||||
Duration keepAliveInterval) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
Assert.notNull(mcpEndpoint, "Message endpoint must not be null");
|
||||
Assert.notNull(contextExtractor, "Context extractor must not be null");
|
||||
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.mcpEndpoint = mcpEndpoint;
|
||||
this.contextExtractor = contextExtractor;
|
||||
this.disallowDelete = disallowDelete;
|
||||
|
|
@ -230,12 +230,13 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
|
||||
return request.bodyToMono(String.class).<ServerResponse>flatMap(body -> {
|
||||
try {
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, body);
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(jsonMapper, body);
|
||||
if (message instanceof McpSchema.JSONRPCRequest jsonrpcRequest
|
||||
&& jsonrpcRequest.method().equals(McpSchema.METHOD_INITIALIZE)) {
|
||||
McpSchema.InitializeRequest initializeRequest = objectMapper.convertValue(jsonrpcRequest.params(),
|
||||
new TypeReference<McpSchema.InitializeRequest>() {
|
||||
});
|
||||
var typeReference = new TypeRef<McpSchema.InitializeRequest>() {
|
||||
};
|
||||
McpSchema.InitializeRequest initializeRequest = jsonMapper.convertValue(jsonrpcRequest.params(),
|
||||
typeReference);
|
||||
McpStreamableServerSession.McpStreamableServerSessionInit init = this.sessionFactory
|
||||
.startSession(initializeRequest);
|
||||
sessions.put(init.session().getId(), init.session());
|
||||
|
|
@ -243,7 +244,7 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
McpSchema.JSONRPCResponse jsonrpcResponse = new McpSchema.JSONRPCResponse(
|
||||
McpSchema.JSONRPC_VERSION, jsonrpcRequest.id(), initializeResult, null);
|
||||
try {
|
||||
return this.objectMapper.writeValueAsString(jsonrpcResponse);
|
||||
return this.jsonMapper.writeValueAsString(jsonrpcResponse);
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.warn("Failed to serialize initResponse", e);
|
||||
|
|
@ -349,7 +350,7 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message, String messageId) {
|
||||
return Mono.fromSupplier(() -> {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(message);
|
||||
return jsonMapper.writeValueAsString(message);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw Exceptions.propagate(e);
|
||||
|
|
@ -369,8 +370,8 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
|
||||
return objectMapper.convertValue(data, typeRef);
|
||||
public <T> T unmarshalFrom(Object data, TypeRef<T> typeRef) {
|
||||
return jsonMapper.convertValue(data, typeRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -397,7 +398,7 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
*/
|
||||
public static class Builder {
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
private String mcpEndpoint = "/mcp";
|
||||
|
||||
|
|
@ -413,15 +414,15 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the ObjectMapper to use for JSON serialization/deserialization of MCP
|
||||
* messages.
|
||||
* @param objectMapper The ObjectMapper instance. Must not be null.
|
||||
* Sets the {@link McpJsonMapper} to use for JSON serialization/deserialization of
|
||||
* MCP messages.
|
||||
* @param jsonMapper The {@link McpJsonMapper} instance. Must not be null.
|
||||
* @return this builder instance
|
||||
* @throws IllegalArgumentException if objectMapper is null
|
||||
* @throws IllegalArgumentException if jsonMapper is null
|
||||
*/
|
||||
public Builder objectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
public Builder jsonMapper(McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "McpJsonMapper must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -482,13 +483,12 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
* @throws IllegalStateException if required parameters are not set
|
||||
*/
|
||||
public WebFluxStreamableServerTransportProvider build() {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must be set");
|
||||
Assert.notNull(mcpEndpoint, "Message endpoint must be set");
|
||||
|
||||
return new WebFluxStreamableServerTransportProvider(objectMapper, mcpEndpoint, contextExtractor,
|
||||
return new WebFluxStreamableServerTransportProvider(
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, mcpEndpoint, contextExtractor,
|
||||
disallowDelete, keepAliveInterval);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ import org.springframework.web.reactive.function.client.WebClient;
|
|||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
|
||||
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
|
||||
|
|
@ -79,7 +77,6 @@ class WebFluxSseIntegrationTests extends AbstractMcpClientServerIntegrationTests
|
|||
public void before() {
|
||||
|
||||
this.mcpServerTransportProvider = new WebFluxSseServerTransportProvider.Builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(CUSTOM_MESSAGE_ENDPOINT)
|
||||
.sseEndpoint(CUSTOM_SSE_ENDPOINT)
|
||||
.contextExtractor(TEST_CONTEXT_EXTRACTOR)
|
||||
|
|
|
|||
|
|
@ -13,9 +13,6 @@ import org.springframework.http.server.reactive.HttpHandler;
|
|||
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport;
|
||||
import io.modelcontextprotocol.client.transport.WebClientStreamableHttpTransport;
|
||||
|
|
@ -67,7 +64,6 @@ class WebFluxStatelessIntegrationTests extends AbstractStatelessIntegrationTests
|
|||
@BeforeEach
|
||||
public void before() {
|
||||
this.mcpStreamableServerTransport = WebFluxStatelessServerTransport.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(CUSTOM_MESSAGE_ENDPOINT)
|
||||
.build();
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ import org.springframework.web.reactive.function.client.WebClient;
|
|||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport;
|
||||
import io.modelcontextprotocol.client.transport.WebClientStreamableHttpTransport;
|
||||
|
|
@ -76,7 +74,6 @@ class WebFluxStreamableIntegrationTests extends AbstractMcpClientServerIntegrati
|
|||
public void before() {
|
||||
|
||||
this.mcpStreamableServerTransportProvider = WebFluxStreamableServerTransportProvider.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(CUSTOM_MESSAGE_ENDPOINT)
|
||||
.contextExtractor(TEST_CONTEXT_EXTRACTOR)
|
||||
.build();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import org.junit.jupiter.api.BeforeAll;
|
|||
import org.junit.jupiter.api.Timeout;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import java.util.function.Function;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.jackson.JacksonMcpJsonMapper;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.JSONRPCRequest;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
|
|
@ -29,6 +31,7 @@ import reactor.test.StepVerifier;
|
|||
import org.springframework.http.codec.ServerSentEvent;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static io.modelcontextprotocol.utils.McpJsonMapperUtils.JSON_MAPPER;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
|
@ -54,8 +57,6 @@ class WebFluxSseClientTransportTests {
|
|||
|
||||
private WebClient.Builder webClientBuilder;
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
// Test class to access protected methods
|
||||
static class TestSseClientTransport extends WebFluxSseClientTransport {
|
||||
|
||||
|
|
@ -63,8 +64,8 @@ class WebFluxSseClientTransportTests {
|
|||
|
||||
private Sinks.Many<ServerSentEvent<String>> events = Sinks.many().unicast().onBackpressureBuffer();
|
||||
|
||||
public TestSseClientTransport(WebClient.Builder webClientBuilder, ObjectMapper objectMapper) {
|
||||
super(webClientBuilder, objectMapper);
|
||||
public TestSseClientTransport(WebClient.Builder webClientBuilder, McpJsonMapper jsonMapper) {
|
||||
super(webClientBuilder, jsonMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -112,8 +113,7 @@ class WebFluxSseClientTransportTests {
|
|||
@BeforeEach
|
||||
void setUp() {
|
||||
webClientBuilder = WebClient.builder().baseUrl(host);
|
||||
objectMapper = new ObjectMapper();
|
||||
transport = new TestSseClientTransport(webClientBuilder, objectMapper);
|
||||
transport = new TestSseClientTransport(webClientBuilder, JSON_MAPPER);
|
||||
transport.connect(Function.identity()).block();
|
||||
}
|
||||
|
||||
|
|
@ -131,12 +131,13 @@ class WebFluxSseClientTransportTests {
|
|||
|
||||
@Test
|
||||
void constructorValidation() {
|
||||
assertThatThrownBy(() -> new WebFluxSseClientTransport(null)).isInstanceOf(IllegalArgumentException.class)
|
||||
assertThatThrownBy(() -> new WebFluxSseClientTransport(null, JSON_MAPPER))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("WebClient.Builder must not be null");
|
||||
|
||||
assertThatThrownBy(() -> new WebFluxSseClientTransport(webClientBuilder, null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("ObjectMapper must not be null");
|
||||
.hasMessageContaining("jsonMapper must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -148,7 +149,7 @@ class WebFluxSseClientTransportTests {
|
|||
// Test builder with custom ObjectMapper
|
||||
ObjectMapper customMapper = new ObjectMapper();
|
||||
WebFluxSseClientTransport transport2 = WebFluxSseClientTransport.builder(webClientBuilder)
|
||||
.objectMapper(customMapper)
|
||||
.jsonMapper(new JacksonMcpJsonMapper(customMapper))
|
||||
.build();
|
||||
assertThatCode(() -> transport2.closeGracefully().block()).doesNotThrowAnyException();
|
||||
|
||||
|
|
@ -160,7 +161,6 @@ class WebFluxSseClientTransportTests {
|
|||
|
||||
// Test builder with all custom parameters
|
||||
WebFluxSseClientTransport transport4 = WebFluxSseClientTransport.builder(webClientBuilder)
|
||||
.objectMapper(customMapper)
|
||||
.sseEndpoint("/custom-sse")
|
||||
.build();
|
||||
assertThatCode(() -> transport4.closeGracefully().block()).doesNotThrowAnyException();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ package io.modelcontextprotocol.common;
|
|||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.client.McpAsyncClient;
|
||||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.transport.WebClientStreamableHttpTransport;
|
||||
|
|
@ -110,18 +109,15 @@ public class AsyncServerMcpTransportContextIntegrationTests {
|
|||
|
||||
// Server transports
|
||||
private final WebFluxStatelessServerTransport statelessServerTransport = WebFluxStatelessServerTransport.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.contextExtractor(serverContextExtractor)
|
||||
.build();
|
||||
|
||||
private final WebFluxStreamableServerTransportProvider streamableServerTransport = WebFluxStreamableServerTransportProvider
|
||||
.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.contextExtractor(serverContextExtractor)
|
||||
.build();
|
||||
|
||||
private final WebFluxSseServerTransportProvider sseServerTransport = WebFluxSseServerTransportProvider.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.contextExtractor(serverContextExtractor)
|
||||
.messageEndpoint("/mcp/message")
|
||||
.build();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import java.util.Map;
|
|||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.McpSyncClient;
|
||||
import io.modelcontextprotocol.client.transport.WebClientStreamableHttpTransport;
|
||||
|
|
@ -105,18 +104,15 @@ public class SyncServerMcpTransportContextIntegrationTests {
|
|||
};
|
||||
|
||||
private final WebFluxStatelessServerTransport statelessServerTransport = WebFluxStatelessServerTransport.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.contextExtractor(serverContextExtractor)
|
||||
.build();
|
||||
|
||||
private final WebFluxStreamableServerTransportProvider streamableServerTransport = WebFluxStreamableServerTransportProvider
|
||||
.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.contextExtractor(serverContextExtractor)
|
||||
.build();
|
||||
|
||||
private final WebFluxSseServerTransportProvider sseServerTransport = WebFluxSseServerTransportProvider.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.contextExtractor(serverContextExtractor)
|
||||
.messageEndpoint("/mcp/message")
|
||||
.build();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.McpServerTransportProvider;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
|
@ -30,8 +29,7 @@ class WebFluxSseMcpAsyncServerTests extends AbstractMcpAsyncServerTests {
|
|||
private DisposableServer httpServer;
|
||||
|
||||
private McpServerTransportProvider createMcpTransportProvider() {
|
||||
var transportProvider = new WebFluxSseServerTransportProvider.Builder().objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(MESSAGE_ENDPOINT)
|
||||
var transportProvider = new WebFluxSseServerTransportProvider.Builder().messageEndpoint(MESSAGE_ENDPOINT)
|
||||
.build();
|
||||
|
||||
HttpHandler httpHandler = RouterFunctions.toHttpHandler(transportProvider.getRouterFunction());
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.McpServerTransportProvider;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
|
@ -37,9 +36,7 @@ class WebFluxSseMcpSyncServerTests extends AbstractMcpSyncServerTests {
|
|||
}
|
||||
|
||||
private McpServerTransportProvider createMcpTransportProvider() {
|
||||
transportProvider = new WebFluxSseServerTransportProvider.Builder().objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(MESSAGE_ENDPOINT)
|
||||
.build();
|
||||
transportProvider = new WebFluxSseServerTransportProvider.Builder().messageEndpoint(MESSAGE_ENDPOINT).build();
|
||||
return transportProvider;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.server.transport.WebFluxStreamableServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
|
@ -32,7 +31,6 @@ class WebFluxStreamableMcpAsyncServerTests extends AbstractMcpAsyncServerTests {
|
|||
|
||||
private McpStreamableServerTransportProvider createMcpTransportProvider() {
|
||||
var transportProvider = WebFluxStreamableServerTransportProvider.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(MESSAGE_ENDPOINT)
|
||||
.build();
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.server.transport.WebFluxStreamableServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
|
@ -32,7 +31,6 @@ class WebFluxStreamableMcpSyncServerTests extends AbstractMcpSyncServerTests {
|
|||
|
||||
private McpStreamableServerTransportProvider createMcpTransportProvider() {
|
||||
var transportProvider = WebFluxStreamableServerTransportProvider.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(MESSAGE_ENDPOINT)
|
||||
.build();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package io.modelcontextprotocol.utils;
|
||||
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
|
||||
public final class McpJsonMapperUtils {
|
||||
|
||||
private McpJsonMapperUtils() {
|
||||
}
|
||||
|
||||
public static final McpJsonMapper JSON_MAPPER = McpJsonMapper.createDefault();
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue