Skip to content

Commit d8ea3f0

Browse files
scottslewisLucaButBoring
authored andcommitted
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>
1 parent be5ec12 commit d8ea3f0

File tree

47 files changed

+368
-353
lines changed

Some content is hidden

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

47 files changed

+368
-353
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: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
Automatic-Module-Name: ${project.groupId}.${project.artifactId}
4242
Import-Package: jakarta.*;resolution:=optional, \
4343
*;
44+
Service-Component: OSGI-INF/io.modelcontextprotocol.json.McpJsonDefaults.xml
4445
Export-Package: io.modelcontextprotocol.*;version="${version}";-noimport:=true
4546
-noimportjava: true;
4647
-nouses: true;
@@ -65,11 +66,6 @@
6566
</build>
6667

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

7470
<dependency>
7571
<groupId>org.slf4j</groupId>
@@ -97,21 +93,19 @@
9793
<scope>provided</scope>
9894
</dependency>
9995

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-
10896
<dependency>
10997
<groupId>org.springframework</groupId>
11098
<artifactId>spring-webmvc</artifactId>
11199
<version>${springframework.version}</version>
112100
<scope>test</scope>
113101
</dependency>
114102

103+
<dependency>
104+
<groupId>tools.jackson.core</groupId>
105+
<artifactId>jackson-databind</artifactId>
106+
<version>${jackson3.version}</version>
107+
<scope>test</scope>
108+
</dependency>
115109

116110
<dependency>
117111
<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;
@@ -842,9 +843,10 @@ public Builder supportedProtocolVersions(List<String> supportedProtocolVersions)
842843
*/
843844
public HttpClientStreamableHttpTransport build() {
844845
HttpClient httpClient = this.clientBuilder.connectTimeout(this.connectTimeout).build();
845-
return new HttpClientStreamableHttpTransport(jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper,
846-
httpClient, requestBuilder, baseUri, endpoint, resumableStreams, openConnectionOnStartup,
847-
httpRequestCustomizer, supportedProtocolVersions);
846+
return new HttpClientStreamableHttpTransport(
847+
jsonMapper == null ? McpJsonDefaults.getDefaultMcpJsonMapper() : jsonMapper, httpClient,
848+
requestBuilder, baseUri, endpoint, resumableStreams, openConnectionOnStartup, httpRequestCustomizer,
849+
supportedProtocolVersions);
848850
}
849851

850852
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* Copyright 2026 - 2026 the original author or authors.
3+
*/
4+
package io.modelcontextprotocol.json;
5+
6+
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
7+
import io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier;
8+
import io.modelcontextprotocol.util.McpServiceLoader;
9+
10+
/**
11+
* This class is to be used to provide access to the default McpJsonMapper and to the
12+
* default JsonSchemaValidator instances via the static methods: getDefaultMcpJsonMapper
13+
* and getDefaultJsonSchemaValidator.
14+
* <p>
15+
* The initialization of (singleton) instances of this class is different in non-OSGi
16+
* environments and OSGi environments. Specifically, in non-OSGi environments The
17+
* McpJsonDefaults class will be loaded by whatever classloader is used to call one of the
18+
* existing static get methods for the first time. For servers, this will usually be in
19+
* response to the creation of the first McpServer instance. At that first time, the
20+
* mcpMapperServiceLoader and mcpValidatorServiceLoader will be null, and the
21+
* McpJsonDefaults constructor will be called, creating/initializing the
22+
* mcpMapperServiceLoader and the mcpValidatorServiceLoader...which will then be used to
23+
* call the ServiceLoader.load method.
24+
* <p>
25+
* In OSGi environments, upon bundle activation SCR will create a new (singleton) instance
26+
* of McpJsonDefaults (via the constructor), and then inject suppliers via the
27+
* setMcpJsonMapperSupplier and setJsonSchemaValidatorSupplier methods with the
28+
* SCR-discovered instances of those services. This does depend upon the jars/bundles
29+
* providing those suppliers to be started/activated. This SCR behavior is dictated by xml
30+
* files in OSGi-INF directory of mcp-core (this project/jar/bundle), and the jsonmapper
31+
* and jsonschemvalidator provider jars/bundles (e.g. mcp-json-jackson2, 3, or others).
32+
*/
33+
public class McpJsonDefaults {
34+
35+
protected static McpServiceLoader<McpJsonMapperSupplier, McpJsonMapper> mcpMapperServiceLoader;
36+
37+
protected static McpServiceLoader<JsonSchemaValidatorSupplier, JsonSchemaValidator> mcpValidatorServiceLoader;
38+
39+
public McpJsonDefaults() {
40+
mcpMapperServiceLoader = new McpServiceLoader<McpJsonMapperSupplier, McpJsonMapper>(
41+
McpJsonMapperSupplier.class);
42+
mcpValidatorServiceLoader = new McpServiceLoader<JsonSchemaValidatorSupplier, JsonSchemaValidator>(
43+
JsonSchemaValidatorSupplier.class);
44+
}
45+
46+
void setMcpJsonMapperSupplier(McpJsonMapperSupplier supplier) {
47+
mcpMapperServiceLoader.setSupplier(supplier);
48+
}
49+
50+
void unsetMcpJsonMapperSupplier(McpJsonMapperSupplier supplier) {
51+
mcpMapperServiceLoader.unsetSupplier(supplier);
52+
}
53+
54+
public synchronized static McpJsonMapper getDefaultMcpJsonMapper() {
55+
if (mcpMapperServiceLoader == null) {
56+
new McpJsonDefaults();
57+
}
58+
return mcpMapperServiceLoader.getDefault();
59+
}
60+
61+
void setJsonSchemaValidatorSupplier(JsonSchemaValidatorSupplier supplier) {
62+
mcpValidatorServiceLoader.setSupplier(supplier);
63+
}
64+
65+
void unsetJsonSchemaValidatorSupplier(JsonSchemaValidatorSupplier supplier) {
66+
mcpValidatorServiceLoader.unsetSupplier(supplier);
67+
}
68+
69+
public synchronized static JsonSchemaValidator getDefaultJsonSchemaValidator() {
70+
if (mcpValidatorServiceLoader == null) {
71+
new McpJsonDefaults();
72+
}
73+
return mcpValidatorServiceLoader.getDefault();
74+
}
75+
76+
}

mcp-json/src/main/java/io/modelcontextprotocol/json/McpJsonMapper.java renamed to mcp-core/src/main/java/io/modelcontextprotocol/json/McpJsonMapper.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,4 @@ public interface McpJsonMapper {
8787
*/
8888
byte[] writeValueAsBytes(Object value) throws IOException;
8989

90-
/**
91-
* Returns the default {@link McpJsonMapper}.
92-
* @return The default {@link McpJsonMapper}
93-
* @throws IllegalStateException If no {@link McpJsonMapper} implementation exists on
94-
* the classpath.
95-
*/
96-
static McpJsonMapper getDefault() {
97-
return McpJsonInternal.getDefaultMapper();
98-
}
99-
100-
/**
101-
* Creates a new default {@link McpJsonMapper}.
102-
* @return The default {@link McpJsonMapper}
103-
* @throws IllegalStateException If no {@link McpJsonMapper} implementation exists on
104-
* the classpath.
105-
*/
106-
static McpJsonMapper createDefault() {
107-
return McpJsonInternal.createDefaultMapper();
108-
}
109-
11090
}

mcp-json/src/main/java/io/modelcontextprotocol/json/McpJsonMapperSupplier.java renamed to mcp-core/src/main/java/io/modelcontextprotocol/json/McpJsonMapperSupplier.java

File renamed without changes.

mcp-json/src/main/java/io/modelcontextprotocol/json/TypeRef.java renamed to mcp-core/src/main/java/io/modelcontextprotocol/json/TypeRef.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
/**
1111
* Captures generic type information at runtime for parameterized JSON (de)serialization.
12-
* Usage: TypeRef&lt;List&lt;Foo&gt;&gt; ref = new TypeRef&lt;&gt;(){};
12+
* Usage: TypeRef<List<Foo>> ref = new TypeRef<>(){};
1313
*/
1414
public abstract class TypeRef<T> {
1515

mcp-json/src/main/java/io/modelcontextprotocol/json/schema/JsonSchemaValidator.java renamed to mcp-core/src/main/java/io/modelcontextprotocol/json/schema/JsonSchemaValidator.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,4 @@ public static ValidationResponse asInvalid(String message) {
4141
*/
4242
ValidationResponse validate(Map<String, Object> schema, Object structuredContent);
4343

44-
/**
45-
* Creates the default {@link JsonSchemaValidator}.
46-
* @return The default {@link JsonSchemaValidator}
47-
* @throws IllegalStateException If no {@link JsonSchemaValidator} implementation
48-
* exists on the classpath.
49-
*/
50-
static JsonSchemaValidator createDefault() {
51-
return JsonSchemaInternal.createDefaultValidator();
52-
}
53-
54-
/**
55-
* Returns the default {@link JsonSchemaValidator}.
56-
* @return The default {@link JsonSchemaValidator}
57-
* @throws IllegalStateException If no {@link JsonSchemaValidator} implementation
58-
* exists on the classpath.
59-
*/
60-
static JsonSchemaValidator getDefault() {
61-
return JsonSchemaInternal.getDefaultValidator();
62-
}
63-
6444
}

0 commit comments

Comments
 (0)