This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch feature/tui-mcp-structured-tools
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 58624e178b7d22e7f321f3f2373e3cbd285cb993
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Jun 3 12:49:43 2026 +0200

    CAMEL-23679: camel-tui - Add structured data access MCP tools
    
    Co-Authored-By: Claude <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../camel/dsl/jbang/core/common/RuntimeHelper.java |  19 ++++
 .../dsl/jbang/core/commands/tui/ActionsPopup.java  |  36 +++++++
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  |  42 ++++++++
 .../dsl/jbang/core/commands/tui/ConsumersTab.java  |  34 ++++++
 .../jbang/core/commands/tui/DiagramSupport.java    |   4 +
 .../dsl/jbang/core/commands/tui/DiagramTab.java    |  14 +++
 .../dsl/jbang/core/commands/tui/EndpointsTab.java  |  38 +++++++
 .../dsl/jbang/core/commands/tui/ErrorsTab.java     |  43 ++++++++
 .../dsl/jbang/core/commands/tui/HealthTab.java     |  30 ++++++
 .../dsl/jbang/core/commands/tui/InflightTab.java   |  30 ++++++
 .../camel/dsl/jbang/core/commands/tui/LogTab.java  |  42 ++++++++
 .../dsl/jbang/core/commands/tui/MonitorTab.java    |   5 +
 .../dsl/jbang/core/commands/tui/OverviewTab.java   |  35 ++++++
 .../dsl/jbang/core/commands/tui/RoutesTab.java     |  35 ++++++
 .../dsl/jbang/core/commands/tui/TuiMcpServer.java  | 117 +++++++++++++++++++++
 15 files changed, 524 insertions(+)

diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeHelper.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeHelper.java
index 94897399442a..11bd051dc0cd 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeHelper.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeHelper.java
@@ -233,6 +233,25 @@ public final class RuntimeHelper {
         }
     }
 
+    public static JsonObject sendMessage(long pid, String endpoint, String 
body, String headers) {
+        String result = executeAction(pid, "send", root -> {
+            root.put("endpoint", endpoint);
+            if (body != null) {
+                root.put("body", body);
+            }
+            if (headers != null) {
+                root.put("headers", headers);
+            }
+        });
+        try {
+            return (JsonObject) Jsoner.deserialize(result);
+        } catch (Exception e) {
+            JsonObject wrapper = new JsonObject();
+            wrapper.put("result", result);
+            return wrapper;
+        }
+    }
+
     public static JsonObject readStatusFromFile(Path path) {
         try {
             if (Files.exists(path) && path.toFile().length() > 0) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
index 1fab0476680f..c37c0738799c 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
@@ -2034,6 +2034,42 @@ class ActionsPopup {
     record InfraServiceEntry(String alias, String description, List<String> 
implementations, boolean running) {
     }
 
+    boolean executeActionByName(String name) {
+        if (name == null || name.isBlank()) {
+            return false;
+        }
+        String normalized = name.replace("-", "_").toUpperCase();
+        Action action;
+        try {
+            action = Action.valueOf(normalized);
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+        switch (action) {
+            case RESET_STATS -> {
+                if (resetStatsAction != null) {
+                    resetStatsAction.run();
+                }
+            }
+            case RESET_SCREEN -> {
+                if (resetScreenAction != null) {
+                    resetScreenAction.run();
+                }
+            }
+            case SCREENSHOT -> screenshotAction.run();
+            case SHOW_KEYSTROKES -> toggleKeystrokes.run();
+            case TAPE_RECORDING -> toggleTapeRecording.run();
+            case DOCTOR -> doctorPopup.open();
+            case CAPTION -> captionOverlay.openInline();
+            case MCP_INFO -> openMcpInfo();
+            case MCP_LOG -> openMcpLog();
+            default -> {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private record PendingLaunch(String name, Process process, Path 
outputFile, long startTime) {
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
index 737b0dc326db..f3f03a59f330 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
@@ -79,6 +79,7 @@ import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
 import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
 import org.apache.camel.dsl.jbang.core.common.PathUtils;
+import org.apache.camel.dsl.jbang.core.common.RuntimeHelper;
 import org.apache.camel.dsl.jbang.core.common.VersionHelper;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
@@ -2822,6 +2823,47 @@ public class CamelMonitor extends CamelCommand {
         return null;
     }
 
+    JsonObject getTableData(String tabName) {
+        if (tabName != null && !tabName.isBlank()) {
+            String prev = getActiveTabName();
+            String switched = navigateToTab(tabName);
+            if (switched == null) {
+                return null;
+            }
+        }
+        MonitorTab tab = activeTab();
+        return tab != null ? tab.getTableDataAsJson() : null;
+    }
+
+    boolean executeAction(String actionName) {
+        return actionsPopup.executeActionByName(actionName);
+    }
+
+    JsonObject getLogData(int limit, String filter, String level) {
+        return logTab.getLogDataAsJson(limit, filter, level);
+    }
+
+    JsonObject getDiagramData() {
+        MonitorTab tab = activeTab();
+        if (tab instanceof DiagramTab dt) {
+            return dt.getTableDataAsJson();
+        }
+        return diagramTab.getTableDataAsJson();
+    }
+
+    JsonObject sendMessage(String endpoint, String body, String headers) {
+        if (ctx.selectedPid == null) {
+            return null;
+        }
+        long pid;
+        try {
+            pid = Long.parseLong(ctx.selectedPid);
+        } catch (NumberFormatException e) {
+            return null;
+        }
+        return RuntimeHelper.sendMessage(pid, endpoint, body, headers);
+    }
+
     private record PendingKey(KeyEvent event, long fireAt) {
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConsumersTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConsumersTab.java
index 37ba385ea62c..b4a147a883a4 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConsumersTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConsumersTab.java
@@ -34,6 +34,8 @@ import dev.tamboui.widgets.table.Cell;
 import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
 import dev.tamboui.widgets.table.TableState;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
 
 import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
 
@@ -395,4 +397,36 @@ class ConsumersTab implements MonitorTab {
                 - `S` — reverse sort order
                 """;
     }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Consumers");
+        JsonArray rows = new JsonArray();
+        for (ConsumerInfo ci : info.consumers) {
+            JsonObject row = new JsonObject();
+            row.put("id", ci.id);
+            row.put("uri", ci.uri);
+            row.put("state", ci.state);
+            row.put("className", ci.className);
+            row.put("scheduled", ci.scheduled);
+            row.put("inflight", ci.inflight);
+            if (ci.totalCounter != null) {
+                row.put("totalCounter", ci.totalCounter);
+            }
+            if (ci.polling != null) {
+                row.put("polling", ci.polling);
+            }
+            rows.add(row);
+        }
+        result.put("rows", rows);
+        result.put("totalRows", info.consumers.size());
+        Integer sel = tableState.selected();
+        result.put("selectedIndex", sel != null ? sel : -1);
+        return result;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
index 43985f4db3fc..193419ff8e52 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
@@ -84,6 +84,10 @@ class DiagramSupport {
     private int cropH = -1;
     private final AtomicBoolean loading = new AtomicBoolean(false);
 
+    List<String> getLines() {
+        return lines;
+    }
+
     boolean isShowDiagram() {
         return showDiagram;
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
index 3c08ef6fbbee..034485a3729f 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
@@ -28,6 +28,7 @@ import dev.tamboui.tui.event.KeyEvent;
 import dev.tamboui.widgets.block.Block;
 import dev.tamboui.widgets.block.BorderType;
 import dev.tamboui.widgets.paragraph.Paragraph;
+import org.apache.camel.util.json.JsonObject;
 
 import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
 
@@ -276,4 +277,17 @@ class DiagramTab implements MonitorTab {
                                 - `Esc` — close diagram
                 """;
     }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        List<String> lines = diagram.getLines();
+        if (lines == null || lines.isEmpty()) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Diagram");
+        result.put("diagram", String.join("\n", lines));
+        result.put("lines", lines.size());
+        return result;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
index d34f07644234..db5b29d7b7a3 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
@@ -41,6 +41,8 @@ import dev.tamboui.widgets.table.Cell;
 import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
 import dev.tamboui.widgets.table.TableState;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
 
 import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
 
@@ -749,4 +751,40 @@ class EndpointsTab implements MonitorTab {
                 - `f` — cycle filter mode
                 """;
     }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Endpoints");
+        JsonArray rows = new JsonArray();
+        for (EndpointInfo ei : info.endpoints) {
+            JsonObject row = new JsonObject();
+            row.put("uri", ei.uri);
+            row.put("component", ei.component);
+            row.put("direction", ei.direction);
+            row.put("routeId", ei.routeId);
+            row.put("hits", ei.hits);
+            row.put("remote", ei.remote);
+            row.put("stub", ei.stub);
+            if (ei.meanBodySize >= 0) {
+                row.put("meanBodySize", ei.meanBodySize);
+            }
+            if (ei.maxBodySize >= 0) {
+                row.put("maxBodySize", ei.maxBodySize);
+            }
+            if (ei.meanHeadersSize >= 0) {
+                row.put("meanHeadersSize", ei.meanHeadersSize);
+            }
+            rows.add(row);
+        }
+        result.put("rows", rows);
+        result.put("totalRows", info.endpoints.size());
+        Integer sel = tableState.selected();
+        result.put("selectedIndex", sel != null ? sel : -1);
+        return result;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
index 2b817ab500ad..b6acc9c6ff05 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
@@ -36,6 +36,8 @@ import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
 import dev.tamboui.widgets.table.TableState;
 import org.apache.camel.diagram.RouteDiagramHelper;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
 import org.apache.camel.util.json.Jsoner;
 
 import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
@@ -550,4 +552,45 @@ class ErrorsTab implements MonitorTab {
                 - `Esc` — back to list
                 """;
     }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Errors");
+        JsonArray rows = new JsonArray();
+        for (ErrorInfo ei : info.errors) {
+            JsonObject row = new JsonObject();
+            row.put("routeId", ei.routeId);
+            row.put("nodeId", ei.nodeId);
+            row.put("exchangeId", ei.exchangeId);
+            row.put("handled", ei.handled);
+            row.put("timestamp", ei.timestamp);
+            row.put("elapsed", ei.elapsed);
+            if (ei.exceptionType != null) {
+                row.put("exceptionType", ei.exceptionType);
+            }
+            if (ei.exceptionMessage != null) {
+                row.put("exceptionMessage", ei.exceptionMessage);
+            }
+            if (ei.stackTrace != null) {
+                row.put("stackTrace", ei.stackTrace);
+            }
+            if (ei.body != null) {
+                row.put("body", ei.body);
+            }
+            if (!ei.headers.isEmpty()) {
+                row.put("headers", new JsonObject(ei.headers));
+            }
+            rows.add(row);
+        }
+        result.put("rows", rows);
+        result.put("totalRows", info.errors.size());
+        Integer sel = tableState.selected();
+        result.put("selectedIndex", sel != null ? sel : -1);
+        return result;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HealthTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HealthTab.java
index b8645f9adacd..3be1eaa89f68 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HealthTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HealthTab.java
@@ -32,6 +32,8 @@ import dev.tamboui.widgets.table.Cell;
 import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
 import dev.tamboui.widgets.table.TableState;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
 
 import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
 
@@ -282,4 +284,32 @@ class HealthTab implements MonitorTab {
                 - `S` — reverse sort order
                 """;
     }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Health");
+        JsonArray rows = new JsonArray();
+        for (HealthCheckInfo hi : info.healthChecks) {
+            JsonObject row = new JsonObject();
+            row.put("group", hi.group);
+            row.put("name", hi.name);
+            row.put("state", hi.state);
+            row.put("readiness", hi.readiness);
+            row.put("liveness", hi.liveness);
+            if (hi.message != null) {
+                row.put("message", hi.message);
+            }
+            rows.add(row);
+        }
+        result.put("rows", rows);
+        result.put("totalRows", info.healthChecks.size());
+        Integer sel = tableState.selected();
+        result.put("selectedIndex", sel != null ? sel : -1);
+        return result;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/InflightTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/InflightTab.java
index 80704fb410da..474aede450f3 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/InflightTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/InflightTab.java
@@ -36,6 +36,8 @@ import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
 import dev.tamboui.widgets.table.TableState;
 import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
 
 import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
 
@@ -310,4 +312,32 @@ class InflightTab implements MonitorTab {
                 - `Esc` — back
                 """;
     }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Inflight");
+        JsonArray rows = new JsonArray();
+        for (InflightInfo ii : info.inflightExchanges) {
+            JsonObject row = new JsonObject();
+            row.put("exchangeId", ii.exchangeId);
+            row.put("fromRouteId", ii.fromRouteId);
+            row.put("fromRemoteEndpoint", ii.fromRemoteEndpoint);
+            row.put("atRouteId", ii.atRouteId);
+            row.put("nodeId", ii.nodeId);
+            row.put("elapsed", ii.elapsed);
+            row.put("duration", ii.duration);
+            row.put("blocked", ii.blocked);
+            rows.add(row);
+        }
+        result.put("rows", rows);
+        result.put("totalRows", info.inflightExchanges.size());
+        Integer sel = tableState.selected();
+        result.put("selectedIndex", sel != null ? sel : -1);
+        return result;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LogTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LogTab.java
index bb2bb659dfb9..e114eff4a211 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LogTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LogTab.java
@@ -53,6 +53,7 @@ import dev.tamboui.widgets.paragraph.Paragraph;
 import dev.tamboui.widgets.scrollbar.Scrollbar;
 import dev.tamboui.widgets.scrollbar.ScrollbarState;
 import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
+import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
 import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
@@ -847,4 +848,45 @@ class LogTab implements MonitorTab {
                 - `Esc` — clear find / back
                 """;
     }
+
+    JsonObject getLogDataAsJson(int limit, String filter, String level) {
+        List<LogEntry> entries = filteredLogEntries;
+        if (entries == null || entries.isEmpty()) {
+            JsonObject result = new JsonObject();
+            result.put("lines", new JsonArray());
+            result.put("totalLines", 0);
+            result.put("returnedLines", 0);
+            return result;
+        }
+
+        List<LogEntry> filtered = new ArrayList<>();
+        for (int i = entries.size() - 1; i >= 0 && filtered.size() < limit; 
i--) {
+            LogEntry e = entries.get(i);
+            if (level != null && !level.isBlank() && 
!level.equalsIgnoreCase(e.level)) {
+                continue;
+            }
+            if (filter != null && !filter.isBlank()
+                    && 
!e.message.toLowerCase().contains(filter.toLowerCase())) {
+                continue;
+            }
+            filtered.add(e);
+        }
+
+        JsonObject result = new JsonObject();
+        JsonArray rows = new JsonArray();
+        for (LogEntry e : filtered) {
+            JsonObject row = new JsonObject();
+            row.put("time", e.time);
+            row.put("level", e.level);
+            if (e.logger != null) {
+                row.put("logger", e.logger);
+            }
+            row.put("message", e.message);
+            rows.add(row);
+        }
+        result.put("lines", rows);
+        result.put("totalLines", entries.size());
+        result.put("returnedLines", filtered.size());
+        return result;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorTab.java
index 1b213347e4f8..4c80a484c3a8 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorTab.java
@@ -22,6 +22,7 @@ import dev.tamboui.layout.Rect;
 import dev.tamboui.terminal.Frame;
 import dev.tamboui.text.Span;
 import dev.tamboui.tui.event.KeyEvent;
+import org.apache.camel.util.json.JsonObject;
 
 /**
  * Interface for TUI monitor tabs. Each tab handles its own events, rendering, 
and footer hints.
@@ -53,4 +54,8 @@ interface MonitorTab {
     default String getHelpText() {
         return null;
     }
+
+    default JsonObject getTableDataAsJson() {
+        return null;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
index 505627de6223..a6411a3c701b 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
@@ -43,6 +43,8 @@ import dev.tamboui.widgets.table.Cell;
 import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
 import dev.tamboui.widgets.table.TableState;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
 
 import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
 import static 
org.apache.camel.dsl.jbang.core.common.CamelCommandHelper.extractState;
@@ -791,4 +793,37 @@ class OverviewTab implements MonitorTab {
                 - `F3` — switch integration
                 """;
     }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        List<IntegrationInfo> integrations = ctx.data.get();
+        if (integrations == null || integrations.isEmpty()) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Overview");
+        JsonArray rows = new JsonArray();
+        for (IntegrationInfo info : integrations) {
+            JsonObject row = new JsonObject();
+            row.put("pid", info.pid);
+            row.put("name", info.name);
+            row.put("camelVersion", info.camelVersion);
+            row.put("platform", info.platform);
+            row.put("state", info.state);
+            row.put("ready", info.ready);
+            row.put("uptime", info.uptime);
+            row.put("exchangesTotal", info.exchangesTotal);
+            row.put("failed", info.failed);
+            row.put("inflight", info.inflight);
+            row.put("throughput", info.throughput);
+            row.put("routeStarted", info.routeStarted);
+            row.put("routeTotal", info.routeTotal);
+            rows.add(row);
+        }
+        result.put("rows", rows);
+        result.put("totalRows", integrations.size());
+        Integer sel = tableState.selected();
+        result.put("selectedIndex", sel != null ? sel : -1);
+        return result;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
index 295dba6e591b..8fcf67c03807 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
@@ -1283,4 +1283,39 @@ class RoutesTab implements MonitorTab {
                 - `Esc` — back to route list
                 """;
     }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Routes");
+        JsonArray rows = new JsonArray();
+        for (RouteInfo ri : info.routes) {
+            JsonObject row = new JsonObject();
+            row.put("routeId", ri.routeId);
+            row.put("from", ri.from);
+            row.put("state", ri.state);
+            row.put("uptime", ri.uptime);
+            row.put("total", ri.total);
+            row.put("failed", ri.failed);
+            row.put("inflight", ri.inflight);
+            row.put("mean", ri.meanTime);
+            row.put("max", ri.maxTime);
+            row.put("min", ri.minTime);
+            row.put("last", ri.lastTime);
+            row.put("throughput", ri.throughput);
+            if (ri.group != null) {
+                row.put("group", ri.group);
+            }
+            rows.add(row);
+        }
+        result.put("rows", rows);
+        result.put("totalRows", info.routes.size());
+        Integer sel = routeTableState.selected();
+        result.put("selectedIndex", sel != null ? sel : -1);
+        return result;
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiMcpServer.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiMcpServer.java
index a1dc64ae002f..c93da5e0685b 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiMcpServer.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiMcpServer.java
@@ -347,6 +347,49 @@ class TuiMcpServer {
                                   + "The underlying content is unchanged since 
drawing is an overlay.",
                 Map.of()));
 
+        // --- Structured data tools ---
+
+        toolList.add(toolDef(
+                "tui_get_table",
+                "Returns the currently visible table data as structured JSON 
with typed values. "
+                                 + "Much more reliable than parsing screen 
text. "
+                                 + "Returns tab name, rows array with all 
fields, totalRows, and selectedIndex.",
+                Map.of("tab", propDef("string",
+                        "Tab name to get data from (e.g. 'Routes', 
'Endpoints', 'Health'). "
+                                                + "If omitted, uses the active 
tab."))));
+        toolList.add(toolDef(
+                "tui_action",
+                "Invokes a TUI action by name, bypassing fragile key 
sequences. "
+                              + "Actions: reset-stats, reset-screen, 
screenshot, show-keystrokes, "
+                              + "tape-recording, doctor, caption, mcp-info, 
mcp-log.",
+                Map.of("action", propDef("string", "Action name in kebab-case 
(e.g. 'reset-stats', 'screenshot')")),
+                List.of("action")));
+        toolList.add(toolDef(
+                "tui_get_log",
+                "Returns recent log lines as structured data with optional 
filtering. "
+                               + "Returns newest entries first.",
+                Map.of("limit", propDef("integer", "Maximum lines to return 
(default 50)"),
+                        "filter", propDef("string", "Case-insensitive 
substring filter on log message"),
+                        "level", propDef("string", "Filter by log level (INFO, 
WARN, ERROR, DEBUG, TRACE)"))));
+        toolList.add(toolDef(
+                "tui_get_errors",
+                "Returns structured error data from the Errors tab. "
+                                  + "Includes routeId, exchangeId, exception 
details, stack trace, body, and headers.",
+                Map.of()));
+        toolList.add(toolDef(
+                "tui_get_diagram",
+                "Returns the route topology diagram as text. "
+                                   + "Shows the ASCII/Unicode art diagram of 
routes and their connections.",
+                Map.of()));
+        toolList.add(toolDef(
+                "tui_send_message",
+                "Sends a message to a Camel endpoint in the selected 
integration. "
+                                    + "Uses the file-based IPC protocol to 
deliver the message directly.",
+                Map.of("endpoint", propDef("string", "Endpoint URI to send to 
(e.g. 'direct:myRoute', 'seda:queue')"),
+                        "body", propDef("string", "Message body to send"),
+                        "headers", propDef("string", "Message headers as 
key=value pairs separated by newlines")),
+                List.of("endpoint")));
+
         JsonObject result = new JsonObject();
         result.put("tools", toolList);
         return result;
@@ -380,6 +423,12 @@ class TuiMcpServer {
                 case "tui_sleep" -> callSleep(args);
                 case "tui_draw" -> callDraw(args);
                 case "tui_draw_clear" -> callDrawClear();
+                case "tui_get_table" -> callGetTable(args);
+                case "tui_action" -> callAction(args);
+                case "tui_get_log" -> callGetLog(args);
+                case "tui_get_errors" -> callGetErrors();
+                case "tui_get_diagram" -> callGetDiagram();
+                case "tui_send_message" -> callSendMessage(args);
                 default -> {
                     isError = true;
                     yield "Unknown tool: " + toolName;
@@ -844,6 +893,74 @@ class TuiMcpServer {
         return "Drawing cleared";
     }
 
+    private String callGetTable(Map<String, Object> args) {
+        String tab = args.get("tab") instanceof String s ? s : null;
+        JsonObject data = monitor.getTableData(tab);
+        if (data == null) {
+            return "No table data available" + (tab != null ? " for tab: " + 
tab : "");
+        }
+        return Jsoner.serialize(data);
+    }
+
+    private String callAction(Map<String, Object> args) {
+        String action = (String) args.get("action");
+        if (action == null || action.isBlank()) {
+            return "Error: action is required";
+        }
+        boolean executed = monitor.executeAction(action);
+        if (executed) {
+            return "Action '" + action + "' executed";
+        }
+        return "Unknown or unsupported action: " + action
+               + ". Available: reset-stats, reset-screen, screenshot, 
show-keystrokes, "
+               + "tape-recording, doctor, caption, mcp-info, mcp-log";
+    }
+
+    private String callGetLog(Map<String, Object> args) {
+        int limit = 50;
+        if (args.get("limit") instanceof Number n) {
+            limit = Math.max(1, Math.min(1000, n.intValue()));
+        }
+        String filter = args.get("filter") instanceof String s ? s : null;
+        String level = args.get("level") instanceof String s ? s : null;
+        JsonObject data = monitor.getLogData(limit, filter, level);
+        return Jsoner.serialize(data);
+    }
+
+    private String callGetErrors() {
+        JsonObject data = monitor.getTableData("Errors");
+        if (data == null) {
+            JsonObject empty = new JsonObject();
+            empty.put("tab", "Errors");
+            empty.put("rows", new JsonArray());
+            empty.put("totalRows", 0);
+            return Jsoner.serialize(empty);
+        }
+        return Jsoner.serialize(data);
+    }
+
+    private String callGetDiagram() {
+        JsonObject data = monitor.getDiagramData();
+        if (data == null) {
+            return "No diagram available. Navigate to the Diagram tab first.";
+        }
+        return Jsoner.serialize(data);
+    }
+
+    private String callSendMessage(Map<String, Object> args) {
+        String endpoint = (String) args.get("endpoint");
+        if (endpoint == null || endpoint.isBlank()) {
+            return "Error: endpoint is required";
+        }
+        String body = args.get("body") instanceof String s ? s : null;
+        String headers = args.get("headers") instanceof String s ? s : null;
+        JsonObject response = monitor.sendMessage(endpoint, body, headers);
+        if (response == null) {
+            return "Error: no integration selected or PID unavailable";
+        }
+        return Jsoner.serialize(response);
+    }
+
     private static JsonArray toJsonArray(List<String> list) {
         JsonArray arr = new JsonArray();
         arr.addAll(list);


Reply via email to