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
22 changed files with 2043 additions and 1421 deletions
|
|
@ -18,11 +18,10 @@ import java.util.function.Function;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
|
||||
import io.modelcontextprotocol.spec.McpClientSession;
|
||||
import io.modelcontextprotocol.spec.McpClientTransport;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.ClientCapabilities;
|
||||
import io.modelcontextprotocol.spec.McpSchema.CreateMessageRequest;
|
||||
|
|
@ -85,25 +84,25 @@ public class McpAsyncClient {
|
|||
|
||||
private static final Logger logger = LoggerFactory.getLogger(McpAsyncClient.class);
|
||||
|
||||
private static final TypeReference<Void> VOID_TYPE_REFERENCE = new TypeReference<>() {
|
||||
private static final TypeRef<Void> VOID_TYPE_REFERENCE = new TypeRef<>() {
|
||||
};
|
||||
|
||||
public static final TypeReference<Object> OBJECT_TYPE_REF = new TypeReference<>() {
|
||||
public static final TypeRef<Object> OBJECT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
public static final TypeReference<PaginatedRequest> PAGINATED_REQUEST_TYPE_REF = new TypeReference<>() {
|
||||
public static final TypeRef<PaginatedRequest> PAGINATED_REQUEST_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
public static final TypeReference<McpSchema.InitializeResult> INITIALIZE_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
public static final TypeRef<McpSchema.InitializeResult> INITIALIZE_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
public static final TypeReference<CreateMessageRequest> CREATE_MESSAGE_REQUEST_TYPE_REF = new TypeReference<>() {
|
||||
public static final TypeRef<CreateMessageRequest> CREATE_MESSAGE_REQUEST_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
public static final TypeReference<LoggingMessageNotification> LOGGING_MESSAGE_NOTIFICATION_TYPE_REF = new TypeReference<>() {
|
||||
public static final TypeRef<LoggingMessageNotification> LOGGING_MESSAGE_NOTIFICATION_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
public static final TypeReference<McpSchema.ProgressNotification> PROGRESS_NOTIFICATION_TYPE_REF = new TypeReference<>() {
|
||||
public static final TypeRef<McpSchema.ProgressNotification> PROGRESS_NOTIFICATION_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -512,7 +511,7 @@ public class McpAsyncClient {
|
|||
// --------------------------
|
||||
private RequestHandler<ElicitResult> elicitationCreateHandler() {
|
||||
return params -> {
|
||||
ElicitRequest request = transport.unmarshalFrom(params, new TypeReference<>() {
|
||||
ElicitRequest request = transport.unmarshalFrom(params, new TypeRef<>() {
|
||||
});
|
||||
|
||||
return this.elicitationHandler.apply(request);
|
||||
|
|
@ -522,10 +521,10 @@ public class McpAsyncClient {
|
|||
// --------------------------
|
||||
// Tools
|
||||
// --------------------------
|
||||
private static final TypeReference<McpSchema.CallToolResult> CALL_TOOL_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.CallToolResult> CALL_TOOL_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
private static final TypeReference<McpSchema.ListToolsResult> LIST_TOOLS_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.ListToolsResult> LIST_TOOLS_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -596,13 +595,13 @@ public class McpAsyncClient {
|
|||
// Resources
|
||||
// --------------------------
|
||||
|
||||
private static final TypeReference<McpSchema.ListResourcesResult> LIST_RESOURCES_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.ListResourcesResult> LIST_RESOURCES_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
private static final TypeReference<McpSchema.ReadResourceResult> READ_RESOURCE_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.ReadResourceResult> READ_RESOURCE_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
private static final TypeReference<McpSchema.ListResourceTemplatesResult> LIST_RESOURCE_TEMPLATES_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.ListResourceTemplatesResult> LIST_RESOURCE_TEMPLATES_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -756,7 +755,7 @@ public class McpAsyncClient {
|
|||
List<Function<List<McpSchema.ResourceContents>, Mono<Void>>> resourcesUpdateConsumers) {
|
||||
return params -> {
|
||||
McpSchema.ResourcesUpdatedNotification resourcesUpdatedNotification = transport.unmarshalFrom(params,
|
||||
new TypeReference<>() {
|
||||
new TypeRef<>() {
|
||||
});
|
||||
|
||||
return readResource(new McpSchema.ReadResourceRequest(resourcesUpdatedNotification.uri()))
|
||||
|
|
@ -773,10 +772,10 @@ public class McpAsyncClient {
|
|||
// --------------------------
|
||||
// Prompts
|
||||
// --------------------------
|
||||
private static final TypeReference<McpSchema.ListPromptsResult> LIST_PROMPTS_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.ListPromptsResult> LIST_PROMPTS_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
private static final TypeReference<McpSchema.GetPromptResult> GET_PROMPT_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.GetPromptResult> GET_PROMPT_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -911,7 +910,7 @@ public class McpAsyncClient {
|
|||
// --------------------------
|
||||
// Completions
|
||||
// --------------------------
|
||||
private static final TypeReference<McpSchema.CompleteResult> COMPLETION_COMPLETE_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.CompleteResult> COMPLETION_COMPLETE_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import java.util.function.Function;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.client.transport.customizer.McpAsyncHttpClientRequestCustomizer;
|
||||
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
|
||||
|
|
@ -97,8 +97,8 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
/** HTTP request builder for building requests to send messages to the server */
|
||||
private final HttpRequest.Builder requestBuilder;
|
||||
|
||||
/** JSON object mapper for message serialization/deserialization */
|
||||
protected ObjectMapper objectMapper;
|
||||
/** JSON mapper for message serialization/deserialization */
|
||||
protected McpJsonMapper jsonMapper;
|
||||
|
||||
/** Flag indicating if the transport is in closing state */
|
||||
private volatile boolean isClosing = false;
|
||||
|
|
@ -117,65 +117,6 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
*/
|
||||
private final McpAsyncHttpClientRequestCustomizer httpRequestCustomizer;
|
||||
|
||||
/**
|
||||
* Creates a new transport instance with default HTTP client and object mapper.
|
||||
* @param baseUri the base URI of the MCP server
|
||||
* @deprecated Use {@link HttpClientSseClientTransport#builder(String)} instead. This
|
||||
* constructor will be removed in future versions.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public HttpClientSseClientTransport(String baseUri) {
|
||||
this(HttpClient.newBuilder(), baseUri, new ObjectMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transport instance with custom HTTP client builder and object mapper.
|
||||
* @param clientBuilder the HTTP client builder to use
|
||||
* @param baseUri the base URI of the MCP server
|
||||
* @param objectMapper the object mapper for JSON serialization/deserialization
|
||||
* @throws IllegalArgumentException if objectMapper or clientBuilder is null
|
||||
* @deprecated Use {@link HttpClientSseClientTransport#builder(String)} instead. This
|
||||
* constructor will be removed in future versions.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, String baseUri, ObjectMapper objectMapper) {
|
||||
this(clientBuilder, baseUri, DEFAULT_SSE_ENDPOINT, objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transport instance with custom HTTP client builder and object mapper.
|
||||
* @param clientBuilder the HTTP client builder to use
|
||||
* @param baseUri the base URI of the MCP server
|
||||
* @param sseEndpoint the SSE endpoint path
|
||||
* @param objectMapper the object mapper for JSON serialization/deserialization
|
||||
* @throws IllegalArgumentException if objectMapper or clientBuilder is null
|
||||
* @deprecated Use {@link HttpClientSseClientTransport#builder(String)} instead. This
|
||||
* constructor will be removed in future versions.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, String baseUri, String sseEndpoint,
|
||||
ObjectMapper objectMapper) {
|
||||
this(clientBuilder, HttpRequest.newBuilder(), baseUri, sseEndpoint, objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transport instance with custom HTTP client builder, object mapper,
|
||||
* and headers.
|
||||
* @param clientBuilder the HTTP client builder to use
|
||||
* @param requestBuilder the HTTP request builder to use
|
||||
* @param baseUri the base URI of the MCP server
|
||||
* @param sseEndpoint the SSE endpoint path
|
||||
* @param objectMapper the object mapper for JSON serialization/deserialization
|
||||
* @throws IllegalArgumentException if objectMapper, clientBuilder, or headers is null
|
||||
* @deprecated Use {@link HttpClientSseClientTransport#builder(String)} instead. This
|
||||
* constructor will be removed in future versions.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, HttpRequest.Builder requestBuilder,
|
||||
String baseUri, String sseEndpoint, ObjectMapper objectMapper) {
|
||||
this(clientBuilder.build(), requestBuilder, baseUri, sseEndpoint, objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transport instance with custom HTTP client builder, object mapper,
|
||||
* and headers.
|
||||
|
|
@ -183,30 +124,14 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
* @param requestBuilder the HTTP request builder to use
|
||||
* @param baseUri the base URI of the MCP server
|
||||
* @param sseEndpoint the SSE endpoint path
|
||||
* @param objectMapper the object mapper for JSON serialization/deserialization
|
||||
* @throws IllegalArgumentException if objectMapper, clientBuilder, or headers is null
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
HttpClientSseClientTransport(HttpClient httpClient, HttpRequest.Builder requestBuilder, String baseUri,
|
||||
String sseEndpoint, ObjectMapper objectMapper) {
|
||||
this(httpClient, requestBuilder, baseUri, sseEndpoint, objectMapper, McpAsyncHttpClientRequestCustomizer.NOOP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transport instance with custom HTTP client builder, object mapper,
|
||||
* and headers.
|
||||
* @param httpClient the HTTP client to use
|
||||
* @param requestBuilder the HTTP request builder to use
|
||||
* @param baseUri the base URI of the MCP server
|
||||
* @param sseEndpoint the SSE endpoint path
|
||||
* @param objectMapper the object mapper for JSON serialization/deserialization
|
||||
* @param jsonMapper the object mapper for JSON serialization/deserialization
|
||||
* @param httpRequestCustomizer customizer for the requestBuilder before executing
|
||||
* requests
|
||||
* @throws IllegalArgumentException if objectMapper, clientBuilder, or headers is null
|
||||
*/
|
||||
HttpClientSseClientTransport(HttpClient httpClient, HttpRequest.Builder requestBuilder, String baseUri,
|
||||
String sseEndpoint, ObjectMapper objectMapper, McpAsyncHttpClientRequestCustomizer httpRequestCustomizer) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
String sseEndpoint, McpJsonMapper jsonMapper, McpAsyncHttpClientRequestCustomizer httpRequestCustomizer) {
|
||||
Assert.notNull(jsonMapper, "jsonMapper must not be null");
|
||||
Assert.hasText(baseUri, "baseUri must not be empty");
|
||||
Assert.hasText(sseEndpoint, "sseEndpoint must not be empty");
|
||||
Assert.notNull(httpClient, "httpClient must not be null");
|
||||
|
|
@ -214,7 +139,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
Assert.notNull(httpRequestCustomizer, "httpRequestCustomizer must not be null");
|
||||
this.baseUri = URI.create(baseUri);
|
||||
this.sseEndpoint = sseEndpoint;
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.httpClient = httpClient;
|
||||
this.requestBuilder = requestBuilder;
|
||||
this.httpRequestCustomizer = httpRequestCustomizer;
|
||||
|
|
@ -245,7 +170,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
|
||||
private HttpClient.Builder clientBuilder = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1);
|
||||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
|
||||
|
||||
|
|
@ -340,13 +265,13 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the object mapper for JSON serialization/deserialization.
|
||||
* @param objectMapper the object mapper
|
||||
* Sets the JSON mapper implementation to use for serialization/deserialization.
|
||||
* @param jsonMapper the JSON mapper
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
|
@ -402,8 +327,8 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
*/
|
||||
public HttpClientSseClientTransport build() {
|
||||
HttpClient httpClient = this.clientBuilder.connectTimeout(this.connectTimeout).build();
|
||||
return new HttpClientSseClientTransport(httpClient, requestBuilder, baseUri, sseEndpoint, objectMapper,
|
||||
httpRequestCustomizer);
|
||||
return new HttpClientSseClientTransport(httpClient, requestBuilder, baseUri, sseEndpoint,
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, httpRequestCustomizer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -450,7 +375,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
}
|
||||
}
|
||||
else if (MESSAGE_EVENT_TYPE.equals(responseEvent.sseEvent().event())) {
|
||||
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper,
|
||||
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(jsonMapper,
|
||||
responseEvent.sseEvent().data());
|
||||
sink.success();
|
||||
return Flux.just(message);
|
||||
|
|
@ -531,7 +456,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
private Mono<String> serializeMessage(final JSONRPCMessage message) {
|
||||
return Mono.defer(() -> {
|
||||
try {
|
||||
return Mono.just(objectMapper.writeValueAsString(message));
|
||||
return Mono.just(jsonMapper.writeValueAsString(message));
|
||||
}
|
||||
catch (IOException e) {
|
||||
return Mono.error(new McpTransportException("Failed to serialize message", e));
|
||||
|
|
@ -582,8 +507,8 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
* @return the unmarshalled object
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ import org.reactivestreams.Publisher;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.client.transport.customizer.McpAsyncHttpClientRequestCustomizer;
|
||||
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
|
||||
|
|
@ -106,7 +106,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
|
||||
public static int BAD_REQUEST = 400;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
private final URI baseUri;
|
||||
|
||||
|
|
@ -124,10 +124,10 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
|
||||
private final AtomicReference<Consumer<Throwable>> exceptionHandler = new AtomicReference<>();
|
||||
|
||||
private HttpClientStreamableHttpTransport(ObjectMapper objectMapper, HttpClient httpClient,
|
||||
private HttpClientStreamableHttpTransport(McpJsonMapper jsonMapper, HttpClient httpClient,
|
||||
HttpRequest.Builder requestBuilder, String baseUri, String endpoint, boolean resumableStreams,
|
||||
boolean openConnectionOnStartup, McpAsyncHttpClientRequestCustomizer httpRequestCustomizer) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.httpClient = httpClient;
|
||||
this.requestBuilder = requestBuilder;
|
||||
this.baseUri = URI.create(baseUri);
|
||||
|
|
@ -278,7 +278,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
// won't since the next version considers
|
||||
// removing it.
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(
|
||||
this.objectMapper, responseEvent.sseEvent().data());
|
||||
this.jsonMapper, responseEvent.sseEvent().data());
|
||||
|
||||
Tuple2<Optional<String>, Iterable<McpSchema.JSONRPCMessage>> idWithMessages = Tuples
|
||||
.of(Optional.ofNullable(responseEvent.sseEvent().id()),
|
||||
|
|
@ -393,7 +393,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
|
||||
public String toString(McpSchema.JSONRPCMessage message) {
|
||||
try {
|
||||
return this.objectMapper.writeValueAsString(message);
|
||||
return this.jsonMapper.writeValueAsString(message);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("Failed to serialize JSON-RPC message", e);
|
||||
|
|
@ -479,7 +479,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
// since the
|
||||
// next version considers removing it.
|
||||
McpSchema.JSONRPCMessage message = McpSchema
|
||||
.deserializeJsonRpcMessage(this.objectMapper, sseEvent.data());
|
||||
.deserializeJsonRpcMessage(this.jsonMapper, sseEvent.data());
|
||||
|
||||
Tuple2<Optional<String>, Iterable<McpSchema.JSONRPCMessage>> idWithMessages = Tuples
|
||||
.of(Optional.ofNullable(sseEvent.id()), List.of(message));
|
||||
|
|
@ -508,7 +508,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
}
|
||||
|
||||
try {
|
||||
return Mono.just(McpSchema.deserializeJsonRpcMessage(objectMapper, data));
|
||||
return Mono.just(McpSchema.deserializeJsonRpcMessage(jsonMapper, data));
|
||||
}
|
||||
catch (IOException e) {
|
||||
return Mono.error(new McpTransportException(
|
||||
|
|
@ -582,8 +582,8 @@ public class HttpClientStreamableHttpTransport 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -593,7 +593,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
|
||||
private final String baseUri;
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
private HttpClient.Builder clientBuilder = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1);
|
||||
|
||||
|
|
@ -663,13 +663,13 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
}
|
||||
|
||||
/**
|
||||
* Configure the {@link ObjectMapper} to use.
|
||||
* @param objectMapper instance to use
|
||||
* Configure a custom {@link McpJsonMapper} implementation 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;
|
||||
}
|
||||
|
||||
|
|
@ -763,12 +763,10 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
* @return a new instance of {@link HttpClientStreamableHttpTransport}
|
||||
*/
|
||||
public HttpClientStreamableHttpTransport build() {
|
||||
ObjectMapper objectMapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
|
||||
|
||||
HttpClient httpClient = this.clientBuilder.connectTimeout(this.connectTimeout).build();
|
||||
|
||||
return new HttpClientStreamableHttpTransport(objectMapper, httpClient, requestBuilder, baseUri, endpoint,
|
||||
resumableStreams, openConnectionOnStartup, httpRequestCustomizer);
|
||||
return new HttpClientStreamableHttpTransport(jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
httpClient, requestBuilder, baseUri, endpoint, resumableStreams, openConnectionOnStartup,
|
||||
httpRequestCustomizer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import java.util.concurrent.Executors;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
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.McpClientTransport;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.JSONRPCMessage;
|
||||
|
|
@ -48,7 +48,7 @@ public class StdioClientTransport implements McpClientTransport {
|
|||
/** The server process being communicated with */
|
||||
private Process process;
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
/** Scheduler for handling inbound messages from the server process */
|
||||
private Scheduler inboundScheduler;
|
||||
|
|
@ -70,29 +70,20 @@ public class StdioClientTransport implements McpClientTransport {
|
|||
private Consumer<String> stdErrorHandler = error -> logger.info("STDERR Message received: {}", error);
|
||||
|
||||
/**
|
||||
* Creates a new StdioClientTransport with the specified parameters and default
|
||||
* ObjectMapper.
|
||||
* Creates a new StdioClientTransport with the specified parameters and JsonMapper.
|
||||
* @param params The parameters for configuring the server process
|
||||
* @param jsonMapper The JsonMapper to use for JSON serialization/deserialization
|
||||
*/
|
||||
public StdioClientTransport(ServerParameters params) {
|
||||
this(params, new ObjectMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new StdioClientTransport with the specified parameters and ObjectMapper.
|
||||
* @param params The parameters for configuring the server process
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
*/
|
||||
public StdioClientTransport(ServerParameters params, ObjectMapper objectMapper) {
|
||||
public StdioClientTransport(ServerParameters params, McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(params, "The params can not be null");
|
||||
Assert.notNull(objectMapper, "The ObjectMapper can not be null");
|
||||
Assert.notNull(jsonMapper, "The JsonMapper can not be null");
|
||||
|
||||
this.inboundSink = Sinks.many().unicast().onBackpressureBuffer();
|
||||
this.outboundSink = Sinks.many().unicast().onBackpressureBuffer();
|
||||
|
||||
this.params = params;
|
||||
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
|
||||
this.errorSink = Sinks.many().unicast().onBackpressureBuffer();
|
||||
|
||||
|
|
@ -259,7 +250,7 @@ public class StdioClientTransport implements McpClientTransport {
|
|||
String line;
|
||||
while (!isClosing && (line = processReader.readLine()) != null) {
|
||||
try {
|
||||
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(this.objectMapper, line);
|
||||
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(this.jsonMapper, line);
|
||||
if (!this.inboundSink.tryEmitNext(message).isSuccess()) {
|
||||
if (!isClosing) {
|
||||
logger.error("Failed to enqueue inbound message: {}", message);
|
||||
|
|
@ -300,7 +291,7 @@ public class StdioClientTransport implements McpClientTransport {
|
|||
.handle((message, s) -> {
|
||||
if (message != null && !isClosing) {
|
||||
try {
|
||||
String jsonMessage = objectMapper.writeValueAsString(message);
|
||||
String jsonMessage = jsonMapper.writeValueAsString(message);
|
||||
// Escape any embedded newlines in the JSON message as per spec:
|
||||
// https://spec.modelcontextprotocol.io/specification/basic/transports/#stdio
|
||||
// - Messages are delimited by newlines, and MUST NOT contain
|
||||
|
|
@ -392,8 +383,8 @@ public class StdioClientTransport 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,10 +15,16 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.spec.DefaultMcpStreamableServerSessionFactory;
|
||||
import io.modelcontextprotocol.spec.JsonSchemaValidator;
|
||||
import io.modelcontextprotocol.spec.McpServerTransportProviderBase;
|
||||
import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
|
||||
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
|
||||
import io.modelcontextprotocol.spec.McpClientSession;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
|
|
@ -90,7 +96,7 @@ public class McpAsyncServer {
|
|||
|
||||
private final McpServerTransportProviderBase mcpTransportProvider;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
private final JsonSchemaValidator jsonSchemaValidator;
|
||||
|
||||
|
|
@ -123,13 +129,13 @@ public class McpAsyncServer {
|
|||
* @param mcpTransportProvider The transport layer implementation for MCP
|
||||
* communication.
|
||||
* @param features The MCP server supported features.
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
* @param jsonMapper The JsonMapper to use for JSON serialization/deserialization
|
||||
*/
|
||||
McpAsyncServer(McpServerTransportProvider mcpTransportProvider, ObjectMapper objectMapper,
|
||||
McpAsyncServer(McpServerTransportProvider mcpTransportProvider, McpJsonMapper jsonMapper,
|
||||
McpServerFeatures.Async features, Duration requestTimeout,
|
||||
McpUriTemplateManagerFactory uriTemplateManagerFactory, JsonSchemaValidator jsonSchemaValidator) {
|
||||
this.mcpTransportProvider = mcpTransportProvider;
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.serverInfo = features.serverInfo();
|
||||
this.serverCapabilities = features.serverCapabilities().mutate().logging().build();
|
||||
this.instructions = features.instructions();
|
||||
|
|
@ -150,11 +156,11 @@ public class McpAsyncServer {
|
|||
requestTimeout, transport, this::asyncInitializeRequestHandler, requestHandlers, notificationHandlers));
|
||||
}
|
||||
|
||||
McpAsyncServer(McpStreamableServerTransportProvider mcpTransportProvider, ObjectMapper objectMapper,
|
||||
McpAsyncServer(McpStreamableServerTransportProvider mcpTransportProvider, McpJsonMapper jsonMapper,
|
||||
McpServerFeatures.Async features, Duration requestTimeout,
|
||||
McpUriTemplateManagerFactory uriTemplateManagerFactory, JsonSchemaValidator jsonSchemaValidator) {
|
||||
this.mcpTransportProvider = mcpTransportProvider;
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.serverInfo = features.serverInfo();
|
||||
this.serverCapabilities = features.serverCapabilities().mutate().logging().build();
|
||||
this.instructions = features.instructions();
|
||||
|
|
@ -505,8 +511,8 @@ public class McpAsyncServer {
|
|||
|
||||
private McpRequestHandler<CallToolResult> toolsCallRequestHandler() {
|
||||
return (exchange, params) -> {
|
||||
McpSchema.CallToolRequest callToolRequest = objectMapper.convertValue(params,
|
||||
new TypeReference<McpSchema.CallToolRequest>() {
|
||||
McpSchema.CallToolRequest callToolRequest = jsonMapper.convertValue(params,
|
||||
new TypeRef<McpSchema.CallToolRequest>() {
|
||||
});
|
||||
|
||||
Optional<McpServerFeatures.AsyncToolSpecification> toolSpecification = this.tools.stream()
|
||||
|
|
@ -633,8 +639,8 @@ public class McpAsyncServer {
|
|||
|
||||
private McpRequestHandler<McpSchema.ReadResourceResult> resourcesReadRequestHandler() {
|
||||
return (exchange, params) -> {
|
||||
McpSchema.ReadResourceRequest resourceRequest = objectMapper.convertValue(params,
|
||||
new TypeReference<McpSchema.ReadResourceRequest>() {
|
||||
McpSchema.ReadResourceRequest resourceRequest = jsonMapper.convertValue(params,
|
||||
new TypeRef<McpSchema.ReadResourceRequest>() {
|
||||
});
|
||||
var resourceUri = resourceRequest.uri();
|
||||
|
||||
|
|
@ -742,8 +748,8 @@ public class McpAsyncServer {
|
|||
|
||||
private McpRequestHandler<McpSchema.GetPromptResult> promptsGetRequestHandler() {
|
||||
return (exchange, params) -> {
|
||||
McpSchema.GetPromptRequest promptRequest = objectMapper.convertValue(params,
|
||||
new TypeReference<McpSchema.GetPromptRequest>() {
|
||||
McpSchema.GetPromptRequest promptRequest = jsonMapper.convertValue(params,
|
||||
new TypeRef<McpSchema.GetPromptRequest>() {
|
||||
});
|
||||
|
||||
// Implement prompt retrieval logic here
|
||||
|
|
@ -790,9 +796,8 @@ public class McpAsyncServer {
|
|||
return (exchange, params) -> {
|
||||
return Mono.defer(() -> {
|
||||
|
||||
SetLevelRequest newMinLoggingLevel = objectMapper.convertValue(params,
|
||||
new TypeReference<SetLevelRequest>() {
|
||||
});
|
||||
SetLevelRequest newMinLoggingLevel = jsonMapper.convertValue(params, new TypeRef<SetLevelRequest>() {
|
||||
});
|
||||
|
||||
exchange.setMinLoggingLevel(newMinLoggingLevel.level());
|
||||
|
||||
|
|
@ -914,4 +919,4 @@ public class McpAsyncServer {
|
|||
this.protocolVersions = protocolVersions;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import io.modelcontextprotocol.common.McpTransportContext;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
import io.modelcontextprotocol.spec.McpLoggableSession;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
|
|
@ -37,16 +37,16 @@ public class McpAsyncServerExchange {
|
|||
|
||||
private final McpTransportContext transportContext;
|
||||
|
||||
private static final TypeReference<McpSchema.CreateMessageResult> CREATE_MESSAGE_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.CreateMessageResult> CREATE_MESSAGE_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
private static final TypeReference<McpSchema.ListRootsResult> LIST_ROOTS_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.ListRootsResult> LIST_ROOTS_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
private static final TypeReference<McpSchema.ElicitResult> ELICITATION_RESULT_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<McpSchema.ElicitResult> ELICITATION_RESULT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
public static final TypeReference<Object> OBJECT_TYPE_REF = new TypeReference<>() {
|
||||
public static final TypeRef<Object> OBJECT_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ import java.util.Arrays;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
|
||||
import io.modelcontextprotocol.spec.DefaultJsonSchemaValidator;
|
||||
import io.modelcontextprotocol.spec.JsonSchemaValidator;
|
||||
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
|
||||
import io.modelcontextprotocol.spec.McpSchema.ResourceTemplate;
|
||||
|
|
@ -67,7 +67,7 @@ import reactor.core.publisher.Mono;
|
|||
* Example of creating a basic synchronous server: <pre>{@code
|
||||
* McpServer.sync(transportProvider)
|
||||
* .serverInfo("my-server", "1.0.0")
|
||||
* .tool(new Tool("calculator", "Performs calculations", schema),
|
||||
* .tool(Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(),
|
||||
* (exchange, args) -> new CallToolResult("Result: " + calculate(args)))
|
||||
* .build();
|
||||
* }</pre>
|
||||
|
|
@ -75,7 +75,7 @@ import reactor.core.publisher.Mono;
|
|||
* Example of creating a basic asynchronous server: <pre>{@code
|
||||
* McpServer.async(transportProvider)
|
||||
* .serverInfo("my-server", "1.0.0")
|
||||
* .tool(new Tool("calculator", "Performs calculations", schema),
|
||||
* .tool(Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(),
|
||||
* (exchange, args) -> Mono.fromSupplier(() -> calculate(args))
|
||||
* .map(result -> new CallToolResult("Result: " + result)))
|
||||
* .build();
|
||||
|
|
@ -227,11 +227,12 @@ public interface McpServer {
|
|||
var features = new McpServerFeatures.Async(this.serverInfo, this.serverCapabilities, this.tools,
|
||||
this.resources, this.resourceTemplates, this.prompts, this.completions, this.rootsChangeHandlers,
|
||||
this.instructions);
|
||||
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
|
||||
var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator
|
||||
: new DefaultJsonSchemaValidator(mapper);
|
||||
return new McpAsyncServer(this.transportProvider, mapper, features, this.requestTimeout,
|
||||
this.uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
|
||||
var jsonSchemaValidator = (this.jsonSchemaValidator != null) ? this.jsonSchemaValidator
|
||||
: JsonSchemaValidator.getDefault();
|
||||
|
||||
return new McpAsyncServer(transportProvider, jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
features, requestTimeout, uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -254,11 +255,10 @@ public interface McpServer {
|
|||
var features = new McpServerFeatures.Async(this.serverInfo, this.serverCapabilities, this.tools,
|
||||
this.resources, this.resourceTemplates, this.prompts, this.completions, this.rootsChangeHandlers,
|
||||
this.instructions);
|
||||
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
|
||||
var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator
|
||||
: new DefaultJsonSchemaValidator(mapper);
|
||||
return new McpAsyncServer(this.transportProvider, mapper, features, this.requestTimeout,
|
||||
this.uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
: JsonSchemaValidator.getDefault();
|
||||
return new McpAsyncServer(transportProvider, jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
features, requestTimeout, uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -270,7 +270,7 @@ public interface McpServer {
|
|||
|
||||
McpUriTemplateManagerFactory uriTemplateManagerFactory = new DeafaultMcpUriTemplateManagerFactory();
|
||||
|
||||
ObjectMapper objectMapper;
|
||||
McpJsonMapper jsonMapper;
|
||||
|
||||
McpSchema.Implementation serverInfo = DEFAULT_SERVER_INFO;
|
||||
|
||||
|
|
@ -417,7 +417,7 @@ public interface McpServer {
|
|||
* <p>
|
||||
* Example usage: <pre>{@code
|
||||
* .tool(
|
||||
* new Tool("calculator", "Performs calculations", schema),
|
||||
* Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(),
|
||||
* (exchange, args) -> Mono.fromSupplier(() -> calculate(args))
|
||||
* .map(result -> new CallToolResult("Result: " + result))
|
||||
* )
|
||||
|
|
@ -765,14 +765,14 @@ public interface McpServer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the object mapper to use for serializing and deserializing JSON messages.
|
||||
* @param objectMapper the instance to use. Must not be null.
|
||||
* Sets the JsonMapper to use for serializing and deserializing JSON messages.
|
||||
* @param jsonMapper the mapper to use. Must not be null.
|
||||
* @return This builder instance for method chaining.
|
||||
* @throws IllegalArgumentException if objectMapper is null
|
||||
* @throws IllegalArgumentException if jsonMapper is null
|
||||
*/
|
||||
public AsyncSpecification<S> objectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
public AsyncSpecification<S> jsonMapper(McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -813,13 +813,11 @@ public interface McpServer {
|
|||
this.rootsChangeHandlers, this.instructions);
|
||||
McpServerFeatures.Async asyncFeatures = McpServerFeatures.Async.fromSync(syncFeatures,
|
||||
this.immediateExecution);
|
||||
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
|
||||
var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator
|
||||
: new DefaultJsonSchemaValidator(mapper);
|
||||
|
||||
var asyncServer = new McpAsyncServer(this.transportProvider, mapper, asyncFeatures, this.requestTimeout,
|
||||
this.uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
|
||||
var asyncServer = new McpAsyncServer(transportProvider,
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, asyncFeatures, requestTimeout,
|
||||
uriTemplateManagerFactory,
|
||||
jsonSchemaValidator != null ? jsonSchemaValidator : JsonSchemaValidator.getDefault());
|
||||
return new McpSyncServer(asyncServer, this.immediateExecution);
|
||||
}
|
||||
|
||||
|
|
@ -846,13 +844,11 @@ public interface McpServer {
|
|||
this.rootsChangeHandlers, this.instructions);
|
||||
McpServerFeatures.Async asyncFeatures = McpServerFeatures.Async.fromSync(syncFeatures,
|
||||
this.immediateExecution);
|
||||
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
|
||||
var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator
|
||||
: new DefaultJsonSchemaValidator(mapper);
|
||||
|
||||
var asyncServer = new McpAsyncServer(this.transportProvider, mapper, asyncFeatures, this.requestTimeout,
|
||||
: JsonSchemaValidator.getDefault();
|
||||
var asyncServer = new McpAsyncServer(transportProvider,
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, asyncFeatures, this.requestTimeout,
|
||||
this.uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
|
||||
return new McpSyncServer(asyncServer, this.immediateExecution);
|
||||
}
|
||||
|
||||
|
|
@ -865,7 +861,7 @@ public interface McpServer {
|
|||
|
||||
McpUriTemplateManagerFactory uriTemplateManagerFactory = new DeafaultMcpUriTemplateManagerFactory();
|
||||
|
||||
ObjectMapper objectMapper;
|
||||
McpJsonMapper jsonMapper;
|
||||
|
||||
McpSchema.Implementation serverInfo = DEFAULT_SERVER_INFO;
|
||||
|
||||
|
|
@ -1014,7 +1010,7 @@ public interface McpServer {
|
|||
* <p>
|
||||
* Example usage: <pre>{@code
|
||||
* .tool(
|
||||
* new Tool("calculator", "Performs calculations", schema),
|
||||
* Tool.builder().name("calculator").title("Performs calculations".inputSchema(schema).build(),
|
||||
* (exchange, args) -> new CallToolResult("Result: " + calculate(args))
|
||||
* )
|
||||
* }</pre>
|
||||
|
|
@ -1363,14 +1359,14 @@ public interface McpServer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the object mapper to use for serializing and deserializing JSON messages.
|
||||
* @param objectMapper the instance to use. Must not be null.
|
||||
* Sets the JsonMapper to use for serializing and deserializing JSON messages.
|
||||
* @param jsonMapper the mapper to use. Must not be null.
|
||||
* @return This builder instance for method chaining.
|
||||
* @throws IllegalArgumentException if objectMapper is null
|
||||
* @throws IllegalArgumentException if jsonMapper is null
|
||||
*/
|
||||
public SyncSpecification<S> objectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
public SyncSpecification<S> jsonMapper(McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -1404,7 +1400,7 @@ public interface McpServer {
|
|||
|
||||
McpUriTemplateManagerFactory uriTemplateManagerFactory = new DeafaultMcpUriTemplateManagerFactory();
|
||||
|
||||
ObjectMapper objectMapper;
|
||||
McpJsonMapper jsonMapper;
|
||||
|
||||
McpSchema.Implementation serverInfo = DEFAULT_SERVER_INFO;
|
||||
|
||||
|
|
@ -1821,14 +1817,14 @@ public interface McpServer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the object mapper to use for serializing and deserializing JSON messages.
|
||||
* @param objectMapper the instance to use. Must not be null.
|
||||
* Sets the JsonMapper to use for serializing and deserializing JSON messages.
|
||||
* @param jsonMapper the mapper to use. Must not be null.
|
||||
* @return This builder instance for method chaining.
|
||||
* @throws IllegalArgumentException if objectMapper is null
|
||||
* @throws IllegalArgumentException if jsonMapper is null
|
||||
*/
|
||||
public StatelessAsyncSpecification objectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
public StatelessAsyncSpecification jsonMapper(McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -1849,11 +1845,9 @@ public interface McpServer {
|
|||
public McpStatelessAsyncServer build() {
|
||||
var features = new McpStatelessServerFeatures.Async(this.serverInfo, this.serverCapabilities, this.tools,
|
||||
this.resources, this.resourceTemplates, this.prompts, this.completions, this.instructions);
|
||||
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
|
||||
var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator
|
||||
: new DefaultJsonSchemaValidator(mapper);
|
||||
return new McpStatelessAsyncServer(this.transport, mapper, features, this.requestTimeout,
|
||||
this.uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
return new McpStatelessAsyncServer(transport, jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
features, requestTimeout, uriTemplateManagerFactory,
|
||||
jsonSchemaValidator != null ? jsonSchemaValidator : JsonSchemaValidator.getDefault());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1866,7 +1860,7 @@ public interface McpServer {
|
|||
|
||||
McpUriTemplateManagerFactory uriTemplateManagerFactory = new DeafaultMcpUriTemplateManagerFactory();
|
||||
|
||||
ObjectMapper objectMapper;
|
||||
McpJsonMapper jsonMapper;
|
||||
|
||||
McpSchema.Implementation serverInfo = DEFAULT_SERVER_INFO;
|
||||
|
||||
|
|
@ -2283,14 +2277,14 @@ public interface McpServer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the object mapper to use for serializing and deserializing JSON messages.
|
||||
* @param objectMapper the instance to use. Must not be null.
|
||||
* Sets the JsonMapper to use for serializing and deserializing JSON messages.
|
||||
* @param jsonMapper the mapper to use. Must not be null.
|
||||
* @return This builder instance for method chaining.
|
||||
* @throws IllegalArgumentException if objectMapper is null
|
||||
* @throws IllegalArgumentException if jsonMapper is null
|
||||
*/
|
||||
public StatelessSyncSpecification objectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
public StatelessSyncSpecification jsonMapper(McpJsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -2325,31 +2319,13 @@ public interface McpServer {
|
|||
}
|
||||
|
||||
public McpStatelessSyncServer build() {
|
||||
/*
|
||||
* McpServerFeatures.Sync syncFeatures = new
|
||||
* McpServerFeatures.Sync(this.serverInfo, this.serverCapabilities,
|
||||
* this.tools, this.resources, this.resourceTemplates, this.prompts,
|
||||
* this.completions, this.rootsChangeHandlers, this.instructions);
|
||||
* McpServerFeatures.Async asyncFeatures =
|
||||
* McpServerFeatures.Async.fromSync(syncFeatures, this.immediateExecution);
|
||||
* var mapper = this.objectMapper != null ? this.objectMapper : new
|
||||
* ObjectMapper(); var jsonSchemaValidator = this.jsonSchemaValidator != null
|
||||
* ? this.jsonSchemaValidator : new DefaultJsonSchemaValidator(mapper);
|
||||
*
|
||||
* var asyncServer = new McpAsyncServer(this.transportProvider, mapper,
|
||||
* asyncFeatures, this.requestTimeout, this.uriTemplateManagerFactory,
|
||||
* jsonSchemaValidator);
|
||||
*
|
||||
* return new McpSyncServer(asyncServer, this.immediateExecution);
|
||||
*/
|
||||
var syncFeatures = new McpStatelessServerFeatures.Sync(this.serverInfo, this.serverCapabilities, this.tools,
|
||||
this.resources, this.resourceTemplates, this.prompts, this.completions, this.instructions);
|
||||
var asyncFeatures = McpStatelessServerFeatures.Async.fromSync(syncFeatures, this.immediateExecution);
|
||||
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
|
||||
var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator
|
||||
: new DefaultJsonSchemaValidator(mapper);
|
||||
var asyncServer = new McpStatelessAsyncServer(this.transport, mapper, asyncFeatures, this.requestTimeout,
|
||||
this.uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
var asyncServer = new McpStatelessAsyncServer(transport,
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, asyncFeatures, requestTimeout,
|
||||
uriTemplateManagerFactory,
|
||||
this.jsonSchemaValidator != null ? this.jsonSchemaValidator : JsonSchemaValidator.getDefault());
|
||||
return new McpStatelessSyncServer(asyncServer, this.immediateExecution);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -453,12 +453,13 @@ public class McpServerFeatures {
|
|||
*
|
||||
* <pre>{@code
|
||||
* McpServerFeatures.SyncToolSpecification.builder()
|
||||
* .tool(new Tool(
|
||||
* "calculator",
|
||||
* "Performs mathematical calculations",
|
||||
* new JsonSchemaObject()
|
||||
* .tool(Tool.builder()
|
||||
* .name("calculator")
|
||||
* .title("Performs mathematical calculations")
|
||||
* .inputSchema(new JsonSchemaObject()
|
||||
* .required("expression")
|
||||
* .property("expression", JsonSchemaType.STRING)))
|
||||
* .property("expression", JsonSchemaType.STRING))
|
||||
* .build()
|
||||
* .toolHandler((exchange, req) -> {
|
||||
* String expr = (String) req.arguments().get("expression");
|
||||
* return new CallToolResult("Result: " + evaluate(expr));
|
||||
|
|
|
|||
|
|
@ -4,16 +4,15 @@
|
|||
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
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.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.spec.JsonSchemaValidator;
|
||||
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
|
||||
import io.modelcontextprotocol.spec.McpSchema.JSONRPCResponse;
|
||||
import io.modelcontextprotocol.spec.McpSchema.ResourceTemplate;
|
||||
import io.modelcontextprotocol.spec.McpSchema.TextContent;
|
||||
import io.modelcontextprotocol.spec.McpSchema.Tool;
|
||||
import io.modelcontextprotocol.spec.McpStatelessServerTransport;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
|
|
@ -48,7 +47,7 @@ public class McpStatelessAsyncServer {
|
|||
|
||||
private final McpStatelessServerTransport mcpTransportProvider;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
private final McpSchema.ServerCapabilities serverCapabilities;
|
||||
|
||||
|
|
@ -72,11 +71,11 @@ public class McpStatelessAsyncServer {
|
|||
|
||||
private final JsonSchemaValidator jsonSchemaValidator;
|
||||
|
||||
McpStatelessAsyncServer(McpStatelessServerTransport mcpTransport, ObjectMapper objectMapper,
|
||||
McpStatelessAsyncServer(McpStatelessServerTransport mcpTransport, McpJsonMapper jsonMapper,
|
||||
McpStatelessServerFeatures.Async features, Duration requestTimeout,
|
||||
McpUriTemplateManagerFactory uriTemplateManagerFactory, JsonSchemaValidator jsonSchemaValidator) {
|
||||
this.mcpTransportProvider = mcpTransport;
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.serverInfo = features.serverInfo();
|
||||
this.serverCapabilities = features.serverCapabilities();
|
||||
this.instructions = features.instructions();
|
||||
|
|
@ -132,7 +131,7 @@ public class McpStatelessAsyncServer {
|
|||
// ---------------------------------------
|
||||
private McpStatelessRequestHandler<McpSchema.InitializeResult> asyncInitializeRequestHandler() {
|
||||
return (ctx, req) -> Mono.defer(() -> {
|
||||
McpSchema.InitializeRequest initializeRequest = this.objectMapper.convertValue(req,
|
||||
McpSchema.InitializeRequest initializeRequest = this.jsonMapper.convertValue(req,
|
||||
McpSchema.InitializeRequest.class);
|
||||
|
||||
logger.info("Client initialize request - Protocol: {}, Capabilities: {}, Info: {}",
|
||||
|
|
@ -376,8 +375,8 @@ public class McpStatelessAsyncServer {
|
|||
|
||||
private McpStatelessRequestHandler<CallToolResult> toolsCallRequestHandler() {
|
||||
return (ctx, params) -> {
|
||||
McpSchema.CallToolRequest callToolRequest = objectMapper.convertValue(params,
|
||||
new TypeReference<McpSchema.CallToolRequest>() {
|
||||
McpSchema.CallToolRequest callToolRequest = jsonMapper.convertValue(params,
|
||||
new TypeRef<McpSchema.CallToolRequest>() {
|
||||
});
|
||||
|
||||
Optional<McpStatelessServerFeatures.AsyncToolSpecification> toolSpecification = this.tools.stream()
|
||||
|
|
@ -479,8 +478,8 @@ public class McpStatelessAsyncServer {
|
|||
|
||||
private McpStatelessRequestHandler<McpSchema.ReadResourceResult> resourcesReadRequestHandler() {
|
||||
return (ctx, params) -> {
|
||||
McpSchema.ReadResourceRequest resourceRequest = objectMapper.convertValue(params,
|
||||
new TypeReference<McpSchema.ReadResourceRequest>() {
|
||||
McpSchema.ReadResourceRequest resourceRequest = jsonMapper.convertValue(params,
|
||||
new TypeRef<McpSchema.ReadResourceRequest>() {
|
||||
});
|
||||
var resourceUri = resourceRequest.uri();
|
||||
|
||||
|
|
@ -569,8 +568,8 @@ public class McpStatelessAsyncServer {
|
|||
|
||||
private McpStatelessRequestHandler<McpSchema.GetPromptResult> promptsGetRequestHandler() {
|
||||
return (ctx, params) -> {
|
||||
McpSchema.GetPromptRequest promptRequest = objectMapper.convertValue(params,
|
||||
new TypeReference<McpSchema.GetPromptRequest>() {
|
||||
McpSchema.GetPromptRequest promptRequest = jsonMapper.convertValue(params,
|
||||
new TypeRef<McpSchema.GetPromptRequest>() {
|
||||
});
|
||||
|
||||
// Implement prompt retrieval logic here
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import java.util.UUID;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
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.McpError;
|
||||
|
|
@ -89,8 +89,8 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
|
||||
public static final String DEFAULT_BASE_URL = "";
|
||||
|
||||
/** JSON object mapper for serialization/deserialization */
|
||||
private final ObjectMapper objectMapper;
|
||||
/** JSON mapper for serialization/deserialization */
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
/** Base URL for the server transport */
|
||||
private final String baseUrl;
|
||||
|
|
@ -121,60 +121,7 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
/**
|
||||
* Creates a new HttpServletSseServerTransportProvider instance with a custom SSE
|
||||
* endpoint.
|
||||
* @param objectMapper The JSON object mapper to use for message
|
||||
* serialization/deserialization
|
||||
* @param messageEndpoint The endpoint path where clients will send their messages
|
||||
* @param sseEndpoint The endpoint path where clients will establish SSE connections
|
||||
* @deprecated Use the builder {@link #builder()} instead for better configuration
|
||||
* options.
|
||||
*/
|
||||
@Deprecated
|
||||
public HttpServletSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint,
|
||||
String sseEndpoint) {
|
||||
this(objectMapper, DEFAULT_BASE_URL, messageEndpoint, sseEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new HttpServletSseServerTransportProvider instance with a custom SSE
|
||||
* endpoint.
|
||||
* @param objectMapper The JSON object mapper to use for message
|
||||
* serialization/deserialization
|
||||
* @param baseUrl The base URL for the server transport
|
||||
* @param messageEndpoint The endpoint path where clients will send their messages
|
||||
* @param sseEndpoint The endpoint path where clients will establish SSE connections
|
||||
* @deprecated Use the builder {@link #builder()} instead for better configuration
|
||||
* options.
|
||||
*/
|
||||
@Deprecated
|
||||
public HttpServletSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
|
||||
String sseEndpoint) {
|
||||
this(objectMapper, baseUrl, messageEndpoint, sseEndpoint, null, (serverRequest) -> McpTransportContext.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new HttpServletSseServerTransportProvider instance with a custom SSE
|
||||
* endpoint.
|
||||
* @param objectMapper The JSON object mapper to use for message
|
||||
* serialization/deserialization
|
||||
* @param baseUrl The base URL for the server transport
|
||||
* @param messageEndpoint The endpoint path where clients will send their messages
|
||||
* @param sseEndpoint The endpoint path where clients will establish SSE connections
|
||||
* @param keepAliveInterval The interval for keep-alive pings, or null to disable
|
||||
* keep-alive functionality
|
||||
* @deprecated Use the builder {@link #builder()} instead for better configuration
|
||||
* options.
|
||||
*/
|
||||
@Deprecated
|
||||
public HttpServletSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
|
||||
String sseEndpoint, Duration keepAliveInterval) {
|
||||
this(objectMapper, baseUrl, messageEndpoint, sseEndpoint, keepAliveInterval,
|
||||
(serverRequest) -> McpTransportContext.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new HttpServletSseServerTransportProvider instance with a custom SSE
|
||||
* endpoint.
|
||||
* @param objectMapper The JSON object mapper to use for message
|
||||
* @param jsonMapper The JSON object mapper to use for message
|
||||
* serialization/deserialization
|
||||
* @param baseUrl The base URL for the server transport
|
||||
* @param messageEndpoint The endpoint path where clients will send their messages
|
||||
|
|
@ -185,16 +132,16 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
* @deprecated Use the builder {@link #builder()} instead for better configuration
|
||||
* options.
|
||||
*/
|
||||
private HttpServletSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
|
||||
private HttpServletSseServerTransportProvider(McpJsonMapper jsonMapper, String baseUrl, String messageEndpoint,
|
||||
String sseEndpoint, Duration keepAliveInterval,
|
||||
McpTransportContextExtractor<HttpServletRequest> contextExtractor) {
|
||||
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
Assert.notNull(messageEndpoint, "messageEndpoint must not be null");
|
||||
Assert.notNull(sseEndpoint, "sseEndpoint 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;
|
||||
|
|
@ -217,17 +164,6 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
return List.of(ProtocolVersions.MCP_2024_11_05);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new HttpServletSseServerTransportProvider instance with the default SSE
|
||||
* endpoint.
|
||||
* @param objectMapper The JSON object mapper to use for message
|
||||
* serialization/deserialization
|
||||
* @param messageEndpoint The endpoint path where clients will send their messages
|
||||
*/
|
||||
public HttpServletSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint) {
|
||||
this(objectMapper, messageEndpoint, DEFAULT_SSE_ENDPOINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session factory for creating new sessions.
|
||||
* @param sessionFactory The session factory to use
|
||||
|
|
@ -342,7 +278,7 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
response.setContentType(APPLICATION_JSON);
|
||||
response.setCharacterEncoding(UTF_8);
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
String jsonError = objectMapper.writeValueAsString(new McpError("Session ID missing in message endpoint"));
|
||||
String jsonError = jsonMapper.writeValueAsString(new McpError("Session ID missing in message endpoint"));
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(jsonError);
|
||||
writer.flush();
|
||||
|
|
@ -355,7 +291,7 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
response.setContentType(APPLICATION_JSON);
|
||||
response.setCharacterEncoding(UTF_8);
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
String jsonError = objectMapper.writeValueAsString(new McpError("Session not found: " + sessionId));
|
||||
String jsonError = jsonMapper.writeValueAsString(new McpError("Session not found: " + sessionId));
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(jsonError);
|
||||
writer.flush();
|
||||
|
|
@ -371,7 +307,7 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
}
|
||||
|
||||
final McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, body.toString());
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(jsonMapper, body.toString());
|
||||
|
||||
// Process the message through the session's handle method
|
||||
// Block for Servlet compatibility
|
||||
|
|
@ -386,7 +322,7 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
response.setContentType(APPLICATION_JSON);
|
||||
response.setCharacterEncoding(UTF_8);
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
String jsonError = objectMapper.writeValueAsString(mcpError);
|
||||
String jsonError = jsonMapper.writeValueAsString(mcpError);
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(jsonError);
|
||||
writer.flush();
|
||||
|
|
@ -482,7 +418,7 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
|
||||
return Mono.fromRunnable(() -> {
|
||||
try {
|
||||
String jsonText = objectMapper.writeValueAsString(message);
|
||||
String jsonText = jsonMapper.writeValueAsString(message);
|
||||
sendEvent(writer, MESSAGE_EVENT_TYPE, jsonText);
|
||||
logger.debug("Message sent to session {}", sessionId);
|
||||
}
|
||||
|
|
@ -495,15 +431,15 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
}
|
||||
|
||||
/**
|
||||
* Converts data from one type to another using the configured ObjectMapper.
|
||||
* Converts data from one type to another using the configured JsonMapper.
|
||||
* @param data The source data object to convert
|
||||
* @param typeRef The target type reference
|
||||
* @return The converted object of type T
|
||||
* @param <T> The target type
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -559,7 +495,7 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
*/
|
||||
public static class Builder {
|
||||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
private String baseUrl = DEFAULT_BASE_URL;
|
||||
|
||||
|
|
@ -573,13 +509,15 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
private Duration keepAliveInterval;
|
||||
|
||||
/**
|
||||
* Sets the JSON object mapper to use for message serialization/deserialization.
|
||||
* @param objectMapper The object mapper to use
|
||||
* Sets the JsonMapper implementation to use for serialization/deserialization. If
|
||||
* not specified, a JacksonJsonMapper will be created from the configured
|
||||
* ObjectMapper.
|
||||
* @param jsonMapper The JsonMapper to use
|
||||
* @return This builder instance for method chaining
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -648,16 +586,14 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
* Builds a new instance of HttpServletSseServerTransportProvider with the
|
||||
* configured settings.
|
||||
* @return A new HttpServletSseServerTransportProvider instance
|
||||
* @throws IllegalStateException if objectMapper or messageEndpoint is not set
|
||||
* @throws IllegalStateException if jsonMapper or messageEndpoint is not set
|
||||
*/
|
||||
public HttpServletSseServerTransportProvider build() {
|
||||
if (objectMapper == null) {
|
||||
throw new IllegalStateException("ObjectMapper must be set");
|
||||
}
|
||||
if (messageEndpoint == null) {
|
||||
throw new IllegalStateException("MessageEndpoint must be set");
|
||||
}
|
||||
return new HttpServletSseServerTransportProvider(objectMapper, baseUrl, messageEndpoint, sseEndpoint,
|
||||
return new HttpServletSseServerTransportProvider(
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, baseUrl, messageEndpoint, sseEndpoint,
|
||||
keepAliveInterval, contextExtractor);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import java.io.PrintWriter;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpStatelessServerHandler;
|
||||
|
|
@ -48,7 +48,7 @@ public class HttpServletStatelessServerTransport extends HttpServlet implements
|
|||
|
||||
public static final String FAILED_TO_SEND_ERROR_RESPONSE = "Failed to send error response: {}";
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
private final String mcpEndpoint;
|
||||
|
||||
|
|
@ -58,13 +58,13 @@ public class HttpServletStatelessServerTransport extends HttpServlet implements
|
|||
|
||||
private volatile boolean isClosing = false;
|
||||
|
||||
private HttpServletStatelessServerTransport(ObjectMapper objectMapper, String mcpEndpoint,
|
||||
private HttpServletStatelessServerTransport(McpJsonMapper jsonMapper, String mcpEndpoint,
|
||||
McpTransportContextExtractor<HttpServletRequest> 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;
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ public class HttpServletStatelessServerTransport extends HttpServlet implements
|
|||
body.append(line);
|
||||
}
|
||||
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, body.toString());
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(jsonMapper, body.toString());
|
||||
|
||||
if (message instanceof McpSchema.JSONRPCRequest jsonrpcRequest) {
|
||||
try {
|
||||
|
|
@ -152,7 +152,7 @@ public class HttpServletStatelessServerTransport extends HttpServlet implements
|
|||
response.setCharacterEncoding(UTF_8);
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
|
||||
String jsonResponseText = objectMapper.writeValueAsString(jsonrpcResponse);
|
||||
String jsonResponseText = jsonMapper.writeValueAsString(jsonrpcResponse);
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(jsonResponseText);
|
||||
writer.flush();
|
||||
|
|
@ -203,7 +203,7 @@ public class HttpServletStatelessServerTransport extends HttpServlet implements
|
|||
response.setContentType(APPLICATION_JSON);
|
||||
response.setCharacterEncoding(UTF_8);
|
||||
response.setStatus(httpCode);
|
||||
String jsonError = objectMapper.writeValueAsString(mcpError);
|
||||
String jsonError = jsonMapper.writeValueAsString(mcpError);
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(jsonError);
|
||||
writer.flush();
|
||||
|
|
@ -236,7 +236,7 @@ public class HttpServletStatelessServerTransport extends HttpServlet implements
|
|||
*/
|
||||
public static class Builder {
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
private String mcpEndpoint = "/mcp";
|
||||
|
||||
|
|
@ -248,15 +248,15 @@ public class HttpServletStatelessServerTransport extends HttpServlet implements
|
|||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
|
@ -295,10 +295,9 @@ public class HttpServletStatelessServerTransport extends HttpServlet implements
|
|||
* @throws IllegalStateException if required parameters are not set
|
||||
*/
|
||||
public HttpServletStatelessServerTransport build() {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must be set");
|
||||
Assert.notNull(mcpEndpoint, "Message endpoint must be set");
|
||||
|
||||
return new HttpServletStatelessServerTransport(objectMapper, mcpEndpoint, contextExtractor);
|
||||
return new HttpServletStatelessServerTransport(jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
mcpEndpoint, contextExtractor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
|
|
@ -29,6 +28,7 @@ import io.modelcontextprotocol.spec.McpStreamableServerTransport;
|
|||
import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.ProtocolVersions;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.util.KeepAliveScheduler;
|
||||
import jakarta.servlet.AsyncContext;
|
||||
import jakarta.servlet.ServletException;
|
||||
|
|
@ -97,7 +97,7 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
*/
|
||||
private final boolean disallowDelete;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
private McpStreamableServerSession.Factory sessionFactory;
|
||||
|
||||
|
|
@ -121,22 +121,22 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
|
||||
/**
|
||||
* Constructs a new HttpServletStreamableServerTransportProvider instance.
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
* of messages.
|
||||
* @param jsonMapper The JsonMapper to use for JSON serialization/deserialization of
|
||||
* messages.
|
||||
* @param mcpEndpoint The endpoint URI where clients should send their JSON-RPC
|
||||
* messages via HTTP. This endpoint will handle GET, POST, and DELETE requests.
|
||||
* @param disallowDelete Whether to disallow DELETE requests on the endpoint.
|
||||
* @param contextExtractor The extractor for transport context from the request.
|
||||
* @throws IllegalArgumentException if any parameter is null
|
||||
*/
|
||||
private HttpServletStreamableServerTransportProvider(ObjectMapper objectMapper, String mcpEndpoint,
|
||||
private HttpServletStreamableServerTransportProvider(McpJsonMapper jsonMapper, String mcpEndpoint,
|
||||
boolean disallowDelete, McpTransportContextExtractor<HttpServletRequest> contextExtractor,
|
||||
Duration keepAliveInterval) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||
Assert.notNull(mcpEndpoint, "MCP endpoint must not be null");
|
||||
Assert.notNull(contextExtractor, "Context extractor must not be null");
|
||||
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.mcpEndpoint = mcpEndpoint;
|
||||
this.disallowDelete = disallowDelete;
|
||||
this.contextExtractor = contextExtractor;
|
||||
|
|
@ -392,7 +392,7 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
body.append(line);
|
||||
}
|
||||
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, body.toString());
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(jsonMapper, body.toString());
|
||||
|
||||
// Handle initialization request
|
||||
if (message instanceof McpSchema.JSONRPCRequest jsonrpcRequest
|
||||
|
|
@ -403,8 +403,8 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
return;
|
||||
}
|
||||
|
||||
McpSchema.InitializeRequest initializeRequest = objectMapper.convertValue(jsonrpcRequest.params(),
|
||||
new TypeReference<McpSchema.InitializeRequest>() {
|
||||
McpSchema.InitializeRequest initializeRequest = jsonMapper.convertValue(jsonrpcRequest.params(),
|
||||
new TypeRef<McpSchema.InitializeRequest>() {
|
||||
});
|
||||
McpStreamableServerSession.McpStreamableServerSessionInit init = this.sessionFactory
|
||||
.startSession(initializeRequest);
|
||||
|
|
@ -418,7 +418,7 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
response.setHeader(HttpHeaders.MCP_SESSION_ID, init.session().getId());
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
|
||||
String jsonResponse = objectMapper.writeValueAsString(new McpSchema.JSONRPCResponse(
|
||||
String jsonResponse = jsonMapper.writeValueAsString(new McpSchema.JSONRPCResponse(
|
||||
McpSchema.JSONRPC_VERSION, jsonrpcRequest.id(), initResult, null));
|
||||
|
||||
PrintWriter writer = response.getWriter();
|
||||
|
|
@ -578,7 +578,7 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
response.setContentType(APPLICATION_JSON);
|
||||
response.setCharacterEncoding(UTF_8);
|
||||
response.setStatus(httpCode);
|
||||
String jsonError = objectMapper.writeValueAsString(mcpError);
|
||||
String jsonError = jsonMapper.writeValueAsString(mcpError);
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(jsonError);
|
||||
writer.flush();
|
||||
|
|
@ -685,7 +685,7 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
return;
|
||||
}
|
||||
|
||||
String jsonText = objectMapper.writeValueAsString(message);
|
||||
String jsonText = jsonMapper.writeValueAsString(message);
|
||||
HttpServletStreamableServerTransportProvider.this.sendEvent(writer, MESSAGE_EVENT_TYPE, jsonText,
|
||||
messageId != null ? messageId : this.sessionId);
|
||||
logger.debug("Message sent to session {} with ID {}", this.sessionId, messageId);
|
||||
|
|
@ -702,15 +702,15 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
}
|
||||
|
||||
/**
|
||||
* Converts data from one type to another using the configured ObjectMapper.
|
||||
* Converts data from one type to another using the configured JsonMapper.
|
||||
* @param data The source data object to convert
|
||||
* @param typeRef The target type reference
|
||||
* @return The converted object of type T
|
||||
* @param <T> The target type
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -762,7 +762,7 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
*/
|
||||
public static class Builder {
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
private McpJsonMapper jsonMapper;
|
||||
|
||||
private String mcpEndpoint = "/mcp";
|
||||
|
||||
|
|
@ -774,15 +774,15 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
private Duration keepAliveInterval;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
|
@ -839,11 +839,10 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
* @throws IllegalStateException if required parameters are not set
|
||||
*/
|
||||
public HttpServletStreamableServerTransportProvider build() {
|
||||
Assert.notNull(this.objectMapper, "ObjectMapper must be set");
|
||||
Assert.notNull(this.mcpEndpoint, "MCP endpoint must be set");
|
||||
|
||||
return new HttpServletStreamableServerTransportProvider(this.objectMapper, this.mcpEndpoint,
|
||||
this.disallowDelete, this.contextExtractor, this.keepAliveInterval);
|
||||
return new HttpServletStreamableServerTransportProvider(
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, mcpEndpoint, disallowDelete,
|
||||
contextExtractor, keepAliveInterval);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ import java.util.concurrent.Executors;
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.JSONRPCMessage;
|
||||
|
|
@ -25,6 +24,7 @@ import io.modelcontextprotocol.spec.McpServerTransport;
|
|||
import io.modelcontextprotocol.spec.McpServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.ProtocolVersions;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
|
@ -44,7 +44,7 @@ public class StdioServerTransportProvider implements McpServerTransportProvider
|
|||
|
||||
private static final Logger logger = LoggerFactory.getLogger(StdioServerTransportProvider.class);
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final McpJsonMapper jsonMapper;
|
||||
|
||||
private final InputStream inputStream;
|
||||
|
||||
|
|
@ -56,36 +56,28 @@ public class StdioServerTransportProvider implements McpServerTransportProvider
|
|||
|
||||
private final Sinks.One<Void> inboundReady = Sinks.one();
|
||||
|
||||
/**
|
||||
* Creates a new StdioServerTransportProvider with a default ObjectMapper and System
|
||||
* streams.
|
||||
*/
|
||||
public StdioServerTransportProvider() {
|
||||
this(new ObjectMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new StdioServerTransportProvider with the specified ObjectMapper and
|
||||
* System streams.
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
* @param jsonMapper The JsonMapper to use for JSON serialization/deserialization
|
||||
*/
|
||||
public StdioServerTransportProvider(ObjectMapper objectMapper) {
|
||||
this(objectMapper, System.in, System.out);
|
||||
public StdioServerTransportProvider(McpJsonMapper jsonMapper) {
|
||||
this(jsonMapper, System.in, System.out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new StdioServerTransportProvider with the specified ObjectMapper and
|
||||
* streams.
|
||||
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
|
||||
* @param jsonMapper The JsonMapper to use for JSON serialization/deserialization
|
||||
* @param inputStream The input stream to read from
|
||||
* @param outputStream The output stream to write to
|
||||
*/
|
||||
public StdioServerTransportProvider(ObjectMapper objectMapper, InputStream inputStream, OutputStream outputStream) {
|
||||
Assert.notNull(objectMapper, "The ObjectMapper can not be null");
|
||||
public StdioServerTransportProvider(McpJsonMapper jsonMapper, InputStream inputStream, OutputStream outputStream) {
|
||||
Assert.notNull(jsonMapper, "The JsonMapper can not be null");
|
||||
Assert.notNull(inputStream, "The InputStream can not be null");
|
||||
Assert.notNull(outputStream, "The OutputStream can not be null");
|
||||
|
||||
this.objectMapper = objectMapper;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.inputStream = inputStream;
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
|
|
@ -165,8 +157,8 @@ public class StdioServerTransportProvider implements McpServerTransportProvider
|
|||
}
|
||||
|
||||
@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
|
||||
|
|
@ -219,7 +211,7 @@ public class StdioServerTransportProvider implements McpServerTransportProvider
|
|||
logger.debug("Received JSON message: {}", line);
|
||||
|
||||
try {
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper,
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(jsonMapper,
|
||||
line);
|
||||
if (!this.inboundSink.tryEmitNext(message).isSuccess()) {
|
||||
// logIfNotClosing("Failed to enqueue message");
|
||||
|
|
@ -263,7 +255,7 @@ public class StdioServerTransportProvider implements McpServerTransportProvider
|
|||
.handle((message, sink) -> {
|
||||
if (message != null && !isClosing.get()) {
|
||||
try {
|
||||
String jsonMessage = objectMapper.writeValueAsString(message);
|
||||
String jsonMessage = jsonMapper.writeValueAsString(message);
|
||||
// Escape any embedded newlines in the JSON message as per spec
|
||||
jsonMessage = jsonMessage.replace("\r\n", "\\n").replace("\n", "\\n").replace("\r", "\\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.spec;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.networknt.schema.JsonSchema;
|
||||
import com.networknt.schema.JsonSchemaFactory;
|
||||
import com.networknt.schema.SpecVersion;
|
||||
import com.networknt.schema.ValidationMessage;
|
||||
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link JsonSchemaValidator} interface. This class
|
||||
* provides methods to validate structured content against a JSON schema. It uses the
|
||||
* NetworkNT JSON Schema Validator library for validation.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public class DefaultJsonSchemaValidator implements JsonSchemaValidator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultJsonSchemaValidator.class);
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final JsonSchemaFactory schemaFactory;
|
||||
|
||||
// TODO: Implement a strategy to purge the cache (TTL, size limit, etc.)
|
||||
private final ConcurrentHashMap<String, JsonSchema> schemaCache;
|
||||
|
||||
public DefaultJsonSchemaValidator() {
|
||||
this(new ObjectMapper());
|
||||
}
|
||||
|
||||
public DefaultJsonSchemaValidator(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
|
||||
this.schemaCache = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResponse validate(Map<String, Object> schema, Object structuredContent) {
|
||||
|
||||
Assert.notNull(schema, "Schema must not be null");
|
||||
Assert.notNull(structuredContent, "Structured content must not be null");
|
||||
|
||||
try {
|
||||
|
||||
JsonNode jsonStructuredOutput = this.objectMapper.valueToTree(structuredContent);
|
||||
|
||||
Set<ValidationMessage> validationResult = this.getOrCreateJsonSchema(schema).validate(jsonStructuredOutput);
|
||||
|
||||
// Check if validation passed
|
||||
if (!validationResult.isEmpty()) {
|
||||
return ValidationResponse
|
||||
.asInvalid("Validation failed: structuredContent does not match tool outputSchema. "
|
||||
+ "Validation errors: " + validationResult);
|
||||
}
|
||||
|
||||
return ValidationResponse.asValid(jsonStructuredOutput.toString());
|
||||
|
||||
}
|
||||
catch (JsonProcessingException e) {
|
||||
logger.error("Failed to validate CallToolResult: Error parsing schema: {}", e);
|
||||
return ValidationResponse.asInvalid("Error parsing tool JSON Schema: " + e.getMessage());
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("Failed to validate CallToolResult: Unexpected error: {}", e);
|
||||
return ValidationResponse.asInvalid("Unexpected validation error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a cached JsonSchema or creates and caches a new one.
|
||||
* @param schema the schema map to convert
|
||||
* @return the compiled JsonSchema
|
||||
* @throws JsonProcessingException if schema processing fails
|
||||
*/
|
||||
private JsonSchema getOrCreateJsonSchema(Map<String, Object> schema) throws JsonProcessingException {
|
||||
// Generate cache key based on schema content
|
||||
String cacheKey = this.generateCacheKey(schema);
|
||||
|
||||
// Try to get from cache first
|
||||
JsonSchema cachedSchema = this.schemaCache.get(cacheKey);
|
||||
if (cachedSchema != null) {
|
||||
return cachedSchema;
|
||||
}
|
||||
|
||||
// Create new schema if not in cache
|
||||
JsonSchema newSchema = this.createJsonSchema(schema);
|
||||
|
||||
// Cache the schema
|
||||
JsonSchema existingSchema = this.schemaCache.putIfAbsent(cacheKey, newSchema);
|
||||
return existingSchema != null ? existingSchema : newSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new JsonSchema from the given schema map.
|
||||
* @param schema the schema map
|
||||
* @return the compiled JsonSchema
|
||||
* @throws JsonProcessingException if schema processing fails
|
||||
*/
|
||||
private JsonSchema createJsonSchema(Map<String, Object> schema) throws JsonProcessingException {
|
||||
// Convert schema map directly to JsonNode (more efficient than string
|
||||
// serialization)
|
||||
JsonNode schemaNode = this.objectMapper.valueToTree(schema);
|
||||
|
||||
// Handle case where ObjectMapper might return null (e.g., in mocked scenarios)
|
||||
if (schemaNode == null) {
|
||||
throw new JsonProcessingException("Failed to convert schema to JsonNode") {
|
||||
};
|
||||
}
|
||||
|
||||
// Handle additionalProperties setting
|
||||
if (schemaNode.isObject()) {
|
||||
ObjectNode objectSchemaNode = (ObjectNode) schemaNode;
|
||||
if (!objectSchemaNode.has("additionalProperties")) {
|
||||
// Clone the node before modification to avoid mutating the original
|
||||
objectSchemaNode = objectSchemaNode.deepCopy();
|
||||
objectSchemaNode.put("additionalProperties", false);
|
||||
schemaNode = objectSchemaNode;
|
||||
}
|
||||
}
|
||||
|
||||
return this.schemaFactory.getSchema(schemaNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a cache key for the given schema map.
|
||||
* @param schema the schema map
|
||||
* @return a cache key string
|
||||
*/
|
||||
protected String generateCacheKey(Map<String, Object> schema) {
|
||||
if (schema.containsKey("$id")) {
|
||||
// Use the (optional) "$id" field as the cache key if present
|
||||
return "" + schema.get("$id");
|
||||
}
|
||||
// Fall back to schema's hash code as a simple cache key
|
||||
// For more sophisticated caching, could use content-based hashing
|
||||
return String.valueOf(schema.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the schema cache. Useful for testing or memory management.
|
||||
*/
|
||||
public void clearCache() {
|
||||
this.schemaCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current size of the schema cache.
|
||||
* @return the number of cached schemas
|
||||
*/
|
||||
public int getCacheSize() {
|
||||
return this.schemaCache.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package io.modelcontextprotocol.spec;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -254,7 +254,7 @@ public class McpClientSession implements McpSession {
|
|||
* @return A Mono containing the response
|
||||
*/
|
||||
@Override
|
||||
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) {
|
||||
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeRef<T> typeRef) {
|
||||
String requestId = this.generateRequestId();
|
||||
|
||||
return Mono.deferContextual(ctx -> Mono.<McpSchema.JSONRPCResponse>create(pendingResponseSink -> {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
|
||||
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.util.Assert;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -109,8 +110,6 @@ public final class McpSchema {
|
|||
// Elicitation Methods
|
||||
public static final String METHOD_ELICITATION_CREATE = "elicitation/create";
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
// ---------------------------
|
||||
// JSON-RPC Error Codes
|
||||
// ---------------------------
|
||||
|
|
@ -176,12 +175,12 @@ public final class McpSchema {
|
|||
|
||||
}
|
||||
|
||||
private static final TypeReference<HashMap<String, Object>> MAP_TYPE_REF = new TypeReference<>() {
|
||||
private static final TypeRef<HashMap<String, Object>> MAP_TYPE_REF = new TypeRef<>() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Deserializes a JSON string into a JSONRPCMessage object.
|
||||
* @param objectMapper The ObjectMapper instance to use for deserialization
|
||||
* @param jsonMapper The JsonMapper instance to use for deserialization
|
||||
* @param jsonText The JSON string to deserialize
|
||||
* @return A JSONRPCMessage instance using either the {@link JSONRPCRequest},
|
||||
* {@link JSONRPCNotification}, or {@link JSONRPCResponse} classes.
|
||||
|
|
@ -189,22 +188,22 @@ public final class McpSchema {
|
|||
* @throws IllegalArgumentException If the JSON structure doesn't match any known
|
||||
* message type
|
||||
*/
|
||||
public static JSONRPCMessage deserializeJsonRpcMessage(ObjectMapper objectMapper, String jsonText)
|
||||
public static JSONRPCMessage deserializeJsonRpcMessage(McpJsonMapper jsonMapper, String jsonText)
|
||||
throws IOException {
|
||||
|
||||
logger.debug("Received JSON message: {}", jsonText);
|
||||
|
||||
var map = objectMapper.readValue(jsonText, MAP_TYPE_REF);
|
||||
var map = jsonMapper.readValue(jsonText, MAP_TYPE_REF);
|
||||
|
||||
// Determine message type based on specific JSON structure
|
||||
if (map.containsKey("method") && map.containsKey("id")) {
|
||||
return objectMapper.convertValue(map, JSONRPCRequest.class);
|
||||
return jsonMapper.convertValue(map, JSONRPCRequest.class);
|
||||
}
|
||||
else if (map.containsKey("method") && !map.containsKey("id")) {
|
||||
return objectMapper.convertValue(map, JSONRPCNotification.class);
|
||||
return jsonMapper.convertValue(map, JSONRPCNotification.class);
|
||||
}
|
||||
else if (map.containsKey("result") || map.containsKey("error")) {
|
||||
return objectMapper.convertValue(map, JSONRPCResponse.class);
|
||||
return jsonMapper.convertValue(map, JSONRPCResponse.class);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Cannot deserialize JSONRPCMessage: " + jsonText);
|
||||
|
|
@ -1270,53 +1269,6 @@ public final class McpSchema {
|
|||
@JsonProperty("annotations") ToolAnnotations annotations,
|
||||
@JsonProperty("_meta") Map<String, Object> meta) { // @formatter:on
|
||||
|
||||
/**
|
||||
* @deprecated Only exists for backwards-compatibility purposes. Use
|
||||
* {@link Tool#builder()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public Tool(String name, String description, JsonSchema inputSchema, ToolAnnotations annotations) {
|
||||
this(name, null, description, inputSchema, null, annotations, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Only exists for backwards-compatibility purposes. Use
|
||||
* {@link Tool#builder()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public Tool(String name, String description, String inputSchema) {
|
||||
this(name, null, description, parseSchema(inputSchema), null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Only exists for backwards-compatibility purposes. Use
|
||||
* {@link Tool#builder()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public Tool(String name, String description, String schema, ToolAnnotations annotations) {
|
||||
this(name, null, description, parseSchema(schema), null, annotations, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Only exists for backwards-compatibility purposes. Use
|
||||
* {@link Tool#builder()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public Tool(String name, String description, String inputSchema, String outputSchema,
|
||||
ToolAnnotations annotations) {
|
||||
this(name, null, description, parseSchema(inputSchema), schemaToMap(outputSchema), annotations, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Only exists for backwards-compatibility purposes. Use
|
||||
* {@link Tool#builder()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public Tool(String name, String title, String description, String inputSchema, String outputSchema,
|
||||
ToolAnnotations annotations) {
|
||||
this(name, title, description, parseSchema(inputSchema), schemaToMap(outputSchema), annotations, null);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
|
@ -1357,8 +1309,8 @@ public final class McpSchema {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder inputSchema(String inputSchema) {
|
||||
this.inputSchema = parseSchema(inputSchema);
|
||||
public Builder inputSchema(McpJsonMapper jsonMapper, String inputSchema) {
|
||||
this.inputSchema = parseSchema(jsonMapper, inputSchema);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -1367,8 +1319,8 @@ public final class McpSchema {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder outputSchema(String outputSchema) {
|
||||
this.outputSchema = schemaToMap(outputSchema);
|
||||
public Builder outputSchema(McpJsonMapper jsonMapper, String outputSchema) {
|
||||
this.outputSchema = schemaToMap(jsonMapper, outputSchema);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -1390,18 +1342,18 @@ public final class McpSchema {
|
|||
}
|
||||
}
|
||||
|
||||
private static Map<String, Object> schemaToMap(String schema) {
|
||||
private static Map<String, Object> schemaToMap(McpJsonMapper jsonMapper, String schema) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(schema, MAP_TYPE_REF);
|
||||
return jsonMapper.readValue(schema, MAP_TYPE_REF);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException("Invalid schema: " + schema, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonSchema parseSchema(String schema) {
|
||||
private static JsonSchema parseSchema(McpJsonMapper jsonMapper, String schema) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(schema, JsonSchema.class);
|
||||
return jsonMapper.readValue(schema, JsonSchema.class);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException("Invalid schema: " + schema, e);
|
||||
|
|
@ -1425,17 +1377,17 @@ public final class McpSchema {
|
|||
@JsonProperty("arguments") Map<String, Object> arguments,
|
||||
@JsonProperty("_meta") Map<String, Object> meta) implements Request { // @formatter:on
|
||||
|
||||
public CallToolRequest(String name, String jsonArguments) {
|
||||
this(name, parseJsonArguments(jsonArguments), null);
|
||||
public CallToolRequest(McpJsonMapper jsonMapper, String name, String jsonArguments) {
|
||||
this(name, parseJsonArguments(jsonMapper, jsonArguments), null);
|
||||
}
|
||||
|
||||
public CallToolRequest(String name, Map<String, Object> arguments) {
|
||||
this(name, arguments, null);
|
||||
}
|
||||
|
||||
private static Map<String, Object> parseJsonArguments(String jsonArguments) {
|
||||
private static Map<String, Object> parseJsonArguments(McpJsonMapper jsonMapper, String jsonArguments) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(jsonArguments, MAP_TYPE_REF);
|
||||
return jsonMapper.readValue(jsonArguments, MAP_TYPE_REF);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException("Invalid arguments: " + jsonArguments, e);
|
||||
|
|
@ -1464,8 +1416,8 @@ public final class McpSchema {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder arguments(String jsonArguments) {
|
||||
this.arguments = parseJsonArguments(jsonArguments);
|
||||
public Builder arguments(McpJsonMapper jsonMapper, String jsonArguments) {
|
||||
this.arguments = parseJsonArguments(jsonMapper, jsonArguments);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -1576,10 +1528,10 @@ public final class McpSchema {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder structuredContent(String structuredContent) {
|
||||
public Builder structuredContent(McpJsonMapper jsonMapper, String structuredContent) {
|
||||
Assert.hasText(structuredContent, "structuredContent must not be empty");
|
||||
try {
|
||||
this.structuredContent = OBJECT_MAPPER.readValue(structuredContent, MAP_TYPE_REF);
|
||||
this.structuredContent = jsonMapper.readValue(structuredContent, MAP_TYPE_REF);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException("Invalid structured content: " + structuredContent, e);
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpAsyncServerExchange;
|
||||
import io.modelcontextprotocol.server.McpInitRequestHandler;
|
||||
import io.modelcontextprotocol.server.McpNotificationHandler;
|
||||
import io.modelcontextprotocol.server.McpRequestHandler;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -153,7 +153,7 @@ public class McpServerSession implements McpLoggableSession {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) {
|
||||
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeRef<T> typeRef) {
|
||||
String requestId = this.generateRequestId();
|
||||
|
||||
return Mono.<McpSchema.JSONRPCResponse>create(sink -> {
|
||||
|
|
@ -259,7 +259,7 @@ public class McpServerSession implements McpLoggableSession {
|
|||
if (McpSchema.METHOD_INITIALIZE.equals(request.method())) {
|
||||
// TODO handle situation where already initialized!
|
||||
McpSchema.InitializeRequest initializeRequest = transport.unmarshalFrom(request.params(),
|
||||
new TypeReference<McpSchema.InitializeRequest>() {
|
||||
new TypeRef<McpSchema.InitializeRequest>() {
|
||||
});
|
||||
|
||||
this.state.lazySet(STATE_INITIALIZING);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package io.modelcontextprotocol.spec;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
|
|
@ -37,7 +37,7 @@ public interface McpSession {
|
|||
* @param typeRef the TypeReference describing the expected response type
|
||||
* @return a Mono that will emit the response when received
|
||||
*/
|
||||
<T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef);
|
||||
<T> Mono<T> sendRequest(String method, Object requestParams, TypeRef<T> typeRef);
|
||||
|
||||
/**
|
||||
* Sends a notification to the model client or server without parameters.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import java.util.function.Supplier;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpAsyncServerExchange;
|
||||
|
|
@ -110,7 +110,7 @@ public class McpStreamableServerSession implements McpLoggableSession {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) {
|
||||
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeRef<T> typeRef) {
|
||||
return Mono.defer(() -> {
|
||||
McpLoggableSession listeningStream = this.listeningStreamRef.get();
|
||||
return listeningStream.sendRequest(method, requestParams, typeRef);
|
||||
|
|
@ -347,7 +347,7 @@ public class McpStreamableServerSession implements McpLoggableSession {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) {
|
||||
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeRef<T> typeRef) {
|
||||
String requestId = McpStreamableServerSession.this.generateRequestId();
|
||||
|
||||
McpStreamableServerSession.this.requestIdToStream.put(requestId, this);
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ package io.modelcontextprotocol.spec;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.modelcontextprotocol.spec.McpSchema.JSONRPCMessage;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
|
|
@ -77,7 +77,7 @@ public interface McpTransport {
|
|||
* @param typeRef the type reference for the object to unmarshal
|
||||
* @return the unmarshalled object
|
||||
*/
|
||||
<T> T unmarshalFrom(Object data, TypeReference<T> typeRef);
|
||||
<T> T unmarshalFrom(Object data, TypeRef<T> typeRef);
|
||||
|
||||
default List<String> protocolVersions() {
|
||||
return List.of(ProtocolVersions.MCP_2024_11_05);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue