type) {
+ JavaType javaType = jsonMapper.getTypeFactory().constructType(type.getType());
+ return jsonMapper.convertValue(fromValue, javaType);
+ }
+
+ @Override
+ public String writeValueAsString(Object value) {
+ return jsonMapper.writeValueAsString(value);
+ }
+
+ @Override
+ public byte[] writeValueAsBytes(Object value) {
+ return jsonMapper.writeValueAsBytes(value);
+ }
+
+}
diff --git a/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/jackson3/JacksonMcpJsonMapperSupplier.java b/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/jackson3/JacksonMcpJsonMapperSupplier.java
new file mode 100644
index 000000000..c53061b2f
--- /dev/null
+++ b/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/jackson3/JacksonMcpJsonMapperSupplier.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2026 - 2026 the original author or authors.
+ */
+
+package io.modelcontextprotocol.json.jackson3;
+
+import tools.jackson.databind.json.JsonMapper;
+
+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 JsonMapper}.
+ */
+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 tools.jackson.databind.json.JsonMapper}.
+ * @return a new {@link McpJsonMapper} instance
+ */
+ @Override
+ public McpJsonMapper get() {
+ return new JacksonMcpJsonMapper(JsonMapper.shared());
+ }
+
+}
diff --git a/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/schema/jackson3/DefaultJsonSchemaValidator.java b/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/schema/jackson3/DefaultJsonSchemaValidator.java
new file mode 100644
index 000000000..8c9b7ccdb
--- /dev/null
+++ b/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/schema/jackson3/DefaultJsonSchemaValidator.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2026-2026 the original author or authors.
+ */
+package io.modelcontextprotocol.json.schema.jackson3;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.networknt.schema.Schema;
+import com.networknt.schema.SchemaRegistry;
+import com.networknt.schema.Error;
+import com.networknt.schema.dialect.Dialects;
+import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import tools.jackson.core.JacksonException;
+import tools.jackson.databind.JsonNode;
+import tools.jackson.databind.json.JsonMapper;
+
+/**
+ * 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 Filip Hrisafov
+ */
+public class DefaultJsonSchemaValidator implements JsonSchemaValidator {
+
+ private static final Logger logger = LoggerFactory.getLogger(DefaultJsonSchemaValidator.class);
+
+ private final JsonMapper jsonMapper;
+
+ private final SchemaRegistry schemaFactory;
+
+ // TODO: Implement a strategy to purge the cache (TTL, size limit, etc.)
+ private final ConcurrentHashMap schemaCache;
+
+ public DefaultJsonSchemaValidator() {
+ this(JsonMapper.shared());
+ }
+
+ public DefaultJsonSchemaValidator(JsonMapper jsonMapper) {
+ this.jsonMapper = jsonMapper;
+ 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.jsonMapper.readTree((String) structuredContent)
+ : this.jsonMapper.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 (JacksonException 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 JacksonException if schema processing fails
+ */
+ private Schema getOrCreateJsonSchema(Map schema) throws JacksonException {
+ // 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 JacksonException if schema processing fails
+ */
+ private Schema createJsonSchema(Map schema) throws JacksonException {
+ // Convert schema map directly to JsonNode (more efficient than string
+ // serialization)
+ JsonNode schemaNode = this.jsonMapper.valueToTree(schema);
+
+ // Handle case where ObjectMapper might return null (e.g., in mocked scenarios)
+ if (schemaNode == null) {
+ throw new JacksonException("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-jackson3/src/main/java/io/modelcontextprotocol/json/schema/jackson3/JacksonJsonSchemaValidatorSupplier.java b/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/schema/jackson3/JacksonJsonSchemaValidatorSupplier.java
new file mode 100644
index 000000000..87cead5db
--- /dev/null
+++ b/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/schema/jackson3/JacksonJsonSchemaValidatorSupplier.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2026 - 2026 the original author or authors.
+ */
+
+package io.modelcontextprotocol.json.schema.jackson3;
+
+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-jackson3/src/main/resources/META-INF/services/io.modelcontextprotocol.json.McpJsonMapperSupplier b/mcp-json-jackson3/src/main/resources/META-INF/services/io.modelcontextprotocol.json.McpJsonMapperSupplier
new file mode 100644
index 000000000..6abfb347f
--- /dev/null
+++ b/mcp-json-jackson3/src/main/resources/META-INF/services/io.modelcontextprotocol.json.McpJsonMapperSupplier
@@ -0,0 +1 @@
+io.modelcontextprotocol.json.jackson3.JacksonMcpJsonMapperSupplier
\ No newline at end of file
diff --git a/mcp-json-jackson3/src/main/resources/META-INF/services/io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier b/mcp-json-jackson3/src/main/resources/META-INF/services/io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier
new file mode 100644
index 000000000..2bab3ba8e
--- /dev/null
+++ b/mcp-json-jackson3/src/main/resources/META-INF/services/io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier
@@ -0,0 +1 @@
+io.modelcontextprotocol.json.schema.jackson3.JacksonJsonSchemaValidatorSupplier
\ No newline at end of file
diff --git a/mcp-json-jackson3/src/test/java/io/modelcontextprotocol/json/DefaultJsonSchemaValidatorTests.java b/mcp-json-jackson3/src/test/java/io/modelcontextprotocol/json/DefaultJsonSchemaValidatorTests.java
new file mode 100644
index 000000000..37c52caf7
--- /dev/null
+++ b/mcp-json-jackson3/src/test/java/io/modelcontextprotocol/json/DefaultJsonSchemaValidatorTests.java
@@ -0,0 +1,807 @@
+/*
+ * Copyright 2026-2026 the original author or authors.
+ */
+
+package io.modelcontextprotocol.json;
+
+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 io.modelcontextprotocol.json.schema.jackson3.DefaultJsonSchemaValidator;
+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 tools.jackson.core.type.TypeReference;
+import tools.jackson.databind.json.JsonMapper;
+
+import io.modelcontextprotocol.json.schema.JsonSchemaValidator.ValidationResponse;
+
+/**
+ * Tests for {@link DefaultJsonSchemaValidator}.
+ *
+ * @author Filip Hrisafov
+ */
+class DefaultJsonSchemaValidatorTests {
+
+ private DefaultJsonSchemaValidator validator;
+
+ private JsonMapper jsonMapper;
+
+ @Mock
+ private JsonMapper mockJsonMapper;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ validator = new DefaultJsonSchemaValidator();
+ jsonMapper = JsonMapper.shared();
+ }
+
+ /**
+ * Utility method to convert JSON string to Map
+ */
+ private Map toMap(String json) {
+ try {
+ return jsonMapper.readValue(json, new TypeReference<>() {
+ });
+ }
+ catch (Exception e) {
+ throw new RuntimeException("Failed to parse JSON: " + json, e);
+ }
+ }
+
+ private List