diff --git a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapper.java b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapper.java
index 6aa2b4ebc..4c69e9d34 100644
--- a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapper.java
+++ b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapper.java
@@ -14,7 +14,12 @@
/**
* Jackson-based implementation of JsonMapper. Wraps a Jackson ObjectMapper but keeps the
* SDK decoupled from Jackson at the API level.
+ *
+ * @deprecated since 18.0.0, use
+ * {@link io.modelcontextprotocol.json.jackson2.JacksonMcpJsonMapper} instead. Will be
+ * removed in 19.0.0
*/
+@Deprecated(forRemoval = true, since = "18.0.0")
public final class JacksonMcpJsonMapper implements McpJsonMapper {
private final ObjectMapper objectMapper;
diff --git a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapperSupplier.java b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapperSupplier.java
index 0e79c3e0e..8a7c0f42a 100644
--- a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapperSupplier.java
+++ b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapperSupplier.java
@@ -13,7 +13,12 @@
*
* This implementation provides a {@link McpJsonMapper} backed by a Jackson
* {@link com.fasterxml.jackson.databind.ObjectMapper}.
+ *
+ * @deprecated since 18.0.0, use
+ * {@link io.modelcontextprotocol.json.jackson2.JacksonMcpJsonMapperSupplier} instead.
+ * Will be removed in 19.0.0.
*/
+@Deprecated(forRemoval = true, since = "18.0.0")
public class JacksonMcpJsonMapperSupplier implements McpJsonMapperSupplier {
/**
diff --git a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson2/JacksonMcpJsonMapper.java b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson2/JacksonMcpJsonMapper.java
new file mode 100644
index 000000000..1760cf472
--- /dev/null
+++ b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson2/JacksonMcpJsonMapper.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2026 - 2026 the original author or authors.
+ */
+
+package io.modelcontextprotocol.json.jackson2;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.modelcontextprotocol.json.McpJsonMapper;
+import io.modelcontextprotocol.json.TypeRef;
+
+/**
+ * Jackson-based implementation of JsonMapper. Wraps a Jackson ObjectMapper but keeps the
+ * SDK decoupled from Jackson at the API level.
+ */
+public final class JacksonMcpJsonMapper implements McpJsonMapper {
+
+ private final ObjectMapper objectMapper;
+
+ /**
+ * Constructs a new JacksonMcpJsonMapper instance with the given ObjectMapper.
+ * @param objectMapper the ObjectMapper to be used for JSON serialization and
+ * deserialization. Must not be null.
+ * @throws IllegalArgumentException if the provided ObjectMapper is null.
+ */
+ public JacksonMcpJsonMapper(ObjectMapper objectMapper) {
+ if (objectMapper == null) {
+ throw new IllegalArgumentException("ObjectMapper must not be null");
+ }
+ this.objectMapper = objectMapper;
+ }
+
+ /**
+ * Returns the underlying Jackson {@link ObjectMapper} used for JSON serialization and
+ * deserialization.
+ * @return the ObjectMapper instance
+ */
+ public ObjectMapper getObjectMapper() {
+ return objectMapper;
+ }
+
+ @Override
+ public T readValue(String content, Class type) throws IOException {
+ return objectMapper.readValue(content, type);
+ }
+
+ @Override
+ public T readValue(byte[] content, Class type) throws IOException {
+ return objectMapper.readValue(content, type);
+ }
+
+ @Override
+ public T readValue(String content, TypeRef type) throws IOException {
+ JavaType javaType = objectMapper.getTypeFactory().constructType(type.getType());
+ return objectMapper.readValue(content, javaType);
+ }
+
+ @Override
+ public T readValue(byte[] content, TypeRef type) throws IOException {
+ JavaType javaType = objectMapper.getTypeFactory().constructType(type.getType());
+ return objectMapper.readValue(content, javaType);
+ }
+
+ @Override
+ public T convertValue(Object fromValue, Class type) {
+ return objectMapper.convertValue(fromValue, type);
+ }
+
+ @Override
+ public T convertValue(Object fromValue, TypeRef type) {
+ JavaType javaType = objectMapper.getTypeFactory().constructType(type.getType());
+ return objectMapper.convertValue(fromValue, javaType);
+ }
+
+ @Override
+ public String writeValueAsString(Object value) throws IOException {
+ return objectMapper.writeValueAsString(value);
+ }
+
+ @Override
+ public byte[] writeValueAsBytes(Object value) throws IOException {
+ return objectMapper.writeValueAsBytes(value);
+ }
+
+}
diff --git a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson2/JacksonMcpJsonMapperSupplier.java b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson2/JacksonMcpJsonMapperSupplier.java
new file mode 100644
index 000000000..acd5dddaa
--- /dev/null
+++ b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson2/JacksonMcpJsonMapperSupplier.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2026 - 2026 the original author or authors.
+ */
+
+package io.modelcontextprotocol.json.jackson2;
+
+import io.modelcontextprotocol.json.McpJsonMapper;
+import io.modelcontextprotocol.json.McpJsonMapperSupplier;
+
+/**
+ * A supplier of {@link McpJsonMapper} instances that uses the Jackson library for JSON
+ * serialization and deserialization.
+ *
+ * This implementation provides a {@link McpJsonMapper} backed by a Jackson
+ * {@link com.fasterxml.jackson.databind.ObjectMapper}.
+ */
+public class JacksonMcpJsonMapperSupplier implements McpJsonMapperSupplier {
+
+ /**
+ * Returns a new instance of {@link McpJsonMapper} that uses the Jackson library for
+ * JSON serialization and deserialization.
+ *
+ * The returned {@link McpJsonMapper} is backed by a new instance of
+ * {@link com.fasterxml.jackson.databind.ObjectMapper}.
+ * @return a new {@link McpJsonMapper} instance
+ */
+ @Override
+ public McpJsonMapper get() {
+ return new JacksonMcpJsonMapper(new com.fasterxml.jackson.databind.ObjectMapper());
+ }
+
+}
diff --git a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/DefaultJsonSchemaValidator.java b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/DefaultJsonSchemaValidator.java
index 1ff28cb80..002a9d2a9 100644
--- a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/DefaultJsonSchemaValidator.java
+++ b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/DefaultJsonSchemaValidator.java
@@ -24,7 +24,11 @@
* NetworkNT JSON Schema Validator library for validation.
*
* @author Christian Tzolov
+ * @deprecated since 18.0.0, use
+ * {@link io.modelcontextprotocol.json.schema.jackson2.DefaultJsonSchemaValidator}
+ * instead. Will be removed in 19.0.0.
*/
+@Deprecated(forRemoval = true, since = "18.0.0")
public class DefaultJsonSchemaValidator implements JsonSchemaValidator {
private static final Logger logger = LoggerFactory.getLogger(DefaultJsonSchemaValidator.class);
diff --git a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/JacksonJsonSchemaValidatorSupplier.java b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/JacksonJsonSchemaValidatorSupplier.java
index 86153a538..ae16d66e9 100644
--- a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/JacksonJsonSchemaValidatorSupplier.java
+++ b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/JacksonJsonSchemaValidatorSupplier.java
@@ -13,6 +13,9 @@
*
* @see JsonSchemaValidatorSupplier
* @see JsonSchemaValidator
+ * @deprecated since 18.0.0, use
+ * {@link io.modelcontextprotocol.json.schema.jackson2.JacksonJsonSchemaValidatorSupplier}
+ * instead. Will be removed in 19.0.0.
*/
public class JacksonJsonSchemaValidatorSupplier implements JsonSchemaValidatorSupplier {
diff --git a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson2/DefaultJsonSchemaValidator.java b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson2/DefaultJsonSchemaValidator.java
new file mode 100644
index 000000000..e07bf1759
--- /dev/null
+++ b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson2/DefaultJsonSchemaValidator.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2026-2026 the original author or authors.
+ */
+package io.modelcontextprotocol.json.schema.jackson2;
+
+import java.util.List;
+import java.util.Map;
+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.networknt.schema.Error;
+import com.networknt.schema.Schema;
+import com.networknt.schema.SchemaRegistry;
+import com.networknt.schema.dialect.Dialects;
+
+import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
+
+/**
+ * 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 SchemaRegistry schemaFactory;
+
+ // TODO: Implement a strategy to purge the cache (TTL, size limit, etc.)
+ private final ConcurrentHashMap schemaCache;
+
+ public DefaultJsonSchemaValidator() {
+ this(new ObjectMapper());
+ }
+
+ public DefaultJsonSchemaValidator(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ this.schemaFactory = SchemaRegistry.withDialect(Dialects.getDraft202012());
+ this.schemaCache = new ConcurrentHashMap<>();
+ }
+
+ @Override
+ public ValidationResponse validate(Map schema, Object structuredContent) {
+
+ if (schema == null) {
+ throw new IllegalArgumentException("Schema must not be null");
+ }
+ if (structuredContent == null) {
+ throw new IllegalArgumentException("Structured content must not be null");
+ }
+
+ try {
+
+ JsonNode jsonStructuredOutput = (structuredContent instanceof String)
+ ? this.objectMapper.readTree((String) structuredContent)
+ : this.objectMapper.valueToTree(structuredContent);
+
+ List 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 Schema or creates and caches a new one.
+ * @param schema the schema map to convert
+ * @return the compiled Schema
+ * @throws JsonProcessingException if schema processing fails
+ */
+ private Schema getOrCreateJsonSchema(Map schema) throws JsonProcessingException {
+ // Generate cache key based on schema content
+ String cacheKey = this.generateCacheKey(schema);
+
+ // Try to get from cache first
+ Schema cachedSchema = this.schemaCache.get(cacheKey);
+ if (cachedSchema != null) {
+ return cachedSchema;
+ }
+
+ // Create new schema if not in cache
+ Schema newSchema = this.createJsonSchema(schema);
+
+ // Cache the schema
+ Schema existingSchema = this.schemaCache.putIfAbsent(cacheKey, newSchema);
+ return existingSchema != null ? existingSchema : newSchema;
+ }
+
+ /**
+ * Creates a new Schema from the given schema map.
+ * @param schema the schema map
+ * @return the compiled Schema
+ * @throws JsonProcessingException if schema processing fails
+ */
+ private Schema createJsonSchema(Map 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") {
+ };
+ }
+
+ 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 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();
+ }
+
+}
diff --git a/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson2/JacksonJsonSchemaValidatorSupplier.java b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson2/JacksonJsonSchemaValidatorSupplier.java
new file mode 100644
index 000000000..aa280a38e
--- /dev/null
+++ b/mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson2/JacksonJsonSchemaValidatorSupplier.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2026 - 2026 the original author or authors.
+ */
+
+package io.modelcontextprotocol.json.schema.jackson2;
+
+import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
+import io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier;
+
+/**
+ * A concrete implementation of {@link JsonSchemaValidatorSupplier} that provides a
+ * {@link JsonSchemaValidator} instance based on the Jackson library.
+ *
+ * @see JsonSchemaValidatorSupplier
+ * @see JsonSchemaValidator
+ */
+public class JacksonJsonSchemaValidatorSupplier implements JsonSchemaValidatorSupplier {
+
+ /**
+ * Returns a new instance of {@link JsonSchemaValidator} that uses the Jackson library
+ * for JSON schema validation.
+ * @return A {@link JsonSchemaValidator} instance.
+ */
+ @Override
+ public JsonSchemaValidator get() {
+ return new DefaultJsonSchemaValidator();
+ }
+
+}
diff --git a/mcp-json-jackson2/src/main/resources/META-INF/services/io.modelcontextprotocol.json.McpJsonMapperSupplier b/mcp-json-jackson2/src/main/resources/META-INF/services/io.modelcontextprotocol.json.McpJsonMapperSupplier
index 8ea66d698..0c62b6478 100644
--- a/mcp-json-jackson2/src/main/resources/META-INF/services/io.modelcontextprotocol.json.McpJsonMapperSupplier
+++ b/mcp-json-jackson2/src/main/resources/META-INF/services/io.modelcontextprotocol.json.McpJsonMapperSupplier
@@ -1 +1 @@
-io.modelcontextprotocol.json.jackson.JacksonMcpJsonMapperSupplier
\ No newline at end of file
+io.modelcontextprotocol.json.jackson2.JacksonMcpJsonMapperSupplier
\ No newline at end of file
diff --git a/mcp-json-jackson2/src/main/resources/META-INF/services/io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier b/mcp-json-jackson2/src/main/resources/META-INF/services/io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier
index 0fb0b7e5a..1b2f05f97 100644
--- a/mcp-json-jackson2/src/main/resources/META-INF/services/io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier
+++ b/mcp-json-jackson2/src/main/resources/META-INF/services/io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier
@@ -1 +1 @@
-io.modelcontextprotocol.json.schema.jackson.JacksonJsonSchemaValidatorSupplier
\ No newline at end of file
+io.modelcontextprotocol.json.schema.jackson2.JacksonJsonSchemaValidatorSupplier
\ No newline at end of file
diff --git a/mcp-json-jackson2/src/test/java/io/modelcontextprotocol/json/DefaultJsonSchemaValidatorTests.java b/mcp-json-jackson2/src/test/java/io/modelcontextprotocol/json/jackson/DefaultJsonSchemaValidatorTests.java
similarity index 99%
rename from mcp-json-jackson2/src/test/java/io/modelcontextprotocol/json/DefaultJsonSchemaValidatorTests.java
rename to mcp-json-jackson2/src/test/java/io/modelcontextprotocol/json/jackson/DefaultJsonSchemaValidatorTests.java
index 7642f0480..66cba09b8 100644
--- a/mcp-json-jackson2/src/test/java/io/modelcontextprotocol/json/DefaultJsonSchemaValidatorTests.java
+++ b/mcp-json-jackson2/src/test/java/io/modelcontextprotocol/json/jackson/DefaultJsonSchemaValidatorTests.java
@@ -2,7 +2,7 @@
* Copyright 2024-2024 the original author or authors.
*/
-package io.modelcontextprotocol.json;
+package io.modelcontextprotocol.json.jackson;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -17,7 +17,6 @@
import java.util.Map;
import java.util.stream.Stream;
-import io.modelcontextprotocol.json.schema.jackson.DefaultJsonSchemaValidator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -30,12 +29,14 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.json.schema.JsonSchemaValidator.ValidationResponse;
+import io.modelcontextprotocol.json.schema.jackson.DefaultJsonSchemaValidator;
/**
* Tests for {@link DefaultJsonSchemaValidator}.
*
* @author Christian Tzolov
*/
+@Deprecated(forRemoval = true)
class DefaultJsonSchemaValidatorTests {
private DefaultJsonSchemaValidator validator;
diff --git a/mcp-json-jackson2/src/test/java/io/modelcontextprotocol/json/jackson2/DefaultJsonSchemaValidatorTests.java b/mcp-json-jackson2/src/test/java/io/modelcontextprotocol/json/jackson2/DefaultJsonSchemaValidatorTests.java
new file mode 100644
index 000000000..5ae3fbed4
--- /dev/null
+++ b/mcp-json-jackson2/src/test/java/io/modelcontextprotocol/json/jackson2/DefaultJsonSchemaValidatorTests.java
@@ -0,0 +1,808 @@
+/*
+ * Copyright 2026-2026 the original author or authors.
+ */
+
+package io.modelcontextprotocol.json.jackson2;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.modelcontextprotocol.json.schema.JsonSchemaValidator.ValidationResponse;
+import io.modelcontextprotocol.json.schema.jackson2.DefaultJsonSchemaValidator;
+
+/**
+ * Tests for {@link DefaultJsonSchemaValidator}.
+ *
+ * @author Christian Tzolov
+ */
+class DefaultJsonSchemaValidatorTests {
+
+ private DefaultJsonSchemaValidator validator;
+
+ private ObjectMapper objectMapper;
+
+ @Mock
+ private ObjectMapper mockObjectMapper;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ validator = new DefaultJsonSchemaValidator();
+ objectMapper = new ObjectMapper();
+ }
+
+ /**
+ * Utility method to convert JSON string to Map
+ */
+ private Map toMap(String json) {
+ try {
+ return objectMapper.readValue(json, new TypeReference