This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new f9c6599ac86c CAMEL-24237: Add MCP tools for full AsciiDoc
documentation from catalog
f9c6599ac86c is described below
commit f9c6599ac86cf1486b8058157050254751a842f0
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Jul 22 13:53:03 2026 +0200
CAMEL-24237: Add MCP tools for full AsciiDoc documentation from catalog
Add camel_catalog_docs tool to list available AsciiDoc documentation page
names with optional filter and limit, and camel_catalog_doc tool to retrieve
full documentation content by page name with "Did you mean?" suggestions
on miss. These complement the existing structured JSON tools by providing
human-readable docs with usage examples and best practices.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
.../dsl/jbang/core/commands/mcp/CatalogTools.java | 105 +++++++++++++++++++++
1 file changed, 105 insertions(+)
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogTools.java
index 9cefe48eb9dd..6358023f74ae 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogTools.java
@@ -385,6 +385,105 @@ public class CatalogTools {
}
}
+ /**
+ * Tool to list available AsciiDoc documentation pages.
+ */
+ @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint
= false, openWorldHint = false),
+ description = "List available AsciiDoc documentation page names from
the catalog. "
+ + "Returns page names (without .adoc extension) that
can be passed to camel_catalog_doc "
+ + "to retrieve the full documentation content. "
+ + "Unlike the structured tools
(camel_catalog_component_doc, camel_catalog_eip_doc, etc.) "
+ + "which return parsed JSON with options and metadata,
"
+ + "the AsciiDoc pages contain the full human-readable
documentation "
+ + "with usage examples, code snippets, and best
practices. "
+ + "Only available from Camel 4.22 onwards.")
+ public DocListResult camel_catalog_docs(
+ @ToolArg(description = "Filter page names by substring
(case-insensitive)") String filter,
+ @ToolArg(description = "Maximum number of results to return
(default: 50)") Integer limit,
+ @ToolArg(description = ToolArgDocs.CAMEL_VERSION) String
camelVersion) {
+
+ int maxResults = limit != null ? limit : 50;
+
+ try {
+ CamelCatalog cat = catalogService.loadCatalog(null, camelVersion,
null);
+
+ List<String> names = cat.findDocNames();
+ if (names == null) {
+ names = List.of();
+ }
+
+ if (filter != null && !filter.isBlank()) {
+ String lowerFilter = filter.toLowerCase();
+ names = names.stream()
+ .filter(n -> n.toLowerCase().contains(lowerFilter))
+ .collect(Collectors.toList());
+ }
+
+ int total = names.size();
+ if (names.size() > maxResults) {
+ names = names.subList(0, maxResults);
+ }
+
+ return new DocListResult(total, names.size(), names);
+ } catch (Throwable e) {
+ throw new ToolCallException(
+ "Failed to list documentation pages: " + e.getMessage(),
e);
+ }
+ }
+
+ /**
+ * Tool to get the full AsciiDoc documentation content for a catalog page.
+ */
+ @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint
= false, openWorldHint = false),
+ description = "Get the full AsciiDoc documentation page from the
catalog. "
+ + "Returns the complete human-readable documentation
with usage examples, "
+ + "code snippets, configuration guides, and best
practices. "
+ + "This complements the structured tools
(camel_catalog_component_doc, "
+ + "camel_catalog_eip_doc, etc.) which return parsed
JSON with options and metadata. "
+ + "Use camel_catalog_docs to discover available page
names. "
+ + "Naming conventions: components use
'<name>-component' (e.g., 'kafka-component'), "
+ + "data formats use '<name>-dataformat' (e.g.,
'jackson-dataformat'), "
+ + "languages use '<name>-language' (e.g.,
'simple-language'), "
+ + "EIPs use '<name>-eip' (e.g., 'split-eip'), "
+ + "and others use their plain name (e.g.,
'cloudevents', 'debug'). "
+ + "Only available from Camel 4.22 onwards.")
+ public DocResult camel_catalog_doc(
+ @ToolArg(description = "Documentation page name without .adoc
extension "
+ + "(e.g., 'kafka-component', 'split-eip',
'simple-language', 'jackson-dataformat')") String name,
+ @ToolArg(description = ToolArgDocs.CAMEL_VERSION) String
camelVersion) {
+
+ if (name == null || name.isBlank()) {
+ throw new ToolCallException("Documentation page name is required",
null);
+ }
+
+ try {
+ CamelCatalog cat = catalogService.loadCatalog(null, camelVersion,
null);
+ String content = cat.asciiDoc(name);
+ if (content == null) {
+ List<String> allNames = cat.findDocNames();
+ if (allNames != null) {
+ String lower = name.toLowerCase();
+ List<String> suggestions = allNames.stream()
+ .filter(n -> n.toLowerCase().contains(lower) ||
lower.contains(n.toLowerCase()))
+ .limit(5)
+ .collect(Collectors.toList());
+ if (!suggestions.isEmpty()) {
+ throw new ToolCallException(
+ "Documentation page not found: " + name + ".
Did you mean one of: " + suggestions, null);
+ }
+ }
+ throw new ToolCallException("Documentation page not found: " +
name, null);
+ }
+ return new DocResult(name, content);
+ } catch (ToolCallException e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new ToolCallException(
+ "Failed to load documentation: " + name + " (" +
e.getClass().getName() + "): " + e.getMessage(),
+ null);
+ }
+ }
+
private static List<String> findComponentNames(CamelCatalog catalog) {
List<String> answer = catalog.findComponentNames();
if (answer == null) {
@@ -732,4 +831,10 @@ public class CatalogTools {
public record FunctionParamInfo(String name, String javaType, boolean
required,
String defaultValue, String description) {
}
+
+ public record DocListResult(int total, int returned, List<String> names) {
+ }
+
+ public record DocResult(String name, String content) {
+ }
}