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

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

commit 20f572763943dfc58cc132b8bda723d5bc71550f
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun May 24 19:24:43 2026 +0200

    CAMEL-23606: camel-tui - MCP navigation tool for tab switching and 
integration selection
    
    Adds tui_navigate MCP tool so AI agents can switch tabs and select
    integrations without key injection. Returns available options on error
    so the agent can self-correct.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../dsl/jbang/core/commands/tui/ActionsPopup.java  |  7 +++-
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  | 37 ++++++++++++++++
 .../dsl/jbang/core/commands/tui/TuiMcpServer.java  | 49 ++++++++++++++++++++++
 3 files changed, 91 insertions(+), 2 deletions(-)

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 0a2d768614e0..bfce21ee00ef 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
@@ -699,7 +699,8 @@ class ActionsPopup {
                      + "| `tui_get_screen` | Returns the current screen 
content as text |\n"
                      + "| `tui_get_events` | Returns recent key presses and 
navigation events |\n"
                      + "| `tui_get_state` | Returns active tab, selected 
integration, etc. |\n"
-                     + "| `tui_show_caption` | Shows a message on the TUI 
screen |\n\n"
+                     + "| `tui_show_caption` | Shows a message on the TUI 
screen |\n"
+                     + "| `tui_navigate` | Switch tabs and select integrations 
|\n\n"
                      + "## Setup for Claude Code\n\n"
                      + "Run this command to connect Claude Code to the 
TUI:\n\n"
                      + "    claude mcp add --transport http camel-tui " + url 
+ "\n\n"
@@ -720,7 +721,9 @@ class ActionsPopup {
                      + "- \"What tab am I on and what integration is 
selected?\"\n"
                      + "- \"What keys did I press in the last minute?\"\n"
                      + "- \"What color is the throughput chart?\"\n"
-                     + "- \"Show me a message on the TUI screen\"\n";
+                     + "- \"Show me a message on the TUI screen\"\n"
+                     + "- \"Switch to the Health tab\"\n"
+                     + "- \"Select the myApp integration\"\n";
         docTitle = "MCP Info";
         docScroll = 0;
         showDocViewer = true;
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 e11639e0a850..ce9cdb0e5248 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
@@ -3060,4 +3060,41 @@ public class CamelMonitor extends CamelCommand {
         captionOverlay.showCaption(text);
     }
 
+    String navigateToTab(String tabName) {
+        for (int i = 0; i < TAB_NAMES.length; i++) {
+            if (TAB_NAMES[i].equalsIgnoreCase(tabName)) {
+                handleTabKey(i);
+                return TAB_NAMES[i];
+            }
+        }
+        return null;
+    }
+
+    String selectIntegration(String nameOrPid) {
+        List<IntegrationInfo> infos = data.get();
+        for (IntegrationInfo info : infos) {
+            if (info.vanishing) {
+                continue;
+            }
+            if (nameOrPid.equals(info.pid)
+                    || (info.name != null && 
info.name.equalsIgnoreCase(nameOrPid))) {
+                ctx.selectedPid = info.pid;
+                ctx.infraTableFocused = false;
+                return info.name != null ? info.name : info.pid;
+            }
+        }
+        return null;
+    }
+
+    List<String> getTabNames() {
+        return List.of(TAB_NAMES);
+    }
+
+    List<String> getIntegrationNames() {
+        return data.get().stream()
+                .filter(i -> !i.vanishing)
+                .map(i -> i.name != null ? i.name : i.pid)
+                .toList();
+    }
+
 }
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 0d3fd0854fd9..3cfd6e483b69 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
@@ -213,6 +213,13 @@ class TuiMcpServer {
                                     + "Supports \\n for newlines.",
                 Map.of("text", propDef("string", "The caption text to 
display")),
                 List.of("text")));
+        toolList.add(toolDef(
+                "tui_navigate",
+                "Navigates the TUI: switch tabs and/or select an integration. "
+                                + "Both parameters are optional — set 
whichever you want to change. "
+                                + "Tab names: Overview, Log, Routes, 
Consumers, Endpoints, HTTP, Health, Inspect, Circuit Breaker.",
+                Map.of("tab", propDef("string", "Tab to switch to (e.g. 
'Routes', 'Health')"),
+                        "integration", propDef("string", "Integration name or 
PID to select"))));
 
         JsonObject result = new JsonObject();
         result.put("tools", toolList);
@@ -239,6 +246,7 @@ class TuiMcpServer {
                 case "tui_get_events" -> callGetEvents(args);
                 case "tui_get_state" -> callGetState();
                 case "tui_show_caption" -> callShowCaption(args);
+                case "tui_navigate" -> callNavigate(args);
                 default -> {
                     isError = true;
                     yield "Unknown tool: " + toolName;
@@ -333,6 +341,47 @@ class TuiMcpServer {
         return "Caption displayed: " + text;
     }
 
+    private String callNavigate(Map<String, Object> args) {
+        JsonObject result = new JsonObject();
+        String tab = (String) args.get("tab");
+        String integration = (String) args.get("integration");
+
+        if (tab == null && integration == null) {
+            result.put("error", "Provide at least one of: tab, integration");
+            result.put("availableTabs", toJsonArray(monitor.getTabNames()));
+            result.put("availableIntegrations", 
toJsonArray(monitor.getIntegrationNames()));
+            return Jsoner.serialize(result);
+        }
+
+        if (integration != null) {
+            String selected = monitor.selectIntegration(integration);
+            if (selected != null) {
+                result.put("selectedIntegration", selected);
+            } else {
+                result.put("integrationError", "Not found: " + integration);
+                result.put("availableIntegrations", 
toJsonArray(monitor.getIntegrationNames()));
+            }
+        }
+
+        if (tab != null) {
+            String switched = monitor.navigateToTab(tab);
+            if (switched != null) {
+                result.put("activeTab", switched);
+            } else {
+                result.put("tabError", "Unknown tab: " + tab);
+                result.put("availableTabs", 
toJsonArray(monitor.getTabNames()));
+            }
+        }
+
+        return Jsoner.serialize(result);
+    }
+
+    private static JsonArray toJsonArray(List<String> list) {
+        JsonArray arr = new JsonArray();
+        arr.addAll(list);
+        return arr;
+    }
+
     // --- JSON-RPC helpers ---
 
     private void sendResult(HttpExchange exchange, JsonObject request, 
JsonObject result) throws IOException {

Reply via email to