This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch feature/CAMEL-24237-mcp-catalog-docs in repository https://gitbox.apache.org/repos/asf/camel.git
commit eb9ed47de09b5201cd46bfc79565052f33152f43 Author: Claus Ibsen <[email protected]> AuthorDate: Wed Jul 22 10:50:18 2026 +0200 CAMEL-24237: Add MCP tools for full AsciiDoc documentation from catalog Co-Authored-By: Claude Opus 4.6 <[email protected]> Signed-off-by: Claus Ibsen <[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) { + } }
