You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2026/08/11 14:25:30 UTC

(camel-quarkus) 07/11: CAMEL-24369: openai: make the MCP client work in native mode

This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit 44f35a0396aa78b6f18d3b695c1736d34780c5e2
Author: Federico Mariani <34...@users.noreply.github.com>
AuthorDate: Fri Aug 7 15:22:40 2026 +0200

    CAMEL-24369: openai: make the MCP client work in native mode
    
    The MCP client (mcpServer.* endpoint options) resolves its JSON mapper and
    schema validator through java.util.ServiceLoader, and (de)serializes the
    MCP protocol messages (McpSchema records) reflectively via Jackson. The MCP
    Java SDK ships no native-image metadata, so a native application using MCP
    tool calling failed at startup with
    ServiceConfigurationError: No McpJsonMapperSupplier available, and after
    registering the providers the client initialize handshake still failed on
    the unregistered schema classes.
    
    Register the two service providers and all indexed
    io.modelcontextprotocol.spec / .json classes for reflection.
    
    Co-authored-by: Claude Fable 5 <no...@anthropic.com>
---
 .../openai/deployment/OpenaiProcessor.java         | 41 ++++++++++++++++++++--
 1 file changed, 39 insertions(+), 2 deletions(-)

diff --git a/extensions/openai/deployment/src/main/java/org/apache/camel/quarkus/component/openai/deployment/OpenaiProcessor.java b/extensions/openai/deployment/src/main/java/org/apache/camel/quarkus/component/openai/deployment/OpenaiProcessor.java
index 61cc735a7e..5667a8554d 100644
--- a/extensions/openai/deployment/src/main/java/org/apache/camel/quarkus/component/openai/deployment/OpenaiProcessor.java
+++ b/extensions/openai/deployment/src/main/java/org/apache/camel/quarkus/component/openai/deployment/OpenaiProcessor.java
@@ -35,6 +35,7 @@ import io.quarkus.deployment.builditem.RemovedResourceBuildItem;
 import io.quarkus.deployment.builditem.nativeimage.NativeImageResourcePatternsBuildItem;
 import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
 import io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
 import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
 import io.quarkus.jackson.deployment.IgnoreJsonDeserializeClassBuildItem;
 import io.quarkus.maven.dependency.ArtifactKey;
@@ -51,8 +52,44 @@ class OpenaiProcessor {
     }
 
     @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
-    IndexDependencyBuildItem indexDependencies() {
-        return new IndexDependencyBuildItem("com.openai", "openai-java-core");
+    void indexDependencies(BuildProducer<IndexDependencyBuildItem> indexDependency) {
+        indexDependency.produce(new IndexDependencyBuildItem("com.openai", "openai-java-core"));
+        indexDependency.produce(new IndexDependencyBuildItem("io.modelcontextprotocol.sdk", "mcp-core"));
+    }
+
+    @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
+    void registerMcpSdkServiceProviders(BuildProducer<ServiceProviderBuildItem> serviceProvider) {
+        // the MCP client (mcpServer.* endpoint options) resolves its JSON mapper and schema
+        // validator through java.util.ServiceLoader; without these registrations a native
+        // application fails at runtime with "No McpJsonMapperSupplier available"
+        serviceProvider.produce(new ServiceProviderBuildItem(
+                "io.modelcontextprotocol.json.McpJsonMapperSupplier",
+                "io.modelcontextprotocol.json.jackson2.JacksonMcpJsonMapperSupplier"));
+        serviceProvider.produce(new ServiceProviderBuildItem(
+                "io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier",
+                "io.modelcontextprotocol.json.schema.jackson2.JacksonJsonSchemaValidatorSupplier"));
+    }
+
+    @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
+    void registerMcpSdkSchemaForReflection(
+            CombinedIndexBuildItem combinedIndex,
+            BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
+        // the MCP protocol messages (McpSchema records and friends) are (de)serialized by Jackson
+        // reflectively; the MCP Java SDK ships no native-image metadata
+        Set<String> mcpSchemaClassNames = combinedIndex.getIndex()
+                .getKnownClasses()
+                .stream()
+                .map(ClassInfo::name)
+                .map(DotName::toString)
+                .filter(className -> className.startsWith("io.modelcontextprotocol.spec")
+                        || className.startsWith("io.modelcontextprotocol.json"))
+                .collect(Collectors.toSet());
+
+        reflectiveClass.produce(ReflectiveClassBuildItem.builder(mcpSchemaClassNames.toArray(new String[0]))
+                .constructors()
+                .fields()
+                .methods()
+                .build());
     }
 
     @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)