Skip to content

Commit 003eb6e

Browse files
committed
Rebasing on main after #742 merged. Moves mcp-json API back into
mcp-core so that mcp-json API is no longer needed and mcp-core has fewer dependencies.
1 parent 0a8cb1e commit 003eb6e

File tree

46 files changed

+605
-99
lines changed

Some content is hidden

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

46 files changed

+605
-99
lines changed

mcp-bom/pom.xml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,6 @@
4040
<version>${project.version}</version>
4141
</dependency>
4242

43-
<!-- MCP JSON -->
44-
<dependency>
45-
<groupId>io.modelcontextprotocol.sdk</groupId>
46-
<artifactId>mcp-json</artifactId>
47-
<version>${project.version}</version>
48-
</dependency>
49-
5043
<!-- MCP JSON Jackson -->
5144
<dependency>
5245
<groupId>io.modelcontextprotocol.sdk</groupId>

mcp-core/pom.xml

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,6 @@
6565
</build>
6666

6767
<dependencies>
68-
<dependency>
69-
<groupId>io.modelcontextprotocol.sdk</groupId>
70-
<artifactId>mcp-json</artifactId>
71-
<version>0.18.0-SNAPSHOT</version>
72-
</dependency>
7368

7469
<dependency>
7570
<groupId>org.slf4j</groupId>
@@ -97,21 +92,18 @@
9792
<scope>provided</scope>
9893
</dependency>
9994

100-
<!-- Test dependencies -->
101-
<dependency>
102-
<groupId>io.modelcontextprotocol.sdk</groupId>
103-
<artifactId>mcp-json-jackson3</artifactId>
104-
<version>0.18.0-SNAPSHOT</version>
105-
<scope>test</scope>
106-
</dependency>
107-
10895
<dependency>
10996
<groupId>org.springframework</groupId>
11097
<artifactId>spring-webmvc</artifactId>
11198
<version>${springframework.version}</version>
11299
<scope>test</scope>
113100
</dependency>
114101

102+
<dependency>
103+
<groupId>tools.jackson.core</groupId>
104+
<artifactId>jackson-databind</artifactId>
105+
<version>${jackson3.version}</version>
106+
</dependency>
115107

116108
<dependency>
117109
<groupId>io.projectreactor.netty</groupId>

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package io.modelcontextprotocol.client;
66

77
import io.modelcontextprotocol.common.McpTransportContext;
8+
import io.modelcontextprotocol.json.McpJsonDefaults;
89
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
910
import io.modelcontextprotocol.spec.McpClientTransport;
1011
import io.modelcontextprotocol.spec.McpSchema;
@@ -491,9 +492,12 @@ public McpSyncClient build() {
491492

492493
McpClientFeatures.Async asyncFeatures = McpClientFeatures.Async.fromSync(syncFeatures);
493494

494-
return new McpSyncClient(new McpAsyncClient(transport, this.requestTimeout, this.initializationTimeout,
495-
jsonSchemaValidator != null ? jsonSchemaValidator : JsonSchemaValidator.getDefault(),
496-
asyncFeatures), this.contextProvider);
495+
return new McpSyncClient(
496+
new McpAsyncClient(transport, this.requestTimeout, this.initializationTimeout,
497+
jsonSchemaValidator != null ? jsonSchemaValidator
498+
: McpJsonDefaults.getDefaultJsonSchemaValidator(),
499+
asyncFeatures),
500+
this.contextProvider);
497501
}
498502

499503
}
@@ -826,7 +830,7 @@ public AsyncSpec enableCallToolSchemaCaching(boolean enableCallToolSchemaCaching
826830
*/
827831
public McpAsyncClient build() {
828832
var jsonSchemaValidator = (this.jsonSchemaValidator != null) ? this.jsonSchemaValidator
829-
: JsonSchemaValidator.getDefault();
833+
: McpJsonDefaults.getDefaultJsonSchemaValidator();
830834
return new McpAsyncClient(this.transport, this.requestTimeout, this.initializationTimeout,
831835
jsonSchemaValidator,
832836
new McpClientFeatures.Async(this.clientInfo, this.capabilities, this.roots,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpClientRequestCustomizer;
2323
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
2424
import io.modelcontextprotocol.common.McpTransportContext;
25+
import io.modelcontextprotocol.json.McpJsonDefaults;
2526
import io.modelcontextprotocol.json.McpJsonMapper;
2627
import io.modelcontextprotocol.json.TypeRef;
2728
import io.modelcontextprotocol.spec.HttpHeaders;
@@ -327,7 +328,7 @@ public Builder connectTimeout(Duration connectTimeout) {
327328
public HttpClientSseClientTransport build() {
328329
HttpClient httpClient = this.clientBuilder.connectTimeout(this.connectTimeout).build();
329330
return new HttpClientSseClientTransport(httpClient, requestBuilder, baseUri, sseEndpoint,
330-
jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, httpRequestCustomizer);
331+
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, httpRequestCustomizer);
331332
}
332333

333334
}

mcp-core/src/main/java/io/modelcontextprotocol/client/transport/HttpClientStreamableHttpTransport.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpClientRequestCustomizer;
2626
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
2727
import io.modelcontextprotocol.common.McpTransportContext;
28+
import io.modelcontextprotocol.json.McpJsonDefaults;
2829
import io.modelcontextprotocol.json.McpJsonMapper;
2930
import io.modelcontextprotocol.json.TypeRef;
3031
import io.modelcontextprotocol.spec.ClosedMcpTransportSession;
@@ -822,9 +823,10 @@ public Builder supportedProtocolVersions(List<String> supportedProtocolVersions)
822823
*/
823824
public HttpClientStreamableHttpTransport build() {
824825
HttpClient httpClient = this.clientBuilder.connectTimeout(this.connectTimeout).build();
825-
return new HttpClientStreamableHttpTransport(jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
826-
httpClient, requestBuilder, baseUri, endpoint, resumableStreams, openConnectionOnStartup,
827-
httpRequestCustomizer, supportedProtocolVersions);
826+
return new HttpClientStreamableHttpTransport(
827+
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, httpClient,
828+
requestBuilder, baseUri, endpoint, resumableStreams, openConnectionOnStartup, httpRequestCustomizer,
829+
supportedProtocolVersions);
828830
}
829831

830832
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package io.modelcontextprotocol.json;
2+
3+
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
4+
import io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier;
5+
import io.modelcontextprotocol.util.McpServiceLoader;
6+
7+
public class McpJsonDefaults {
8+
9+
protected static McpServiceLoader<McpJsonMapperSupplier, McpJsonMapper> mcpMapperServiceLoader;
10+
11+
protected static McpServiceLoader<JsonSchemaValidatorSupplier, JsonSchemaValidator> mcpValidatorServiceLoader;
12+
13+
public McpJsonDefaults() {
14+
mcpMapperServiceLoader = new McpServiceLoader<McpJsonMapperSupplier, McpJsonMapper>(
15+
McpJsonMapperSupplier.class);
16+
mcpValidatorServiceLoader = new McpServiceLoader<JsonSchemaValidatorSupplier, JsonSchemaValidator>(
17+
JsonSchemaValidatorSupplier.class);
18+
}
19+
20+
void setMcpJsonMapperSupplier(McpJsonMapperSupplier supplier) {
21+
mcpMapperServiceLoader.setSupplier(supplier);
22+
}
23+
24+
void unsetMcpJsonMapperSupplier(McpJsonMapperSupplier supplier) {
25+
mcpMapperServiceLoader.unsetSupplier(supplier);
26+
}
27+
28+
public synchronized static McpJsonMapper getDefaultMcpJsonMapper() {
29+
if (mcpMapperServiceLoader == null) {
30+
new McpJsonDefaults();
31+
}
32+
return mcpMapperServiceLoader.getDefault();
33+
}
34+
35+
void setJsonSchemaValidatorSupplier(JsonSchemaValidatorSupplier supplier) {
36+
mcpValidatorServiceLoader.setSupplier(supplier);
37+
}
38+
39+
void unsetJsonSchemaValidatorSupplier(JsonSchemaValidatorSupplier supplier) {
40+
mcpValidatorServiceLoader.unsetSupplier(supplier);
41+
}
42+
43+
public synchronized static JsonSchemaValidator getDefaultJsonSchemaValidator() {
44+
if (mcpValidatorServiceLoader == null) {
45+
new McpJsonDefaults();
46+
}
47+
return mcpValidatorServiceLoader.getDefault();
48+
}
49+
50+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2025 - 2025 the original author or authors.
3+
*/
4+
5+
package io.modelcontextprotocol.json;
6+
7+
import java.io.IOException;
8+
9+
/**
10+
* Abstraction for JSON serialization/deserialization to decouple the SDK from any
11+
* specific JSON library. A default implementation backed by Jackson is provided in
12+
* io.modelcontextprotocol.spec.json.jackson.JacksonJsonMapper.
13+
*/
14+
public interface McpJsonMapper {
15+
16+
/**
17+
* Deserialize JSON string into a target type.
18+
* @param content JSON as String
19+
* @param type target class
20+
* @return deserialized instance
21+
* @param <T> generic type
22+
* @throws IOException on parse errors
23+
*/
24+
<T> T readValue(String content, Class<T> type) throws IOException;
25+
26+
/**
27+
* Deserialize JSON bytes into a target type.
28+
* @param content JSON as bytes
29+
* @param type target class
30+
* @return deserialized instance
31+
* @param <T> generic type
32+
* @throws IOException on parse errors
33+
*/
34+
<T> T readValue(byte[] content, Class<T> type) throws IOException;
35+
36+
/**
37+
* Deserialize JSON string into a parameterized target type.
38+
* @param content JSON as String
39+
* @param type parameterized type reference
40+
* @return deserialized instance
41+
* @param <T> generic type
42+
* @throws IOException on parse errors
43+
*/
44+
<T> T readValue(String content, TypeRef<T> type) throws IOException;
45+
46+
/**
47+
* Deserialize JSON bytes into a parameterized target type.
48+
* @param content JSON as bytes
49+
* @param type parameterized type reference
50+
* @return deserialized instance
51+
* @param <T> generic type
52+
* @throws IOException on parse errors
53+
*/
54+
<T> T readValue(byte[] content, TypeRef<T> type) throws IOException;
55+
56+
/**
57+
* Convert a value to a given type, useful for mapping nested JSON structures.
58+
* @param fromValue source value
59+
* @param type target class
60+
* @return converted value
61+
* @param <T> generic type
62+
*/
63+
<T> T convertValue(Object fromValue, Class<T> type);
64+
65+
/**
66+
* Convert a value to a given parameterized type.
67+
* @param fromValue source value
68+
* @param type target type reference
69+
* @return converted value
70+
* @param <T> generic type
71+
*/
72+
<T> T convertValue(Object fromValue, TypeRef<T> type);
73+
74+
/**
75+
* Serialize an object to JSON string.
76+
* @param value object to serialize
77+
* @return JSON as String
78+
* @throws IOException on serialization errors
79+
*/
80+
String writeValueAsString(Object value) throws IOException;
81+
82+
/**
83+
* Serialize an object to JSON bytes.
84+
* @param value object to serialize
85+
* @return JSON as bytes
86+
* @throws IOException on serialization errors
87+
*/
88+
byte[] writeValueAsBytes(Object value) throws IOException;
89+
90+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright 2025 - 2025 the original author or authors.
3+
*/
4+
5+
package io.modelcontextprotocol.json;
6+
7+
import java.util.function.Supplier;
8+
9+
/**
10+
* Strategy interface for resolving a {@link McpJsonMapper}.
11+
*/
12+
public interface McpJsonMapperSupplier extends Supplier<McpJsonMapper> {
13+
14+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2025 - 2025 the original author or authors.
3+
*/
4+
5+
package io.modelcontextprotocol.json;
6+
7+
import java.lang.reflect.ParameterizedType;
8+
import java.lang.reflect.Type;
9+
10+
/**
11+
* Captures generic type information at runtime for parameterized JSON (de)serialization.
12+
* Usage: TypeRef<List<Foo>> ref = new TypeRef<>(){};
13+
*/
14+
public abstract class TypeRef<T> {
15+
16+
private final Type type;
17+
18+
/**
19+
* Constructs a new TypeRef instance, capturing the generic type information of the
20+
* subclass. This constructor should be called from an anonymous subclass to capture
21+
* the actual type arguments. For example: <pre>
22+
* TypeRef&lt;List&lt;Foo&gt;&gt; ref = new TypeRef&lt;&gt;(){};
23+
* </pre>
24+
* @throws IllegalStateException if TypeRef is not subclassed with actual type
25+
* information
26+
*/
27+
protected TypeRef() {
28+
Type superClass = getClass().getGenericSuperclass();
29+
if (superClass instanceof Class) {
30+
throw new IllegalStateException("TypeRef constructed without actual type information");
31+
}
32+
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
33+
}
34+
35+
/**
36+
* Returns the captured type information.
37+
* @return the Type representing the actual type argument captured by this TypeRef
38+
* instance
39+
*/
40+
public Type getType() {
41+
return type;
42+
}
43+
44+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package io.modelcontextprotocol.json.internal;
2+
3+
import java.util.Optional;
4+
import java.util.ServiceConfigurationError;
5+
import java.util.ServiceLoader;
6+
7+
import io.modelcontextprotocol.json.McpJsonMapper;
8+
import io.modelcontextprotocol.json.McpJsonMapperSupplier;
9+
10+
public class DefaultMcpJsonMapperSupplier {
11+
12+
private static McpJsonMapperSupplier jsonMapperSupplier;
13+
14+
private static McpJsonMapper defaultJsonMapper;
15+
16+
void setMcpJsonMapperSupplier(McpJsonMapperSupplier supplier) {
17+
jsonMapperSupplier = supplier;
18+
}
19+
20+
void unsetMcpJsonMapperSupplier(McpJsonMapperSupplier supplier) {
21+
jsonMapperSupplier = null;
22+
defaultJsonMapper = null;
23+
}
24+
25+
public synchronized static McpJsonMapper getDefaultMcpJsonMapper() {
26+
if (defaultJsonMapper == null) {
27+
if (jsonMapperSupplier == null) {
28+
// Use serviceloader
29+
Optional<McpJsonMapperSupplier> sl = ServiceLoader.load(McpJsonMapperSupplier.class).findFirst();
30+
if (sl.isEmpty()) {
31+
throw new ServiceConfigurationError("No JsonMapperSupplier available for creating McpJsonMapper");
32+
}
33+
jsonMapperSupplier = sl.get();
34+
}
35+
defaultJsonMapper = jsonMapperSupplier.get();
36+
}
37+
return defaultJsonMapper;
38+
}
39+
40+
}

0 commit comments

Comments
 (0)