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 6edffdd14288 CAMEL-24867: camel-jbang-mcp - expose the sql, 
datasource, circuit breaker, metrics, spans, EIP stats, startup and route 
analysis runtime tools
6edffdd14288 is described below

commit 6edffdd1428876e4c9494090ff944279781464f5
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Sep 21 11:08:33 2026 +0200

    CAMEL-24867: camel-jbang-mcp - expose the sql, datasource, circuit breaker, 
metrics, spans, EIP stats, startup and route analysis runtime tools
    
    CAMEL-24867
    
    The MCP server wraps the shared runtime tool registry in `RuntimeTools`, 
but only 27 of its runtime tools. A model working through the MCP server on an 
app with a datasource could not look at the database at all, nor at circuit 
breakers, metrics, spans, EIP statistics, startup steps, route analysis or 
configuration drift, although the running app answers all of them and the 
camel-jbang views and the agent REPL already have them.
    
    This adds ten wrappers with the same `camel_runtime_*` naming and 
delegation as the existing ones:
    
    | Tool | Registry tool |
    |---|---|
    | `camel_runtime_sql` | `execute_sql` |
    | `camel_runtime_datasources` | `get_datasources` |
    | `camel_runtime_sql_trace` | `get_sql_trace` |
    | `camel_runtime_circuit_breakers` | `get_circuit_breakers` |
    | `camel_runtime_metrics` | `get_metrics` |
    | `camel_runtime_eip_stats` | `get_eip_stats` |
    | `camel_runtime_spans` | `get_spans` |
    | `camel_runtime_startup_steps` | `get_startup_steps` |
    | `camel_runtime_route_analysis` | `get_route_analysis` |
    | `camel_runtime_config_drift` | `detect_config_drift` |
    
    The remaining unwrapped registry tools are covered by other MCP tools 
already (catalog, examples, errors, eval, control, heap dump, processes). 
Documented in a new "Data, Resilience and Analysis" table of the 
camel-jbang-mcp page. Tests: `RuntimeToolsTest` checks the required argument of 
the sql tool and that every wrapper names a registry tool that exists.
    
    Found while preparing the CAMEL-24834 tool-group experiment on the 
camel-jbang-mcp server: the sql example on H2 was meant to compare the 
authoring set with and without the sql tools, and the server had none of them.
---
 .../modules/ROOT/pages/camel-jbang-mcp.adoc        |  40 +++++
 .../dsl/jbang/core/commands/mcp/RuntimeTools.java  | 174 +++++++++++++++++----
 .../jbang/core/commands/mcp/RuntimeToolsTest.java  |  18 +++
 3 files changed, 205 insertions(+), 27 deletions(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc
index ec63967b8187..30f7ee2a02e2 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc
@@ -690,6 +690,46 @@ process is running).
 | Get a JVM thread dump showing thread names, states, and stack traces.
 |===
 
+==== Data, Resilience and Analysis
+
+[cols="1,3",options="header"]
+|===
+| Tool | Description
+
+| `camel_runtime_sql`
+| Execute a SQL statement against a DataSource of the running application: 
columns and rows for a SELECT,
+  the update count otherwise. Lets the model look at the data a route reads or 
writes, or try a statement
+  before putting it in a route.
+
+| `camel_runtime_datasources`
+| Datasource connection pool status: active, idle and total connections, max 
pool size and waiting threads.
+
+| `camel_runtime_sql_trace`
+| Traced SQL executions of the camel-sql and camel-jdbc components with 
timing, row counts, route ID and
+  failure status.
+
+| `camel_runtime_circuit_breakers`
+| Circuit breaker state (CLOSED/OPEN/HALF_OPEN), call counts, failure rates 
and not-permitted calls.
+
+| `camel_runtime_metrics`
+| Micrometer metrics: counters, gauges, timers and distributions (requires 
`--observe` or camel-micrometer).
+
+| `camel_runtime_eip_stats`
+| EIP usage across all routes with processor counts and performance figures.
+
+| `camel_runtime_spans`
+| OpenTelemetry spans with trace IDs, durations, route IDs and status 
(requires `--observe`).
+
+| `camel_runtime_startup_steps`
+| Startup recorder steps with duration, level and type (requires 
`camel.main.startup-recorder=true`).
+
+| `camel_runtime_route_analysis`
+| Anti-pattern and structure analysis per route: error handling, complexity, 
component usage.
+
+| `camel_runtime_config_drift`
+| Compares the running route definitions with the source files to detect 
configuration drift.
+|===
+
 ==== Configuration and Registry
 
 [cols="1,3",options="header"]
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RuntimeTools.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RuntimeTools.java
index 7a6f7fa9b495..2432e3a5212e 100644
--- 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RuntimeTools.java
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RuntimeTools.java
@@ -115,77 +115,77 @@ public class RuntimeTools {
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Get Camel context information: name, version, state, 
uptime, route count, exchange statistics.")
     public JsonObject camel_runtime_context(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_context", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "List Camel routes with their state, uptime, messages 
processed, last error, and throughput statistics.")
     public JsonObject camel_runtime_routes(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_routes", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Get health check status for the Camel application.")
     public JsonObject camel_runtime_health(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_health", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "List all endpoints registered in the Camel context 
with their URIs and usage statistics.")
     public JsonObject camel_runtime_endpoints(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_endpoints", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Show currently in-flight exchanges (messages being 
processed).")
     public JsonObject camel_runtime_inflight(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_inflight", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Show blocked exchanges that are stuck or waiting.")
     public JsonObject camel_runtime_blocked(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_blocked", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Show exchange variables in the Camel context.")
     public JsonObject camel_runtime_variables(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_variables", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Show consumer statistics (polling consumers, 
event-driven consumers).")
     public JsonObject camel_runtime_consumers(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_consumers", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Show configuration properties of the running Camel 
application.")
     public JsonObject camel_runtime_properties(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_properties", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Show services registered in the Camel service 
registry.")
     public JsonObject camel_runtime_services(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_services", nameOrPid, Map.of());
     }
 
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Show JVM memory usage (heap/non-heap), garbage 
collection stats, and thread counts.")
     public JsonObject camel_runtime_memory(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_memory", nameOrPid, Map.of());
     }
 
@@ -194,7 +194,7 @@ public class RuntimeTools {
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Get the source code of routes in the running Camel 
application.")
     public JsonObject camel_runtime_route_source(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Filter source files by name (supports 
wildcards)") String filter) {
         return delegateToRegistry("get_route_source", nameOrPid,
                 Map.of("filter", filter != null ? filter : "*"));
@@ -203,7 +203,7 @@ public class RuntimeTools {
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Dump route definitions in XML, YAML, or Java DSL 
format.")
     public JsonObject camel_runtime_route_dump(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Route ID to dump (use * for all routes)") 
String routeId,
             @ToolArg(description = "Output format: xml, yaml, or java 
(default: yaml)") String format) {
         Map<String, String> args = new HashMap<>();
@@ -215,7 +215,7 @@ public class RuntimeTools {
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Show the route structure as a tree of processors.")
     public JsonObject camel_runtime_route_structure(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Route ID to inspect (use * for all 
routes)") String routeId) {
         return delegateToRegistry("get_route_structure", nameOrPid,
                 Map.of("routeId", routeId != null ? routeId : "*"));
@@ -228,7 +228,7 @@ public class RuntimeTools {
                   Use includeDocs=true to enrich the response with 
documentation from the Camel catalog \
                   for each EIP option and component endpoint option.""")
     public JsonObject camel_runtime_processor_detail(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Route ID to inspect (use * for all 
routes)") String routeId,
             @ToolArg(description = "If true, enrich each processor's options 
with documentation from the Camel catalog") Boolean includeDocs) {
         Map<String, String> args = new HashMap<>();
@@ -242,7 +242,7 @@ public class RuntimeTools {
     @Tool(annotations = @Tool.Annotations(readOnlyHint = false, 
destructiveHint = true, openWorldHint = false),
           description = "Control a route: start, stop, suspend, or resume it.")
     public JsonObject camel_runtime_route_control(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Route ID to control") String routeId,
             @ToolArg(description = "Command: start, stop, suspend, or resume") 
String command) {
         if (routeId == null || routeId.isBlank()) {
@@ -263,10 +263,130 @@ public class RuntimeTools {
         return delegateToRegistry(toolName, nameOrPid, Map.of("routeId", 
routeId));
     }
 
+    // ---- Data, resilience, metrics and analysis (CAMEL-24867: the rest of 
the shared runtime registry) ----
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = false, 
destructiveHint = true, openWorldHint = false),
+          description = """
+                  Execute a SQL statement against a DataSource of the running 
Camel application. \
+                  Returns columns, rows and metadata for a SELECT, or the 
update count for INSERT/UPDATE/DELETE. \
+                  Use it to look at the data a route reads or writes, or to 
try a statement before putting it in a route.""")
+    public JsonObject camel_runtime_sql(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
+            @ToolArg(description = "The SQL statement to execute") String 
query,
+            @ToolArg(description = "Name of the DataSource bean (auto-detected 
if only one exists)",
+                     required = false) String datasource,
+            @ToolArg(description = "Maximum number of rows to return (default 
100)", required = false) String maxRows) {
+        if (query == null || query.isBlank()) {
+            throw new ToolCallException("query is required", null);
+        }
+        Map<String, String> args = new HashMap<>();
+        args.put("query", query);
+        putIfNotBlank(args, "datasource", datasource);
+        putIfNotBlank(args, "maxRows", maxRows);
+        return delegateToRegistry("execute_sql", nameOrPid, args);
+    }
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = """
+                  Get the datasources of the running Camel application with 
their connection pool status: \
+                  active, idle and total connections, max pool size and 
waiting threads (HikariCP and Agroal).""")
+    public JsonObject camel_runtime_datasources(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
+        return delegateToRegistry("get_datasources", nameOrPid, Map.of());
+    }
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = """
+                  Get the traced SQL executions of the camel-sql and 
camel-jdbc components: per statement timing, \
+                  row counts, category (SELECT/INSERT/UPDATE/DELETE), route ID 
and failure status, with summary statistics.""")
+    public JsonObject camel_runtime_sql_trace(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
+        return delegateToRegistry("get_sql_trace", nameOrPid, Map.of());
+    }
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = """
+                  Get the circuit breakers of the running Camel application: 
state (CLOSED/OPEN/HALF_OPEN), \
+                  call counts, failure rates and not-permitted calls 
(Resilience4j and MicroProfile Fault Tolerance).""")
+    public JsonObject camel_runtime_circuit_breakers(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
+        return delegateToRegistry("get_circuit_breakers", nameOrPid, Map.of());
+    }
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = """
+                  Get the Micrometer metrics of the running Camel application: 
counters, gauges, timers and \
+                  distributions. Requires micrometer (run with --observe or 
add camel-micrometer).""")
+    public JsonObject camel_runtime_metrics(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
+        return delegateToRegistry("get_metrics", nameOrPid, Map.of());
+    }
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = """
+                  Aggregate EIP usage across all routes: which processors are 
used, how often, and their \
+                  performance (total exchanges, failures, mean and max 
processing time).""")
+    public JsonObject camel_runtime_eip_stats(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
+        return delegateToRegistry("get_eip_stats", nameOrPid, Map.of());
+    }
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = """
+                  Get the OpenTelemetry spans of the running Camel 
application: trace IDs, span names, durations, \
+                  route IDs and status. Requires tracing (run with 
--observe).""")
+    public JsonObject camel_runtime_spans(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
+            @ToolArg(description = "Maximum number of spans to return (default 
100)", required = false) String limit) {
+        Map<String, String> args = new HashMap<>();
+        putIfNotBlank(args, "limit", limit);
+        return delegateToRegistry("get_spans", nameOrPid, args);
+    }
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = """
+                  Get the startup recorder steps of the running Camel 
application: each step with duration, level \
+                  and type, for diagnosing a slow startup. Requires 
camel.main.startup-recorder=true.""")
+    public JsonObject camel_runtime_startup_steps(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
+        return delegateToRegistry("get_startup_steps", nameOrPid, Map.of());
+    }
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = """
+                  Analyze the routes of the running Camel application for 
anti-patterns and structural issues: \
+                  error handler and dead letter channel configuration, 
complexity (processor count and nesting depth), \
+                  component usage and potential issues, per route.""")
+    public JsonObject camel_runtime_route_analysis(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
+            @ToolArg(description = "Route ID to analyze (* for all routes, the 
default)", required = false) String routeId) {
+        Map<String, String> args = new HashMap<>();
+        putIfNotBlank(args, "routeId", routeId);
+        return delegateToRegistry("get_route_analysis", nameOrPid, args);
+    }
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = """
+                  Compare the running route definitions with the original 
source files, to detect configuration \
+                  drift between what runs and what is deployed.""")
+    public JsonObject camel_runtime_config_drift(
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
+            @ToolArg(description = "Dump format for the comparison: yaml 
(default) or xml", required = false) String format) {
+        Map<String, String> args = new HashMap<>();
+        putIfNotBlank(args, "format", format);
+        return delegateToRegistry("detect_config_drift", nameOrPid, args);
+    }
+
+    private static void putIfNotBlank(Map<String, String> args, String key, 
String value) {
+        if (value != null && !value.isBlank()) {
+            args.put(key, value);
+        }
+    }
+
     @Tool(annotations = @Tool.Annotations(readOnlyHint = false, 
destructiveHint = true, openWorldHint = false),
           description = "Send a test message to a Camel endpoint in the 
running application.")
     public JsonObject camel_runtime_send(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Endpoint URI to send to (e.g., 
direct:myRoute, seda:queue)") String endpoint,
             @ToolArg(description = "Message body to send") String body,
             @ToolArg(description = "Message headers as key=value pairs 
separated by newlines") String headers) {
@@ -287,7 +407,7 @@ public class RuntimeTools {
     @Tool(annotations = @Tool.Annotations(readOnlyHint = false, 
destructiveHint = false, openWorldHint = false),
           description = "Enable, disable, or dump message tracing for the 
running Camel application.")
     public JsonObject camel_runtime_trace(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Action: enable, disable, or dump") String 
action) {
         if (action == null || action.isBlank()) {
             throw new ToolCallException("action is required (enable, disable, 
dump)", null);
@@ -298,7 +418,7 @@ public class RuntimeTools {
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Show top processor statistics: which processors are 
slowest and most active.")
     public JsonObject camel_runtime_top(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_top_processors", nameOrPid, Map.of());
     }
 
@@ -307,7 +427,7 @@ public class RuntimeTools {
                   Get the inter-route topology showing how routes connect to 
each other \
                   and to external endpoints. Returns nodes and edges 
describing the route graph.""")
     public JsonObject camel_runtime_route_topology(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Include live metrics (message counts, 
throughput) on nodes and edges") Boolean metric,
             @ToolArg(description = "Include external systems (databases, 
messaging brokers, etc.) as nodes") Boolean external) {
         Map<String, String> args = new HashMap<>();
@@ -319,7 +439,7 @@ public class RuntimeTools {
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Get a JVM thread dump showing thread names, states, 
and stack traces.")
     public JsonObject camel_runtime_thread_dump(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_thread_dump", nameOrPid, Map.of());
     }
 
@@ -328,7 +448,7 @@ public class RuntimeTools {
                   Get a class-level heap histogram showing instance counts and 
byte usage per class. \
                   Useful for diagnosing memory leaks and understanding which 
classes dominate heap usage.""")
     public JsonObject camel_runtime_heap_histogram(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_heap_histogram", nameOrPid, Map.of());
     }
 
@@ -337,7 +457,7 @@ public class RuntimeTools {
                   Write a heap dump (.hprof) file from a running Camel 
integration for deep memory analysis \
                   with tools like Eclipse MAT, VisualVM, or jhat. The dump is 
written to the process working directory.""")
     public JsonObject camel_runtime_heap_dump(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "File name for the heap dump (without 
.hprof extension). Defaults to heap-dump-<timestamp>") String name,
             @ToolArg(description = "Whether to dump only live objects (default 
true). Live dumps trigger a GC first") String live) {
         RuntimeService.ProcessInfo p = 
runtimeService.findSingleProcess(nameOrPid);
@@ -365,7 +485,7 @@ public class RuntimeTools {
                   Entries with lowConfidence=true have unreliable growth 
percentages due to low sample counts or \
                   sample counts that diverge significantly between runs — 
recommend a longer recording duration.""")
     public JsonObject camel_runtime_memory_leak(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Command: start, stop, status, or query") 
String command,
             @ToolArg(description = "Recording duration in seconds (only for 
start command, default 60, use 0 for manual stop)") String duration,
             @ToolArg(description = "Recording mode: dual (default, two 
recordings at Xs and 2Xs with trend comparison) or single (one recording)") 
String mode,
@@ -501,7 +621,7 @@ public class RuntimeTools {
                   This is always captured (no need to enable tracing) and 
shows the single most recent exchange \
                   with its route path, processors visited, headers, body, and 
timing.""")
     public JsonObject camel_runtime_history(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid) {
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid) {
         return delegateToRegistry("get_history", nameOrPid, Map.of());
     }
 
@@ -510,7 +630,7 @@ public class RuntimeTools {
                   Receive (poll) a message from a Camel endpoint in the 
running application. \
                   This is the complement to camel_runtime_send — it consumes 
one message from the endpoint.""")
     public JsonObject camel_runtime_receive(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Endpoint URI to receive from") String 
endpoint) {
         if (endpoint == null || endpoint.isBlank()) {
             throw new ToolCallException("endpoint is required", null);
@@ -526,7 +646,7 @@ public class RuntimeTools {
     @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
           description = "Browse messages in a Camel endpoint (e.g., browse 
messages queued in a SEDA endpoint).")
     public JsonObject camel_runtime_browse(
-            @ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
+            @ToolArg(description = NAME_OR_PID_DESC, required = false) String 
nameOrPid,
             @ToolArg(description = "Endpoint URI to browse") String endpoint,
             @ToolArg(description = "Maximum number of messages to return 
(default: 50)") Integer limit) {
         if (endpoint == null || endpoint.isBlank()) {
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RuntimeToolsTest.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RuntimeToolsTest.java
index 74feb4d32e19..851060c78f88 100644
--- 
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RuntimeToolsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RuntimeToolsTest.java
@@ -19,6 +19,7 @@ package org.apache.camel.dsl.jbang.core.commands.mcp;
 import java.util.List;
 
 import io.quarkiverse.mcp.server.ToolCallException;
+import org.apache.camel.dsl.jbang.core.commands.ai.ToolRegistry;
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -66,6 +67,23 @@ class RuntimeToolsTest {
                 .hasMessageContaining("command is required");
     }
 
+    @Test
+    void sqlRequiresQuery() {
+        RuntimeTools tools = createTools();
+        assertThatThrownBy(() -> tools.camel_runtime_sql(null, null, null, 
null))
+                .isInstanceOf(ToolCallException.class)
+                .hasMessageContaining("query is required");
+    }
+
+    @Test
+    void theNewWrappersDelegateToRegistryTools() {
+        // CAMEL-24867: every wrapper names a tool the shared registry has, so 
a typo cannot hide until runtime
+        for (String name : List.of("execute_sql", "get_datasources", 
"get_sql_trace", "get_circuit_breakers", "get_metrics",
+                "get_eip_stats", "get_spans", "get_startup_steps", 
"get_route_analysis", "detect_config_drift")) {
+            assertThat(ToolRegistry.findTool(name)).as(name).isNotNull();
+        }
+    }
+
     @Test
     void sendRequiresEndpoint() {
         RuntimeTools tools = createTools();

Reply via email to