Move mcp-json into mcp-core, add OSGi support
Co-authored-by: Luca Chang <131398524+LucaButBoring@users.noreply.github.com> Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
This commit is contained in:
parent
be5ec12e1b
commit
c3b9ab09ea
47 changed files with 368 additions and 353 deletions
|
|
@ -40,13 +40,6 @@
|
|||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MCP JSON -->
|
||||
<dependency>
|
||||
<groupId>io.modelcontextprotocol.sdk</groupId>
|
||||
<artifactId>mcp-json</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MCP JSON Jackson -->
|
||||
<dependency>
|
||||
<groupId>io.modelcontextprotocol.sdk</groupId>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
Automatic-Module-Name: ${project.groupId}.${project.artifactId}
|
||||
Import-Package: jakarta.*;resolution:=optional, \
|
||||
*;
|
||||
Service-Component: OSGI-INF/io.modelcontextprotocol.json.McpJsonDefaults.xml
|
||||
Export-Package: io.modelcontextprotocol.*;version="${version}";-noimport:=true
|
||||
-noimportjava: true;
|
||||
-nouses: true;
|
||||
|
|
@ -65,11 +66,6 @@
|
|||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.modelcontextprotocol.sdk</groupId>
|
||||
<artifactId>mcp-json</artifactId>
|
||||
<version>0.18.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
|
@ -97,14 +93,6 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>io.modelcontextprotocol.sdk</groupId>
|
||||
<artifactId>mcp-json-jackson3</artifactId>
|
||||
<version>0.18.0-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
|
|
@ -112,6 +100,12 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>tools.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson3.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.netty</groupId>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
package io.modelcontextprotocol.client;
|
||||
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.json.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
|
||||
import io.modelcontextprotocol.spec.McpClientTransport;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
|
|
@ -491,9 +492,12 @@ public interface McpClient {
|
|||
|
||||
McpClientFeatures.Async asyncFeatures = McpClientFeatures.Async.fromSync(syncFeatures);
|
||||
|
||||
return new McpSyncClient(new McpAsyncClient(transport, this.requestTimeout, this.initializationTimeout,
|
||||
jsonSchemaValidator != null ? jsonSchemaValidator : JsonSchemaValidator.getDefault(),
|
||||
asyncFeatures), this.contextProvider);
|
||||
return new McpSyncClient(
|
||||
new McpAsyncClient(transport, this.requestTimeout, this.initializationTimeout,
|
||||
jsonSchemaValidator != null ? jsonSchemaValidator
|
||||
: McpJsonDefaults.getDefaultJsonSchemaValidator(),
|
||||
asyncFeatures),
|
||||
this.contextProvider);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -826,7 +830,7 @@ public interface McpClient {
|
|||
*/
|
||||
public McpAsyncClient build() {
|
||||
var jsonSchemaValidator = (this.jsonSchemaValidator != null) ? this.jsonSchemaValidator
|
||||
: JsonSchemaValidator.getDefault();
|
||||
: McpJsonDefaults.getDefaultJsonSchemaValidator();
|
||||
return new McpAsyncClient(this.transport, this.requestTimeout, this.initializationTimeout,
|
||||
jsonSchemaValidator,
|
||||
new McpClientFeatures.Async(this.clientInfo, this.capabilities, this.roots,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import io.modelcontextprotocol.client.transport.ResponseSubscribers.ResponseEven
|
|||
import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpClientRequestCustomizer;
|
||||
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.json.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.spec.HttpHeaders;
|
||||
|
|
@ -327,7 +328,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
public HttpClientSseClientTransport build() {
|
||||
HttpClient httpClient = this.clientBuilder.connectTimeout(this.connectTimeout).build();
|
||||
return new HttpClientSseClientTransport(httpClient, requestBuilder, baseUri, sseEndpoint,
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, httpRequestCustomizer);
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, httpRequestCustomizer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import io.modelcontextprotocol.client.transport.ResponseSubscribers.ResponseEven
|
|||
import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpClientRequestCustomizer;
|
||||
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.json.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.spec.ClosedMcpTransportSession;
|
||||
|
|
@ -842,9 +843,10 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
|
|||
*/
|
||||
public HttpClientStreamableHttpTransport build() {
|
||||
HttpClient httpClient = this.clientBuilder.connectTimeout(this.connectTimeout).build();
|
||||
return new HttpClientStreamableHttpTransport(jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
httpClient, requestBuilder, baseUri, endpoint, resumableStreams, openConnectionOnStartup,
|
||||
httpRequestCustomizer, supportedProtocolVersions);
|
||||
return new HttpClientStreamableHttpTransport(
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, httpClient,
|
||||
requestBuilder, baseUri, endpoint, resumableStreams, openConnectionOnStartup, httpRequestCustomizer,
|
||||
supportedProtocolVersions);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* Copyright 2026 - 2026 the original author or authors.
|
||||
*/
|
||||
package io.modelcontextprotocol.json;
|
||||
|
||||
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
|
||||
import io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier;
|
||||
import io.modelcontextprotocol.util.McpServiceLoader;
|
||||
|
||||
/**
|
||||
* This class is to be used to provide access to the default McpJsonMapper and to the
|
||||
* default JsonSchemaValidator instances via the static methods: getDefaultMcpJsonMapper
|
||||
* and getDefaultJsonSchemaValidator.
|
||||
* <p>
|
||||
* The initialization of (singleton) instances of this class is different in non-OSGi
|
||||
* environments and OSGi environments. Specifically, in non-OSGi environments The
|
||||
* McpJsonDefaults class will be loaded by whatever classloader is used to call one of the
|
||||
* existing static get methods for the first time. For servers, this will usually be in
|
||||
* response to the creation of the first McpServer instance. At that first time, the
|
||||
* mcpMapperServiceLoader and mcpValidatorServiceLoader will be null, and the
|
||||
* McpJsonDefaults constructor will be called, creating/initializing the
|
||||
* mcpMapperServiceLoader and the mcpValidatorServiceLoader...which will then be used to
|
||||
* call the ServiceLoader.load method.
|
||||
* <p>
|
||||
* In OSGi environments, upon bundle activation SCR will create a new (singleton) instance
|
||||
* of McpJsonDefaults (via the constructor), and then inject suppliers via the
|
||||
* setMcpJsonMapperSupplier and setJsonSchemaValidatorSupplier methods with the
|
||||
* SCR-discovered instances of those services. This does depend upon the jars/bundles
|
||||
* providing those suppliers to be started/activated. This SCR behavior is dictated by xml
|
||||
* files in OSGi-INF directory of mcp-core (this project/jar/bundle), and the jsonmapper
|
||||
* and jsonschemvalidator provider jars/bundles (e.g. mcp-json-jackson2, 3, or others).
|
||||
*/
|
||||
public class McpJsonDefaults {
|
||||
|
||||
protected static McpServiceLoader<McpJsonMapperSupplier, McpJsonMapper> mcpMapperServiceLoader;
|
||||
|
||||
protected static McpServiceLoader<JsonSchemaValidatorSupplier, JsonSchemaValidator> mcpValidatorServiceLoader;
|
||||
|
||||
public McpJsonDefaults() {
|
||||
mcpMapperServiceLoader = new McpServiceLoader<McpJsonMapperSupplier, McpJsonMapper>(
|
||||
McpJsonMapperSupplier.class);
|
||||
mcpValidatorServiceLoader = new McpServiceLoader<JsonSchemaValidatorSupplier, JsonSchemaValidator>(
|
||||
JsonSchemaValidatorSupplier.class);
|
||||
}
|
||||
|
||||
void setMcpJsonMapperSupplier(McpJsonMapperSupplier supplier) {
|
||||
mcpMapperServiceLoader.setSupplier(supplier);
|
||||
}
|
||||
|
||||
void unsetMcpJsonMapperSupplier(McpJsonMapperSupplier supplier) {
|
||||
mcpMapperServiceLoader.unsetSupplier(supplier);
|
||||
}
|
||||
|
||||
public synchronized static McpJsonMapper getDefaultMcpJsonMapper() {
|
||||
if (mcpMapperServiceLoader == null) {
|
||||
new McpJsonDefaults();
|
||||
}
|
||||
return mcpMapperServiceLoader.getDefault();
|
||||
}
|
||||
|
||||
void setJsonSchemaValidatorSupplier(JsonSchemaValidatorSupplier supplier) {
|
||||
mcpValidatorServiceLoader.setSupplier(supplier);
|
||||
}
|
||||
|
||||
void unsetJsonSchemaValidatorSupplier(JsonSchemaValidatorSupplier supplier) {
|
||||
mcpValidatorServiceLoader.unsetSupplier(supplier);
|
||||
}
|
||||
|
||||
public synchronized static JsonSchemaValidator getDefaultJsonSchemaValidator() {
|
||||
if (mcpValidatorServiceLoader == null) {
|
||||
new McpJsonDefaults();
|
||||
}
|
||||
return mcpValidatorServiceLoader.getDefault();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2025 - 2025 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.json;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Abstraction for JSON serialization/deserialization to decouple the SDK from any
|
||||
* specific JSON library. A default implementation backed by Jackson is provided in
|
||||
* io.modelcontextprotocol.spec.json.jackson.JacksonJsonMapper.
|
||||
*/
|
||||
public interface McpJsonMapper {
|
||||
|
||||
/**
|
||||
* Deserialize JSON string into a target type.
|
||||
* @param content JSON as String
|
||||
* @param type target class
|
||||
* @return deserialized instance
|
||||
* @param <T> generic type
|
||||
* @throws IOException on parse errors
|
||||
*/
|
||||
<T> T readValue(String content, Class<T> type) throws IOException;
|
||||
|
||||
/**
|
||||
* Deserialize JSON bytes into a target type.
|
||||
* @param content JSON as bytes
|
||||
* @param type target class
|
||||
* @return deserialized instance
|
||||
* @param <T> generic type
|
||||
* @throws IOException on parse errors
|
||||
*/
|
||||
<T> T readValue(byte[] content, Class<T> type) throws IOException;
|
||||
|
||||
/**
|
||||
* Deserialize JSON string into a parameterized target type.
|
||||
* @param content JSON as String
|
||||
* @param type parameterized type reference
|
||||
* @return deserialized instance
|
||||
* @param <T> generic type
|
||||
* @throws IOException on parse errors
|
||||
*/
|
||||
<T> T readValue(String content, TypeRef<T> type) throws IOException;
|
||||
|
||||
/**
|
||||
* Deserialize JSON bytes into a parameterized target type.
|
||||
* @param content JSON as bytes
|
||||
* @param type parameterized type reference
|
||||
* @return deserialized instance
|
||||
* @param <T> generic type
|
||||
* @throws IOException on parse errors
|
||||
*/
|
||||
<T> T readValue(byte[] content, TypeRef<T> type) throws IOException;
|
||||
|
||||
/**
|
||||
* Convert a value to a given type, useful for mapping nested JSON structures.
|
||||
* @param fromValue source value
|
||||
* @param type target class
|
||||
* @return converted value
|
||||
* @param <T> generic type
|
||||
*/
|
||||
<T> T convertValue(Object fromValue, Class<T> type);
|
||||
|
||||
/**
|
||||
* Convert a value to a given parameterized type.
|
||||
* @param fromValue source value
|
||||
* @param type target type reference
|
||||
* @return converted value
|
||||
* @param <T> generic type
|
||||
*/
|
||||
<T> T convertValue(Object fromValue, TypeRef<T> type);
|
||||
|
||||
/**
|
||||
* Serialize an object to JSON string.
|
||||
* @param value object to serialize
|
||||
* @return JSON as String
|
||||
* @throws IOException on serialization errors
|
||||
*/
|
||||
String writeValueAsString(Object value) throws IOException;
|
||||
|
||||
/**
|
||||
* Serialize an object to JSON bytes.
|
||||
* @param value object to serialize
|
||||
* @return JSON as bytes
|
||||
* @throws IOException on serialization errors
|
||||
*/
|
||||
byte[] writeValueAsBytes(Object value) throws IOException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright 2025 - 2025 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.json;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Strategy interface for resolving a {@link McpJsonMapper}.
|
||||
*/
|
||||
public interface McpJsonMapperSupplier extends Supplier<McpJsonMapper> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2025 - 2025 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.json;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Captures generic type information at runtime for parameterized JSON (de)serialization.
|
||||
* Usage: TypeRef<List<Foo>> ref = new TypeRef<>(){};
|
||||
*/
|
||||
public abstract class TypeRef<T> {
|
||||
|
||||
private final Type type;
|
||||
|
||||
/**
|
||||
* Constructs a new TypeRef instance, capturing the generic type information of the
|
||||
* subclass. This constructor should be called from an anonymous subclass to capture
|
||||
* the actual type arguments. For example: <pre>
|
||||
* TypeRef<List<Foo>> ref = new TypeRef<>(){};
|
||||
* </pre>
|
||||
* @throws IllegalStateException if TypeRef is not subclassed with actual type
|
||||
* information
|
||||
*/
|
||||
protected TypeRef() {
|
||||
Type superClass = getClass().getGenericSuperclass();
|
||||
if (superClass instanceof Class) {
|
||||
throw new IllegalStateException("TypeRef constructed without actual type information");
|
||||
}
|
||||
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the captured type information.
|
||||
* @return the Type representing the actual type argument captured by this TypeRef
|
||||
* instance
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
*/
|
||||
package io.modelcontextprotocol.json.schema;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface for validating structured content against a JSON schema. This interface
|
||||
* defines a method to validate structured content based on the provided output schema.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public interface JsonSchemaValidator {
|
||||
|
||||
/**
|
||||
* Represents the result of a validation operation.
|
||||
*
|
||||
* @param valid Indicates whether the validation was successful.
|
||||
* @param errorMessage An error message if the validation failed, otherwise null.
|
||||
* @param jsonStructuredOutput The text structured content in JSON format if the
|
||||
* validation was successful, otherwise null.
|
||||
*/
|
||||
record ValidationResponse(boolean valid, String errorMessage, String jsonStructuredOutput) {
|
||||
|
||||
public static ValidationResponse asValid(String jsonStructuredOutput) {
|
||||
return new ValidationResponse(true, null, jsonStructuredOutput);
|
||||
}
|
||||
|
||||
public static ValidationResponse asInvalid(String message) {
|
||||
return new ValidationResponse(false, message, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the structured content against the provided JSON schema.
|
||||
* @param schema The JSON schema to validate against.
|
||||
* @param structuredContent The structured content to validate.
|
||||
* @return A ValidationResponse indicating whether the validation was successful or
|
||||
* not.
|
||||
*/
|
||||
ValidationResponse validate(Map<String, Object> schema, Object structuredContent);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2025 - 2025 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.json.schema;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A supplier interface that provides a {@link JsonSchemaValidator} instance.
|
||||
* Implementations of this interface are expected to return a new or cached instance of
|
||||
* {@link JsonSchemaValidator} when {@link #get()} is invoked.
|
||||
*
|
||||
* @see JsonSchemaValidator
|
||||
* @see Supplier
|
||||
*/
|
||||
public interface JsonSchemaValidatorSupplier extends Supplier<JsonSchemaValidator> {
|
||||
|
||||
}
|
||||
|
|
@ -4,7 +4,17 @@
|
|||
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.json.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
|
|
@ -18,11 +28,6 @@ import io.modelcontextprotocol.util.McpUriTemplateManagerFactory;
|
|||
import io.modelcontextprotocol.util.ToolNameValidator;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Factory class for creating Model Context Protocol (MCP) servers. MCP servers expose
|
||||
* tools, resources, and prompts to AI models through a standardized interface.
|
||||
|
|
@ -235,10 +240,11 @@ public interface McpServer {
|
|||
this.instructions);
|
||||
|
||||
var jsonSchemaValidator = (this.jsonSchemaValidator != null) ? this.jsonSchemaValidator
|
||||
: JsonSchemaValidator.getDefault();
|
||||
: McpJsonDefaults.getDefaultJsonSchemaValidator();
|
||||
|
||||
return new McpAsyncServer(transportProvider, jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
features, requestTimeout, uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
return new McpAsyncServer(transportProvider,
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, features,
|
||||
requestTimeout, uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -262,9 +268,10 @@ public interface McpServer {
|
|||
this.resources, this.resourceTemplates, this.prompts, this.completions, this.rootsChangeHandlers,
|
||||
this.instructions);
|
||||
var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator
|
||||
: JsonSchemaValidator.getDefault();
|
||||
return new McpAsyncServer(transportProvider, jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
features, requestTimeout, uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
: McpJsonDefaults.getDefaultJsonSchemaValidator();
|
||||
return new McpAsyncServer(transportProvider,
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, features,
|
||||
requestTimeout, uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -851,9 +858,9 @@ public interface McpServer {
|
|||
this.immediateExecution);
|
||||
|
||||
var asyncServer = new McpAsyncServer(transportProvider,
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, asyncFeatures, requestTimeout,
|
||||
uriTemplateManagerFactory,
|
||||
jsonSchemaValidator != null ? jsonSchemaValidator : JsonSchemaValidator.getDefault());
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, asyncFeatures,
|
||||
requestTimeout, uriTemplateManagerFactory, jsonSchemaValidator != null ? jsonSchemaValidator
|
||||
: McpJsonDefaults.getDefaultJsonSchemaValidator());
|
||||
return new McpSyncServer(asyncServer, this.immediateExecution);
|
||||
}
|
||||
|
||||
|
|
@ -881,10 +888,10 @@ public interface McpServer {
|
|||
McpServerFeatures.Async asyncFeatures = McpServerFeatures.Async.fromSync(syncFeatures,
|
||||
this.immediateExecution);
|
||||
var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator
|
||||
: JsonSchemaValidator.getDefault();
|
||||
: McpJsonDefaults.getDefaultJsonSchemaValidator();
|
||||
var asyncServer = new McpAsyncServer(transportProvider,
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, asyncFeatures, this.requestTimeout,
|
||||
this.uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, asyncFeatures,
|
||||
this.requestTimeout, this.uriTemplateManagerFactory, jsonSchemaValidator);
|
||||
return new McpSyncServer(asyncServer, this.immediateExecution);
|
||||
}
|
||||
|
||||
|
|
@ -1931,9 +1938,10 @@ 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);
|
||||
return new McpStatelessAsyncServer(transport, jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
features, requestTimeout, uriTemplateManagerFactory,
|
||||
jsonSchemaValidator != null ? jsonSchemaValidator : JsonSchemaValidator.getDefault());
|
||||
return new McpStatelessAsyncServer(transport,
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, features,
|
||||
requestTimeout, uriTemplateManagerFactory, jsonSchemaValidator != null ? jsonSchemaValidator
|
||||
: McpJsonDefaults.getDefaultJsonSchemaValidator());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2432,9 +2440,9 @@ public interface McpServer {
|
|||
this.resources, this.resourceTemplates, this.prompts, this.completions, this.instructions);
|
||||
var asyncFeatures = McpStatelessServerFeatures.Async.fromSync(syncFeatures, this.immediateExecution);
|
||||
var asyncServer = new McpStatelessAsyncServer(transport,
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, asyncFeatures, requestTimeout,
|
||||
uriTemplateManagerFactory,
|
||||
this.jsonSchemaValidator != null ? this.jsonSchemaValidator : JsonSchemaValidator.getDefault());
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, asyncFeatures,
|
||||
requestTimeout, uriTemplateManagerFactory, this.jsonSchemaValidator != null
|
||||
? this.jsonSchemaValidator : McpJsonDefaults.getDefaultJsonSchemaValidator());
|
||||
return new McpStatelessSyncServer(asyncServer, this.immediateExecution);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.json.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
|
|
@ -689,8 +690,8 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
|
|||
throw new IllegalStateException("MessageEndpoint must be set");
|
||||
}
|
||||
return new HttpServletSseServerTransportProvider(
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, baseUrl, messageEndpoint, sseEndpoint,
|
||||
keepAliveInterval, contextExtractor, securityValidator);
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, baseUrl,
|
||||
messageEndpoint, sseEndpoint, keepAliveInterval, contextExtractor, securityValidator);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import java.util.Map;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.modelcontextprotocol.json.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
|
|
@ -347,8 +348,9 @@ public class HttpServletStatelessServerTransport extends HttpServlet implements
|
|||
*/
|
||||
public HttpServletStatelessServerTransport build() {
|
||||
Assert.notNull(mcpEndpoint, "Message endpoint must be set");
|
||||
return new HttpServletStatelessServerTransport(jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
|
||||
mcpEndpoint, contextExtractor, securityValidator);
|
||||
return new HttpServletStatelessServerTransport(
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, mcpEndpoint,
|
||||
contextExtractor, securityValidator);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,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.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.util.KeepAliveScheduler;
|
||||
import jakarta.servlet.AsyncContext;
|
||||
|
|
@ -912,8 +913,8 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
|
|||
public HttpServletStreamableServerTransportProvider build() {
|
||||
Assert.notNull(this.mcpEndpoint, "MCP endpoint must be set");
|
||||
return new HttpServletStreamableServerTransportProvider(
|
||||
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, mcpEndpoint, disallowDelete,
|
||||
contextExtractor, keepAliveInterval, securityValidator);
|
||||
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, mcpEndpoint,
|
||||
disallowDelete, contextExtractor, keepAliveInterval, securityValidator);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright 2026 - 2026 the original author or authors.
|
||||
*/
|
||||
package io.modelcontextprotocol.util;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Instance of this class are intended to be used differently in OSGi and non-OSGi
|
||||
* environments. In all non-OSGi environments the supplier member will be
|
||||
* <code>null</code> and the serviceLoad method will be called to use the
|
||||
* ServiceLoader.load to find the first instance of the supplier (assuming one is present
|
||||
* in the runtime), cache it, and call the supplier's get method.
|
||||
* <p>
|
||||
* In OSGi environments, the Service component runtime (scr) will call the setSupplier
|
||||
* method upon bundle activation (assuming one is present in the runtime), and subsequent
|
||||
* calls will use the given supplier instance rather than the ServiceLoader.load.
|
||||
*
|
||||
* @param <S> the type of the supplier
|
||||
* @param <R> the type of the supplier result/returned value
|
||||
*/
|
||||
public class McpServiceLoader<S extends Supplier<R>, R> {
|
||||
|
||||
private Class<S> supplierType;
|
||||
|
||||
private S supplier;
|
||||
|
||||
private R supplierResult;
|
||||
|
||||
public void setSupplier(S supplier) {
|
||||
this.supplier = supplier;
|
||||
this.supplierResult = null;
|
||||
}
|
||||
|
||||
public void unsetSupplier(S supplier) {
|
||||
this.supplier = null;
|
||||
this.supplierResult = null;
|
||||
}
|
||||
|
||||
public McpServiceLoader(Class<S> supplierType) {
|
||||
this.supplierType = supplierType;
|
||||
}
|
||||
|
||||
protected Optional<S> serviceLoad(Class<S> type) {
|
||||
return ServiceLoader.load(type).findFirst();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized R getDefault() {
|
||||
if (this.supplierResult == null) {
|
||||
if (this.supplier == null) {
|
||||
// Use serviceloader
|
||||
Optional<?> sl = serviceLoad(this.supplierType);
|
||||
if (sl.isEmpty()) {
|
||||
throw new ServiceConfigurationError(
|
||||
"No %s available for creating McpJsonMapper".formatted(this.supplierType.getSimpleName()));
|
||||
}
|
||||
this.supplier = (S) sl.get();
|
||||
}
|
||||
this.supplierResult = this.supplier.get();
|
||||
}
|
||||
return supplierResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.3.0" name="io.modelcontextprotocol.json.McpJsonDefaults" immediate="true">
|
||||
<service>
|
||||
<provide interface="io.modelcontextprotocol.json.McpJsonDefaults"/>
|
||||
</service>
|
||||
<reference name="McpJsonMapperSupplier" interface="io.modelcontextprotocol.json.McpJsonMapperSupplier" bind="setMcpJsonMapperSupplier" unbind="unsetMcpJsonMapperSupplier"/>
|
||||
<reference name="JsonSchemaValidatorSupplier" interface="io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier" bind="setJsonSchemaValidatorSupplier" unbind="unsetJsonSchemaValidatorSupplier"/>
|
||||
<implementation class="io.modelcontextprotocol.json.McpJsonDefaults"/>
|
||||
</scr:component>
|
||||
|
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.spec.McpClientTransport;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
|
|
@ -100,7 +100,7 @@ public class MockMcpClientTransport implements McpClientTransport {
|
|||
|
||||
@Override
|
||||
public <T> T unmarshalFrom(Object data, TypeRef<T> typeRef) {
|
||||
return McpJsonMapper.getDefault().convertValue(data, typeRef);
|
||||
return McpJsonDefaults.getDefaultMcpJsonMapper().convertValue(data, typeRef);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.json.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.TypeRef;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.JSONRPCNotification;
|
||||
|
|
@ -68,7 +68,7 @@ public class MockMcpServerTransport implements McpServerTransport {
|
|||
|
||||
@Override
|
||||
public <T> T unmarshalFrom(Object data, TypeRef<T> typeRef) {
|
||||
return McpJsonMapper.getDefault().convertValue(data, typeRef);
|
||||
return McpJsonDefaults.getDefaultMcpJsonMapper().convertValue(data, typeRef);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package io.modelcontextprotocol.spec;
|
||||
|
||||
import io.modelcontextprotocol.json.McpJsonDefaults;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.io.IOException;
|
||||
|
|
@ -10,7 +11,7 @@ class CompleteCompletionSerializationTest {
|
|||
|
||||
@Test
|
||||
void codeCompletionSerialization() throws IOException {
|
||||
McpJsonMapper jsonMapper = McpJsonMapper.getDefault();
|
||||
McpJsonMapper jsonMapper = McpJsonDefaults.getDefaultMcpJsonMapper();
|
||||
McpSchema.CompleteResult.CompleteCompletion codeComplete = new McpSchema.CompleteResult.CompleteCompletion(
|
||||
Collections.emptyList(), 0, false);
|
||||
String json = jsonMapper.writeValueAsString(codeComplete);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue