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 45343260ef56 CAMEL-23529: camel-jbang-mcp - add ascii/unicode theme 
support to route diagram tool (#23306)
45343260ef56 is described below

commit 45343260ef569a3ec0051553df23a547a49c33df
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon May 18 21:31:53 2026 +0200

    CAMEL-23529: camel-jbang-mcp - add ascii/unicode theme support to route 
diagram tool (#23306)
    
    The MCP camel_render_route_diagram tool now supports 'ascii' and 'unicode'
    themes in addition to the existing PNG image themes (dark, light, 
transparent).
    
    For text themes the diagram is returned directly as the asciiDiagram field 
of
    the result so that LLM callers can read and reason about the route structure
    without needing to open a file. The temporary output file uses a .txt suffix
    in text mode so CamelRouteDiagramAction writes to the correct path.
    
    Signed-off-by: Claus Ibsen <[email protected]>
    Co-authored-by: Claude Sonnet 4.6 <[email protected]>
---
 .../jbang/core/commands/mcp/RouteDiagramTools.java | 50 ++++++++++++++++------
 .../core/commands/mcp/RouteDiagramToolsTest.java   | 20 +++++++++
 2 files changed, 56 insertions(+), 14 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteDiagramTools.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteDiagramTools.java
index 452ee8892eaf..0ecdb4f8ce5b 100644
--- 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteDiagramTools.java
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteDiagramTools.java
@@ -19,6 +19,7 @@ package org.apache.camel.dsl.jbang.core.commands.mcp;
 import java.io.File;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.Set;
 
 import jakarta.enterprise.context.ApplicationScoped;
 
@@ -30,25 +31,32 @@ import 
org.apache.camel.dsl.jbang.core.commands.action.CamelRouteDiagramAction;
 import org.apache.camel.dsl.jbang.core.common.Printer;
 
 /**
- * MCP Tool for generating a visual PNG diagram of Camel routes from a source 
file (non-running integration). Wraps the
- * {@code camel route-diagram} jbang command.
+ * MCP Tool for generating a visual diagram of Camel routes from a source file 
(non-running integration). Wraps the
+ * {@code camel route-diagram} jbang command. Supports both PNG image output 
and plain-text ASCII/Unicode output.
  */
 @ApplicationScoped
 public class RouteDiagramTools {
 
+    private static final Set<String> TEXT_THEMES = Set.of("ascii", "unicode");
+
     @Tool(annotations = @Tool.Annotations(readOnlyHint = false, 
destructiveHint = false, openWorldHint = false),
-          description = "Generate a visual PNG diagram of Camel routes from a 
route source file (YAML, XML, Java, ...). "
-                        + "The source file is parsed without running it. The 
resulting PNG is written to disk and the "
-                        + "absolute path is returned so it can be displayed or 
shared. Useful to visualize a route "
-                        + "structure for review, documentation, or 
troubleshooting.")
+          description = "Generate a diagram of Camel routes from a route 
source file (YAML, XML, Java, ...). "
+                        + "The source file is parsed without running it. "
+                        + "For image themes (dark, light, transparent) the PNG 
is written to disk and the absolute path "
+                        + "is returned. For text themes (ascii, unicode) the 
diagram is returned directly as text so "
+                        + "it can be read and understood by the caller. "
+                        + "Useful to visualize a route structure for review, 
documentation, or troubleshooting.")
     public RouteDiagramResult camel_render_route_diagram(
             @ToolArg(description = "Absolute or relative path to the Camel 
route source file (YAML, XML, Java, ...)") String sourceFile,
-            @ToolArg(description = "Optional output PNG file path. If not 
specified, a temporary file is created.") String outputFile,
-            @ToolArg(description = "Color theme: 'dark' (default), 'light', 
'transparent', or a custom spec like "
-                                   + "'bg=#1e1e1e:from=#2e7d32:to=#1565c0'") 
String theme,
+            @ToolArg(description = "Optional output file path. For image 
themes a PNG is written; for text themes a .txt "
+                                   + "file is written. If not specified, a 
temporary file is created.") String outputFile,
+            @ToolArg(description = "Color theme: 'dark' (default), 'light', 
'transparent', 'ascii' (plain ASCII art), "
+                                   + "'unicode' (box-drawing characters), or a 
custom spec like "
+                                   + "'bg=#1e1e1e:from=#2e7d32:to=#1565c0'. "
+                                   + "Use 'ascii' or 'unicode' to get a text 
diagram that can be read directly.") String theme,
             @ToolArg(description = "Optional filter to limit the diagram to 
routes whose route id or source filename "
                                    + "matches the given pattern (supports 
wildcards)") String filter,
-            @ToolArg(description = "Image width in pixels; 0 (or unset) = 
auto") Integer width,
+            @ToolArg(description = "Image width in pixels; 0 (or unset) = auto 
(only used for image themes)") Integer width,
             @ToolArg(description = "Font size in logical pixels for node text 
(default 12)") Integer fontSize,
             @ToolArg(description = "Node box width in logical pixels (default 
180)") Integer boxWidth,
             @ToolArg(description = "What text to display in diagram nodes: 
'code' (default), 'description' (prefer "
@@ -64,10 +72,13 @@ public class RouteDiagramTools {
             throw new ToolCallException("Source file does not exist: " + 
sourceFile, null);
         }
 
+        boolean textMode = theme != null && 
TEXT_THEMES.contains(theme.toLowerCase());
+
         String resolvedOutput;
         try {
             if (outputFile == null || outputFile.isBlank()) {
-                Path tmp = Files.createTempFile("camel-route-diagram-", 
".png");
+                String suffix = textMode ? ".txt" : ".png";
+                Path tmp = Files.createTempFile("camel-route-diagram-", 
suffix);
                 resolvedOutput = tmp.toAbsolutePath().toString();
             } else {
                 resolvedOutput = new File(outputFile).getAbsolutePath();
@@ -97,17 +108,28 @@ public class RouteDiagramTools {
             boolean success = exit == 0 && out.isFile() && out.length() > 0;
             long size = out.exists() ? out.length() : 0L;
 
+            if (textMode) {
+                String asciiContent = success ? Files.readString(out.toPath()) 
: null;
+                String message = success
+                        ? "ASCII diagram generated (" + size + " bytes)"
+                        : "Failed to render diagram (exit code " + exit + ")";
+                return new RouteDiagramResult(success, resolvedOutput, size, 
message, asciiContent);
+            }
+
             String message = success
                     ? "Diagram saved to: " + resolvedOutput
                     : "Failed to render diagram (exit code " + exit + ")";
-
-            return new RouteDiagramResult(success, resolvedOutput, size, 
message);
+            return new RouteDiagramResult(success, resolvedOutput, size, 
message, null);
         } catch (Throwable e) {
             throw new ToolCallException(
                     "Failed to render route diagram (" + 
e.getClass().getName() + "): " + e.getMessage(), null);
         }
     }
 
-    public record RouteDiagramResult(boolean success, String outputFile, long 
sizeBytes, String message) {
+    /**
+     * @param asciiDiagram plain-text diagram content for ascii/unicode 
themes; null for image themes
+     */
+    public record RouteDiagramResult(boolean success, String outputFile, long 
sizeBytes, String message,
+            String asciiDiagram) {
     }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteDiagramToolsTest.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteDiagramToolsTest.java
index fcceec06a600..a257762b4bf6 100644
--- 
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteDiagramToolsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteDiagramToolsTest.java
@@ -50,4 +50,24 @@ class RouteDiagramToolsTest {
                 .isInstanceOf(ToolCallException.class)
                 .hasMessageContaining("does not exist");
     }
+
+    @Test
+    void nonExistingSourceFileWithAsciiThemeThrows() {
+        RouteDiagramTools tools = new RouteDiagramTools();
+
+        assertThatThrownBy(() -> tools.camel_render_route_diagram(
+                "/no/such/file.yaml", null, "ascii", null, null, null, null, 
null, null))
+                .isInstanceOf(ToolCallException.class)
+                .hasMessageContaining("does not exist");
+    }
+
+    @Test
+    void nonExistingSourceFileWithUnicodeThemeThrows() {
+        RouteDiagramTools tools = new RouteDiagramTools();
+
+        assertThatThrownBy(() -> tools.camel_render_route_diagram(
+                "/no/such/file.yaml", null, "unicode", null, null, null, null, 
null, null))
+                .isInstanceOf(ToolCallException.class)
+                .hasMessageContaining("does not exist");
+    }
 }

Reply via email to