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 <[email protected]> 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 <[email protected]> --- .../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)
