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 ff1f11035d17 camel-jbang - Add tui_get_processor_detail MCP tool
ff1f11035d17 is described below
commit ff1f11035d1754c845fec441989c280c514c4aa5
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Jul 24 11:15:17 2026 +0200
camel-jbang - Add tui_get_processor_detail MCP tool
Add a new MCP tool to the TUI that exposes processor detail data
(EIP configuration, options, catalog documentation) as structured JSON
for AI agents. This is the programmatic equivalent of the Diagram tab's
detail panel, making EIP and component configuration accessible to AI
without parsing visual output.
camel-jbang - Add tui_get_ai_log and tui_get_mcp_log MCP tools
Expose the AI panel activity log and MCP server tool call log
to external AI agents via MCP, so they can see what was already
investigated and audit MCP interactions.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../camel/dsl/jbang/core/commands/tui/AiPanel.java | 6 ++
.../dsl/jbang/core/commands/tui/CamelMonitor.java | 2 +
.../dsl/jbang/core/commands/tui/McpFacade.java | 29 +++++++++
.../jbang/core/commands/tui/TuiToolRegistry.java | 73 +++++++++++++++++++++-
4 files changed, 109 insertions(+), 1 deletion(-)
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
index c2b26cff3c35..2cbf27d80bbe 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
@@ -1359,6 +1359,12 @@ class AiPanel {
sb.append("- tui_get_errors: get error details with stack traces,
WITHOUT navigating to the Errors tab\n");
sb.append("- tui_get_diagram: view route diagrams as text, WITHOUT
navigating to the Diagram tab\n");
sb.append("- tui_get_topology: see how routes connect to each other,
WITHOUT navigating to the Topology tab\n");
+ sb.append("- tui_get_processor_detail: get configured options for all
processors in a route as structured JSON. ");
+ sb.append("USE THIS to explain what a route does, walk through each
step, or understand EIP/component configuration. ");
+ sb.append("Set includeDocs=true to get catalog documentation for each
option\n");
+ sb.append("- tui_catalog_doc: look up Camel catalog documentation for
any component, EIP, data format, or language\n");
+ sb.append("- tui_get_ai_log: view the AI panel's own activity log
(questions, tool calls, responses)\n");
+ sb.append("- tui_get_mcp_log: view the MCP server's tool call log
(external client connections and requests)\n");
sb.append("- tui_get_history: trace exchange processing steps, WITHOUT
navigating to the History tab\n");
sb.append("- tui_get_spans: OpenTelemetry span data, WITHOUT
navigating to the Spans tab\n");
sb.append("- tui_navigate: switch tabs, select integrations, select
routes ");
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 57bd47762717..7dc8be3d826c 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
@@ -476,12 +476,14 @@ public class CamelMonitor extends CamelCommand {
}
});
aiPanel.setMcpFacade(mcpFacade);
+ mcpFacade.setAiActivityLog(aiPanel::getActivityLog);
Path mcpJsonFile = null;
actionsPopup.setAiActivityLog(aiPanel::getActivityLog);
if (mcp) {
mcpServer = new TuiMcpServer(mcpPort, mcpFacade);
try {
mcpServer.start();
+ mcpFacade.setMcpActivityLog(mcpServer::getActivityLog,
mcpServer::getToolCallCount);
actionsPopup.setMcpEnabled(true, mcpPort,
mcpServer::getConnectedClient,
mcpServer::getActivityLog,
mcpServer::getToolCallCount);
mcpJsonFile = writeMcpJson(mcpPort);
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpFacade.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpFacade.java
index 044ee50c679b..90941b7fdedd 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpFacade.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpFacade.java
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
import dev.tamboui.buffer.Buffer;
import dev.tamboui.export.ExportRequest;
@@ -101,6 +102,10 @@ class McpFacade {
private final Queue<PendingKey> pendingKeys;
private final MonitorBridge bridge;
+ private volatile Supplier<List<AiPanel.LogEntry>> aiActivityLog;
+ private volatile Supplier<List<TuiMcpServer.LogEntry>> mcpActivityLog;
+ private volatile Supplier<Integer> mcpToolCallCount;
+
McpFacade(
MonitorContext ctx,
AtomicReference<List<IntegrationInfo>> data,
@@ -130,6 +135,30 @@ class McpFacade {
this.bridge = bridge;
}
+ void setAiActivityLog(Supplier<List<AiPanel.LogEntry>> aiActivityLog) {
+ this.aiActivityLog = aiActivityLog;
+ }
+
+ void setMcpActivityLog(Supplier<List<TuiMcpServer.LogEntry>>
mcpActivityLog, Supplier<Integer> mcpToolCallCount) {
+ this.mcpActivityLog = mcpActivityLog;
+ this.mcpToolCallCount = mcpToolCallCount;
+ }
+
+ List<AiPanel.LogEntry> getAiActivityLog() {
+ Supplier<List<AiPanel.LogEntry>> s = aiActivityLog;
+ return s != null ? s.get() : List.of();
+ }
+
+ List<TuiMcpServer.LogEntry> getMcpActivityLog() {
+ Supplier<List<TuiMcpServer.LogEntry>> s = mcpActivityLog;
+ return s != null ? s.get() : List.of();
+ }
+
+ int getMcpToolCallCount() {
+ Supplier<Integer> s = mcpToolCallCount;
+ return s != null ? s.get() : 0;
+ }
+
// ---- Screen state ----
Buffer getLastBuffer() {
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
index eeffc94d43d5..5d6b5f9d77da 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
@@ -79,7 +79,7 @@ class TuiToolRegistry {
}
/**
- * Returns all 40 tool definitions. The result is cached since it is
immutable.
+ * Returns all 42 tool definitions. The result is cached since it is
immutable.
*/
List<ToolDef> getToolDefinitions() {
List<ToolDef> tools = cachedTools;
@@ -137,6 +137,8 @@ class TuiToolRegistry {
case "tui_animate_status" -> callAnimateStatus(args);
case "tui_catalog_doc" -> callCatalogDoc(args);
case "tui_get_processor_detail" -> callGetProcessorDetail(args);
+ case "tui_get_ai_log" -> callGetAiLog(args);
+ case "tui_get_mcp_log" -> callGetMcpLog(args);
case "tui_list_examples" -> callListExamples(args);
case "tui_run_example" -> callRunExample(args);
default -> throw new IllegalArgumentException("Unknown tool: " +
name);
@@ -591,6 +593,25 @@ class TuiToolRegistry {
"If true, enrich each processor's options with
documentation from the Camel catalog "
+ "(description,
type, group, defaultValue, required, deprecated, enum values)")))));
+ // --- AI and MCP log tools ---
+
+ tools.add(toToolDef(toolDef(
+ "tui_get_ai_log",
+ "Returns the TUI's built-in AI panel activity log as
structured JSON. "
+ + "Shows the AI panel's questions, tool
calls, tool results, responses, and errors. "
+ + "Useful to see what the built-in AI has
already investigated "
+ + "before repeating the same work.",
+ Map.of("limit", propDef("integer",
+ "Maximum number of entries to return (default
50)")))));
+
+ tools.add(toToolDef(toolDef(
+ "tui_get_mcp_log",
+ "Returns the TUI MCP server's tool call log as structured
JSON. "
+ + "Shows external MCP client connections
and tool call requests/responses. "
+ + "Useful for debugging and auditing MCP
interactions.",
+ Map.of("limit", propDef("integer",
+ "Maximum number of entries to return (default
50)")))));
+
// --- Example tools ---
tools.add(toToolDef(toolDef(
@@ -2037,6 +2058,56 @@ class TuiToolRegistry {
return doc;
}
+ private String callGetAiLog(Map<String, Object> args) {
+ int limit = args.get("limit") instanceof Number n ? n.intValue() : 50;
+ List<AiPanel.LogEntry> entries = facade.getAiActivityLog();
+ if (entries.size() > limit) {
+ entries = entries.subList(entries.size() - limit, entries.size());
+ }
+ JsonArray arr = new JsonArray();
+ for (AiPanel.LogEntry e : entries) {
+ JsonObject obj = new JsonObject();
+ obj.put("timestamp", e.timestamp());
+ obj.put("level", e.level().name());
+ obj.put("message", e.message());
+ if (e.detail() != null) {
+ obj.put("detail", e.detail());
+ }
+ arr.add(obj);
+ }
+ JsonObject result = new JsonObject();
+ result.put("entries", arr);
+ result.put("count", arr.size());
+ return result.toJson();
+ }
+
+ private String callGetMcpLog(Map<String, Object> args) {
+ int limit = args.get("limit") instanceof Number n ? n.intValue() : 50;
+ List<TuiMcpServer.LogEntry> entries = facade.getMcpActivityLog();
+ if (entries.size() > limit) {
+ entries = entries.subList(entries.size() - limit, entries.size());
+ }
+ JsonArray arr = new JsonArray();
+ for (TuiMcpServer.LogEntry e : entries) {
+ JsonObject obj = new JsonObject();
+ obj.put("timestamp", e.timestamp());
+ obj.put("level", e.level().name());
+ obj.put("message", e.message());
+ if (e.requestBody() != null) {
+ obj.put("requestBody", e.requestBody());
+ }
+ if (e.responseBody() != null) {
+ obj.put("responseBody", e.responseBody());
+ }
+ arr.add(obj);
+ }
+ JsonObject result = new JsonObject();
+ result.put("entries", arr);
+ result.put("count", arr.size());
+ result.put("toolCallCount", facade.getMcpToolCallCount());
+ return result.toJson();
+ }
+
@SuppressWarnings("unchecked")
private String callListExamples(Map<String, Object> args) {
List<JsonObject> catalog = exampleCatalog;