This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch CAMEL-22975 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 842740e89b66c2f38d53c476661ed7b5c22112b1 Author: Andrea Cosentino <[email protected]> AuthorDate: Tue Feb 10 10:57:17 2026 +0100 CAMEL-22975 - Camel-jbang-MCP: Add Kamelets catalog and doc tool Signed-off-by: Andrea Cosentino <[email protected]> --- docs/user-manual/modules/ROOT/nav.adoc | 1 + .../modules/ROOT/pages/camel-jbang-mcp.adoc | 296 +++++++++++++++++++++ .../jbang/core/commands/catalog/KameletModel.java | 12 +- .../core/commands/catalog/KameletOptionModel.java | 14 +- .../dsl/jbang/core/commands/mcp/KameletTools.java | 161 +++++++++++ 5 files changed, 471 insertions(+), 13 deletions(-) diff --git a/docs/user-manual/modules/ROOT/nav.adoc b/docs/user-manual/modules/ROOT/nav.adoc index 37a204df317a..eb09a11eadaa 100644 --- a/docs/user-manual/modules/ROOT/nav.adoc +++ b/docs/user-manual/modules/ROOT/nav.adoc @@ -10,6 +10,7 @@ *** xref:camel-jbang-launcher.adoc[Camel JBang Launcher] *** xref:camel-jbang-kubernetes.adoc[Camel JBang Kubernetes plugin] *** xref:camel-jbang-test.adoc[Camel JBang Testing plugin] +*** xref:camel-jbang-mcp.adoc[Camel MCP Server] ** xref:camel-maven-plugin.adoc[Camel Maven Plugin] ** xref:camel-component-maven-plugin.adoc[Camel Component Maven Plugin] ** xref:camel-report-maven-plugin.adoc[Camel Maven Report Plugin] diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc new file mode 100644 index 000000000000..a1d7c1089fc6 --- /dev/null +++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc @@ -0,0 +1,296 @@ += Camel MCP Server + +The Camel MCP Server exposes the Apache Camel Catalog and a set of specialized tools through the +https://modelcontextprotocol.io/[Model Context Protocol (MCP)], the open standard that allows AI coding assistants +to call external tools. This enables AI tools such as Claude Code, OpenAI Codex, GitHub Copilot, and JetBrains AI +to query live Camel catalog data, validate endpoint URIs, analyze routes for security concerns, browse Kamelets, and more. + +The server is built on https://quarkus.io/[Quarkus] using the +https://docs.quarkiverse.io/quarkus-mcp-server/dev/index.html[quarkus-mcp-server] extension and ships as a single +uber-JAR that can be launched via https://www.jbang.dev/[JBang]. + +NOTE: This module is in *Preview* status as of Camel 4.18. + +== Transport + +The server supports two transports: + +* **STDIO** -- The default transport for CLI-based AI tools. The server communicates over stdin/stdout using the MCP + protocol. All logging goes to stderr to keep stdout clean for protocol messages. +* **HTTP/SSE** -- An optional transport for web-based clients and remote access scenarios. Useful when running the + MCP server as a shared service for a team or in a container. + +By default, the HTTP server is disabled. To enable it, set `quarkus.http.host-enabled=true`. + +== Available Tools + +The server exposes 13 tools organized into six functional areas. + +=== Catalog Exploration + +[cols="1,3",options="header"] +|=== +| Tool | Description + +| `camel_catalog_components` +| List available Camel components with filtering by name, label (e.g., `messaging`, `cloud`, `database`), and + runtime type (`main`, `spring-boot`, `quarkus`). Supports querying specific Camel versions. + +| `camel_catalog_component_doc` +| Get detailed documentation for a specific component including all endpoint options, component-level options, + Maven coordinates, and URI syntax. + +| `camel_catalog_dataformats` +| List available data formats (JSON, XML, CSV, Avro, Protobuf, and others). + +| `camel_catalog_languages` +| List expression languages (Simple, JsonPath, XPath, JQ, Groovy, and others). + +| `camel_catalog_eips` +| List Enterprise Integration Patterns with filtering by category. + +| `camel_catalog_eip_doc` +| Get detailed documentation for a specific EIP including all its options. +|=== + +=== Kamelet Catalog + +[cols="1,3",options="header"] +|=== +| Tool | Description + +| `camel_catalog_kamelets` +| List available Kamelets from the Kamelet Catalog with filtering by name, description, and type (`source`, `sink`, + `action`). Supports querying specific Kamelets catalog versions. + +| `camel_catalog_kamelet_doc` +| Get detailed documentation for a specific Kamelet including all properties/options, their types, defaults, + examples, and the Kamelet's Maven dependencies. +|=== + +=== Route Understanding + +[cols="1,3",options="header"] +|=== +| Tool | Description + +| `camel_route_context` +| Given a Camel route (YAML, XML, or Java DSL), extracts all components and EIPs used, looks up their documentation + from the catalog, and returns structured context. +|=== + +=== Security Analysis + +[cols="1,3",options="header"] +|=== +| Tool | Description + +| `camel_route_harden_context` +| Analyzes a route for security concerns. Identifies security-sensitive components, assigns risk levels, detects + issues like hardcoded credentials or plain-text protocols, and returns structured security findings alongside + best practices. +|=== + +=== Validation and Transformation + +[cols="1,3",options="header"] +|=== +| Tool | Description + +| `camel_validate_route` +| Validates Camel endpoint URIs against the catalog schema. Catches unknown options, missing required parameters, + invalid enum values, and type mismatches. Also provides suggestions for misspelled option names. + +| `camel_transform_route` +| Assists with route DSL format transformation between YAML and XML. +|=== + +=== Version Management + +[cols="1,3",options="header"] +|=== +| Tool | Description + +| `camel_version_list` +| Lists available Camel versions for a given runtime, including release dates, JDK requirements, and LTS status. +|=== + +== Setup + +The MCP server requires https://www.jbang.dev/[JBang] to be installed and available on your PATH. + +=== Claude Code + +Add the following to your project's `.mcp.json` (or `~/.claude/mcp.json` for global configuration): + +[source,json] +---- +{ + "mcpServers": { + "camel": { + "command": "jbang", + "args": [ + "-Dquarkus.log.level=WARN", + "org.apache.camel:camel-jbang-mcp:4.18.0:runner" + ] + } + } +} +---- + +=== OpenAI Codex + +Add the server to your MCP configuration: + +[source,json] +---- +{ + "mcpServers": { + "camel": { + "command": "jbang", + "args": [ + "-Dquarkus.log.level=WARN", + "org.apache.camel:camel-jbang-mcp:4.18.0:runner" + ] + } + } +} +---- + +=== VS Code with Copilot + +Configure MCP servers in your `.vscode/mcp.json` or in the user settings: + +[source,json] +---- +{ + "servers": { + "camel": { + "command": "jbang", + "args": [ + "-Dquarkus.log.level=WARN", + "org.apache.camel:camel-jbang-mcp:4.18.0:runner" + ] + } + } +} +---- + +=== JetBrains IDEs + +JetBrains IDEs support MCP servers starting from 2025.1. Configure them in +Settings > Tools > AI Assistant > MCP Servers, or create an `.junie/mcp.json` file in your project root: + +[source,json] +---- +{ + "mcpServers": { + "camel": { + "command": "jbang", + "args": [ + "-Dquarkus.log.level=WARN", + "org.apache.camel:camel-jbang-mcp:4.18.0:runner" + ] + } + } +} +---- + +=== Generic STDIO Client + +Any MCP client that supports the STDIO transport can launch the server directly: + +[source,bash] +---- +jbang org.apache.camel:camel-jbang-mcp:4.18.0:runner +---- + +=== HTTP/SSE Transport + +To start the server with the HTTP/SSE transport enabled: + +[source,bash] +---- +jbang -Dquarkus.http.host-enabled=true -Dquarkus.http.port=8080 org.apache.camel:camel-jbang-mcp:4.18.0:runner +---- + +MCP clients that support HTTP/SSE can then connect to the server at `http://localhost:8080/mcp/sse`. + +== Examples + +=== Listing Components + +Prompt your AI assistant with: + +---- +List all Camel components in the messaging category +---- + +The assistant calls `camel_catalog_components` with `label=messaging` and receives structured results with name, +title, description, label, deprecation status, and support level for each matching component. + +=== Getting Component Documentation + +---- +Show me the documentation for the Kafka component, including all endpoint options +---- + +The assistant calls `camel_catalog_component_doc` with `component=kafka` and receives the full component model +including the URI syntax, Maven coordinates, and every endpoint option with types, defaults, and descriptions. + +=== Browsing Kamelets + +---- +Show me all available source kamelets related to AWS +---- + +The assistant calls `camel_catalog_kamelets` with `type=source` and `filter=aws` and returns matching Kamelets +with their name, type, support level, and description. + +To drill into a specific Kamelet: + +---- +What options does the aws-s3-source kamelet accept? +---- + +The assistant calls `camel_catalog_kamelet_doc` with `kamelet=aws-s3-source` and returns the complete property +list including required fields, types, defaults, and Maven dependencies. + +=== Validating an Endpoint URI + +---- +Validate this Kafka endpoint: kafka:myTopic?brkers=localhost:9092&groupId=myGroup +---- + +The assistant calls `camel_validate_route` and detects the typo (`brkers`), reports the URI as invalid, and +suggests the correct option name (`brokers`). + +=== Understanding a Route + +Paste a route and ask: + +---- +Explain what this route does +---- + +The assistant calls `camel_route_context` which extracts all components and EIPs used in the route, looks up +their documentation from the catalog, and returns enriched context so the AI can provide an accurate explanation. + +=== Security Hardening + +---- +Analyze this route for security concerns and suggest hardening measures +---- + +The assistant calls `camel_route_harden_context` which analyzes the route for security-sensitive components, +detects issues (hardcoded credentials, HTTP instead of HTTPS, plain FTP, etc.), assigns risk levels, and +returns structured findings with remediation recommendations. + +=== Checking Camel Versions + +---- +What are the latest LTS versions of Camel for Spring Boot? +---- + +The assistant calls `camel_version_list` with `runtime=spring-boot` and `lts=true` and returns version +information including release dates, end-of-life dates, and JDK requirements. diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/KameletModel.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/KameletModel.java index 62ac3e3c6fe5..28a4b7965260 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/KameletModel.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/KameletModel.java @@ -21,11 +21,11 @@ import java.util.Map; public class KameletModel { - String name; - String type; - String supportLevel; - String description; - Map<String, KameletOptionModel> properties; - List<String> dependencies; + public String name; + public String type; + public String supportLevel; + public String description; + public Map<String, KameletOptionModel> properties; + public List<String> dependencies; } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/KameletOptionModel.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/KameletOptionModel.java index a0a7837a0368..5f4f2c5bead2 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/KameletOptionModel.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/KameletOptionModel.java @@ -20,12 +20,12 @@ import java.util.List; public class KameletOptionModel { - String name; - boolean required; - String description; - String type; - String defaultValue; - String example; - List<String> enumValues; + public String name; + public boolean required; + public String description; + public String type; + public String defaultValue; + public String example; + public List<String> enumValues; } diff --git a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java new file mode 100644 index 000000000000..61e1d8a06ed9 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.dsl.jbang.core.commands.mcp; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import jakarta.enterprise.context.ApplicationScoped; + +import io.quarkiverse.mcp.server.Tool; +import io.quarkiverse.mcp.server.ToolArg; +import io.quarkiverse.mcp.server.ToolCallException; +import org.apache.camel.dsl.jbang.core.commands.catalog.KameletCatalogHelper; +import org.apache.camel.dsl.jbang.core.commands.catalog.KameletModel; +import org.apache.camel.dsl.jbang.core.commands.catalog.KameletOptionModel; +import org.apache.camel.dsl.jbang.core.common.RuntimeType; + +/** + * MCP Tools for querying the Kamelet Catalog using Quarkus MCP Server. + */ +@ApplicationScoped +public class KameletTools { + + /** + * Tool to list available Kamelets. + */ + @Tool(description = "List available Camel Kamelets from the Kamelet Catalog. " + + "Returns kamelet name, type (source, sink, action), support level, and description. " + + "Use filter to search by name or description, type to filter by category.") + public KameletListResult camel_catalog_kamelets( + @ToolArg(description = "Filter kamelets by name or description (case-insensitive substring match)") String filter, + @ToolArg(description = "Filter by type: source, sink, or action") String type, + @ToolArg(description = "Maximum number of results to return (default: 50)") Integer limit, + @ToolArg(description = "Apache Camel Kamelets version. If not specified, uses the default version.") String kameletsVersion) { + + int maxResults = limit != null ? limit : 50; + + try { + String version = kameletsVersion != null && !kameletsVersion.isBlank() + ? kameletsVersion : RuntimeType.KAMELETS_VERSION; + + Map<String, Object> kamelets = KameletCatalogHelper.loadKamelets(version, null); + + List<KameletInfo> result = new ArrayList<>(); + for (Object o : kamelets.values()) { + KameletModel km = KameletCatalogHelper.createModel(o, false); + + // filter by type + if (type != null && !type.isBlank() + && !type.equalsIgnoreCase(km.type)) { + continue; + } + + // filter by name or description + if (filter != null && !filter.isBlank()) { + String lowerFilter = filter.toLowerCase(Locale.ROOT); + boolean matches = (km.name != null && km.name.toLowerCase(Locale.ROOT).contains(lowerFilter)) + || (km.description != null && km.description.toLowerCase(Locale.ROOT).contains(lowerFilter)); + if (!matches) { + continue; + } + } + + result.add(new KameletInfo(km.name, km.type, km.supportLevel, km.description)); + + if (result.size() >= maxResults) { + break; + } + } + + // sort by name + result.sort((a, b) -> a.name().compareToIgnoreCase(b.name())); + + return new KameletListResult(result.size(), version, result); + } catch (Exception e) { + throw new ToolCallException("Failed to list kamelets: " + e.getMessage(), e); + } + } + + /** + * Tool to get detailed documentation for a specific Kamelet. + */ + @Tool(description = "Get detailed documentation for a specific Camel Kamelet including all properties/options, " + + "dependencies, and usage information.") + public KameletDetailResult camel_catalog_kamelet_doc( + @ToolArg(description = "Kamelet name (e.g., aws-s3-source, kafka-sink, log-action)") String kamelet, + @ToolArg(description = "Apache Camel Kamelets version. If not specified, uses the default version.") String kameletsVersion) { + + if (kamelet == null || kamelet.isBlank()) { + throw new ToolCallException("Kamelet name is required", null); + } + + try { + String version = kameletsVersion != null && !kameletsVersion.isBlank() + ? kameletsVersion : RuntimeType.KAMELETS_VERSION; + + KameletModel km = KameletCatalogHelper.loadKameletModel(kamelet, version, null); + if (km == null) { + throw new ToolCallException("Kamelet not found: " + kamelet, null); + } + + List<KameletOptionInfo> options = new ArrayList<>(); + if (km.properties != null) { + for (KameletOptionModel om : km.properties.values()) { + options.add(new KameletOptionInfo( + om.name, + om.description, + om.type, + om.required, + om.defaultValue, + om.example, + om.enumValues)); + } + } + + return new KameletDetailResult( + km.name, + km.type, + km.supportLevel, + km.description, + options, + km.dependencies); + } catch (ToolCallException e) { + throw e; + } catch (Exception e) { + throw new ToolCallException("Failed to get kamelet doc: " + e.getMessage(), e); + } + } + + // Result record classes for Jackson serialization + + public record KameletListResult(int count, String kameletsVersion, List<KameletInfo> kamelets) { + } + + public record KameletInfo(String name, String type, String supportLevel, String description) { + } + + public record KameletDetailResult(String name, String type, String supportLevel, String description, + List<KameletOptionInfo> options, List<String> dependencies) { + } + + public record KameletOptionInfo(String name, String description, String type, boolean required, + String defaultValue, String example, List<String> enumValues) { + } +}
