This is an automated email from the ASF dual-hosted git repository.
Croway 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 5cf327be365d camel-jbang-mcp - tool arguments documented as optional
are optional, a non-Camel platformBom is ignored for the main runtime (#27511)
5cf327be365d is described below
commit 5cf327be365d37d7baae82c8bf160bb9f25aafb3
Author: Federico Mariani <[email protected]>
AuthorDate: Thu Oct 8 09:01:54 2026 +0200
camel-jbang-mcp - tool arguments documented as optional are optional, a
non-Camel platformBom is ignored for the main runtime (#27511)
* camel-jbang-mcp - tool arguments documented as optional are optional, a
non-Camel platformBom is ignored for the main runtime
Tool arguments whose description says they are optional or have a default
were still declared required, so the
input schema forced an assistant to invent a value for each of them.
Declare them optional (42 arguments, each
checked to be handled when absent by the tool). camel_runtime_memory_leak
now records in dual mode when mode is
omitted, as documented.
With the main runtime, a platformBom that is not an org.apache.camel GAV (a
Spring Boot or Quarkus platform BOM,
"none", a value that is not a GAV) does not select a Camel version: it is
ignored instead of failing the call.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* camel-jbang-mcp - more tool arguments the tools handle when absent are
optional
Review follow-up: arguments the tool already handles when absent (a null
check with a default, or no filtering) but
still declared required (22): documentProcessor and documentSource of
camel_ai_pipeline_scaffold, filter and type of
camel_catalog_kamelets, duration and minSize of camel_runtime_memory_leak,
width and ignoreLoadingError of
camel_render_route_diagram, routes of the dependency tools, javaVersion of
the migration tools, routeId of the route
dump, structure and processor detail tools (all routes), body and headers
of camel_runtime_send, the boolean flags
of the topology and processor detail tools, and fromVersion of
camel_version_list.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
---
.../dsl/jbang/core/commands/mcp/AdvisoryTools.java | 8 ++--
.../core/commands/mcp/AiPipelineScaffoldTools.java | 12 ++++--
.../dsl/jbang/core/commands/mcp/AiTraceTools.java | 3 +-
.../jbang/core/commands/mcp/CatalogService.java | 12 ++++++
.../core/commands/mcp/DependencyCheckTools.java | 6 ++-
.../commands/mcp/DependencySecurityAuditTools.java | 6 ++-
.../dsl/jbang/core/commands/mcp/ExplainTools.java | 2 +-
.../dsl/jbang/core/commands/mcp/HardenTools.java | 2 +-
.../dsl/jbang/core/commands/mcp/KameletTools.java | 13 +++---
.../jbang/core/commands/mcp/MigrationTools.java | 12 +++---
.../commands/mcp/MigrationWildflyKarafTools.java | 6 ++-
.../dsl/jbang/core/commands/mcp/OpenApiTools.java | 9 ++--
.../core/commands/mcp/RouteCostEstimateTools.java | 12 ++++--
.../jbang/core/commands/mcp/RouteDiagramTools.java | 22 ++++++----
.../dsl/jbang/core/commands/mcp/RuntimeTools.java | 48 ++++++++++++++--------
.../jbang/core/commands/mcp/SecurityScanTools.java | 2 +-
.../jbang/core/commands/mcp/TestScaffoldTools.java | 4 +-
.../dsl/jbang/core/commands/mcp/VersionTools.java | 6 +--
.../core/commands/mcp/CatalogServiceTest.java | 31 +++++++++++++-
19 files changed, 149 insertions(+), 67 deletions(-)
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AdvisoryTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AdvisoryTools.java
index 1fd76914592c..5c8ca4127954 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AdvisoryTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AdvisoryTools.java
@@ -50,12 +50,14 @@ public class AdvisoryTools {
+ "advisories published after this Camel version was
released are not included - check the "
+ "web page for the very latest.")
public AdvisoriesResult camel_security_advisories(
- @ToolArg(description = "Camel version to check, e.g. 4.10.1
(optional)") String camelVersion,
+ @ToolArg(description = "Camel version to check, e.g. 4.10.1
(optional)", required = false) String camelVersion,
@ToolArg(description = "Component to filter by, e.g. kafka or
camel-kafka (optional; best-effort match "
+ "against components named in the advisory
text - older advisories may not name "
- + "components)") String component,
+ + "components)",
+ required = false) String component,
@ToolArg(description = "Severity to filter by: LOW, MEDIUM, HIGH,
or CRITICAL "
- + "(optional)") String severity) {
+ + "(optional)",
+ required = false) String severity) {
try {
List<SecurityAdvisoryModel> advisories =
advisoryService.advisories();
List<AdvisoryService.AdvisoryView> matches
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AiPipelineScaffoldTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AiPipelineScaffoldTools.java
index 18de55b1206f..e88da86a6990 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AiPipelineScaffoldTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AiPipelineScaffoldTools.java
@@ -42,14 +42,18 @@ public class AiPipelineScaffoldTools {
public ScaffoldResult camel_ai_pipeline_scaffold(
@ToolArg(description = "Pipeline type: summarization, extraction,
rag, or classification") String pipelineType,
@ToolArg(description = "Document processor: docling (open-source,
default), textract (AWS), "
- + "or combined (Docling for text + Textract
for tables)") String documentProcessor,
+ + "or combined (Docling for text + Textract
for tables)",
+ required = false) String documentProcessor,
@ToolArg(description = "Document source: file (local path,
default), s3 (AWS S3 bucket), "
- + "or url (HTTP/HTTPS URL)") String
documentSource,
+ + "or url (HTTP/HTTPS URL)",
+ required = false) String documentSource,
@ToolArg(description = "Bedrock model ID (default: Claude Sonnet
4). "
+ "Examples:
anthropic.claude-sonnet-4-20250514-v1:0, "
+ "anthropic.claude-opus-4-20250514-v1:0, "
- + "amazon.nova-pro-v1:0") String modelId,
- @ToolArg(description = "AWS region for Bedrock and Textract
(default: us-east-1)") String region) {
+ + "amazon.nova-pro-v1:0",
+ required = false) String modelId,
+ @ToolArg(description = "AWS region for Bedrock and Textract
(default: us-east-1)",
+ required = false) String region) {
if (pipelineType == null || pipelineType.isBlank()) {
throw new ToolCallException(
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AiTraceTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AiTraceTools.java
index 522a1cd574c0..000f7bea18ef 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AiTraceTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/AiTraceTools.java
@@ -75,7 +75,8 @@ public class AiTraceTools {
+ "Combines message history with processor statistics
filtered to AI steps.")
public AiTraceResult camel_runtime_ai_trace(
@ToolArg(description = NAME_OR_PID_DESC) String nameOrPid,
- @ToolArg(description = "Route ID filter (exact match or * for all,
default: *)") String routeFilter) {
+ @ToolArg(description = "Route ID filter (exact match or * for all,
default: *)",
+ required = false) String routeFilter) {
RuntimeService.ProcessInfo p =
runtimeService.findSingleProcess(nameOrPid);
ToolContext ctx = new ToolContext();
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogService.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogService.java
index f148c4f76312..38e592f8dd09 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogService.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogService.java
@@ -88,6 +88,12 @@ public class CatalogService {
hasVersion = false;
}
boolean hasBom = platformBom != null && !platformBom.isBlank();
+ if (hasBom && runtimeType == RuntimeType.main &&
!isCamelGav(platformBom)) {
+ // with the main runtime only a Camel artifact
(org.apache.camel:camel-bom:<version>) selects a version: a
+ // Spring Boot or Quarkus platform BOM, or a value that is not a
GAV ("none", "n/a"), does not apply to main
+ // and is ignored rather than failing the call; the answer reports
the catalog version it used
+ hasBom = false;
+ }
// No version-specific parameters and main runtime -> default catalog
if (!hasVersion && !hasBom && runtimeType == RuntimeType.main) {
@@ -143,6 +149,12 @@ public class CatalogService {
return cache.get(key);
}
+ /** Whether the value is an org.apache.camel groupId:artifactId:version
GAV. */
+ static boolean isCamelGav(String gav) {
+ String[] parts = gav.trim().split(":");
+ return parts.length == 3 && "org.apache.camel".equals(parts[0].trim())
&& !parts[1].isBlank() && !parts[2].isBlank();
+ }
+
/** Whether the version is the default catalog's, with or without a
-SNAPSHOT qualifier. */
boolean sameAsDefault(String camelVersion) {
String mine = defaultCatalog.getCatalogVersion();
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencyCheckTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencyCheckTools.java
index a7fe216bf01d..1622dbb21c45 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencyCheckTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencyCheckTools.java
@@ -60,11 +60,13 @@ public class DependencyCheckTools {
+ "IMPORTANT: Avoid including sensitive
data such as passwords, tokens, or API keys. "
+ "Sensitive content is automatically
detected and masked.") String pomContent,
@ToolArg(description = "Route definitions (YAML, XML, or Java DSL)
to check for missing component dependencies. "
- + "Multiple routes can be provided
concatenated.") String routes,
+ + "Multiple routes can be provided
concatenated.",
+ required = false) String routes,
@ToolArg(description = ToolArgDocs.RUNTIME, required = false)
String runtime,
@ToolArg(description = ToolArgDocs.CAMEL_VERSION, required =
false) String camelVersion,
@ToolArg(description = ToolArgDocs.PLATFORM_BOM, required = false)
String platformBom,
- @ToolArg(description = "If true (default), automatically sanitize
POM content by masking credentials") Boolean sanitizePom) {
+ @ToolArg(description = "If true (default), automatically sanitize
POM content by masking credentials",
+ required = false) Boolean sanitizePom) {
if (pomContent == null || pomContent.isBlank()) {
throw new ToolCallException("pomContent is required", null);
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencySecurityAuditTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencySecurityAuditTools.java
index 05b5cf2a6217..f204062d963f 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencySecurityAuditTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencySecurityAuditTools.java
@@ -57,11 +57,13 @@ public class DependencySecurityAuditTools {
public AuditResult camel_dependency_security_audit(
@ToolArg(description = "The pom.xml file content") String
pomContent,
@ToolArg(description = "Route definitions (YAML, XML, or Java DSL)
to determine which components "
- + "are actually used (for reachability
analysis)") String routes,
+ + "are actually used (for reachability
analysis)",
+ required = false) String routes,
@ToolArg(description = ToolArgDocs.RUNTIME, required = false)
String runtime,
@ToolArg(description = ToolArgDocs.CAMEL_VERSION, required =
false) String camelVersion,
@ToolArg(description = ToolArgDocs.PLATFORM_BOM, required = false)
String platformBom,
- @ToolArg(description = "If true (default), mask credentials in POM
content") Boolean sanitizePom) {
+ @ToolArg(description = "If true (default), mask credentials in POM
content",
+ required = false) Boolean sanitizePom) {
if (pomContent == null || pomContent.isBlank()) {
throw new ToolCallException("pomContent is required", null);
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ExplainTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ExplainTools.java
index 57a7c75c452a..fc7c3584a9a7 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ExplainTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ExplainTools.java
@@ -52,7 +52,7 @@ public class ExplainTools {
"Use this context to understand and explain the
route.")
public RouteContextResult camel_route_context(
@ToolArg(description = "The Camel route content (YAML, XML, or
Java DSL)") String route,
- @ToolArg(description = "Route format: yaml, xml, or java (default:
yaml)") String format,
+ @ToolArg(description = "Route format: yaml, xml, or java (default:
yaml)", required = false) String format,
@ToolArg(description = ToolArgDocs.RUNTIME, required = false)
String runtime,
@ToolArg(description = ToolArgDocs.CAMEL_VERSION, required =
false) String camelVersion,
@ToolArg(description = ToolArgDocs.PLATFORM_BOM, required = false)
String platformBom) {
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/HardenTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/HardenTools.java
index 9b178b0d78cc..e2ba938a7666 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/HardenTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/HardenTools.java
@@ -67,7 +67,7 @@ public class HardenTools {
"Use this context to provide security hardening
recommendations for the route.")
public HardenContextResult camel_route_harden_context(
@ToolArg(description = "The Camel route content (YAML, XML, or
Java DSL)") String route,
- @ToolArg(description = "Route format: yaml, xml, or java (default:
yaml)") String format,
+ @ToolArg(description = "Route format: yaml, xml, or java (default:
yaml)", required = false) String format,
@ToolArg(description = ToolArgDocs.RUNTIME, required = false)
String runtime,
@ToolArg(description = ToolArgDocs.CAMEL_VERSION, required =
false) String camelVersion,
@ToolArg(description = ToolArgDocs.PLATFORM_BOM, required = false)
String platformBom) {
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java
index 3167220bf593..43000d02a0b5 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/KameletTools.java
@@ -46,10 +46,12 @@ public class KameletTools {
"Returns kamelet name, type (source, sink, action),
support level, and description. " +
"Use filter to search by name or description, type to
filter by category.")
public KameletListResult camel_catalog_kamelets(
- @ToolArg(description = "Filter kamelets by name or description
(case-insensitive substring match)") String filter,
- @ToolArg(description = "Filter by type: source, sink, or action")
String type,
- @ToolArg(description = "Maximum number of results to return
(default: 50)") Integer limit,
- @ToolArg(description = "Apache Camel Kamelets version. If not
specified, uses the default version.") String kameletsVersion) {
+ @ToolArg(description = "Filter kamelets by name or description
(case-insensitive substring match)",
+ required = false) String filter,
+ @ToolArg(description = "Filter by type: source, sink, or action",
required = false) String type,
+ @ToolArg(description = "Maximum number of results to return
(default: 50)", required = false) Integer limit,
+ @ToolArg(description = "Apache Camel Kamelets version. If not
specified, uses the default version.",
+ required = false) String kameletsVersion) {
int maxResults = limit != null ? limit : 50;
@@ -104,7 +106,8 @@ public class KameletTools {
+ "dependencies, and usage information.")
public KameletDetailResult camel_catalog_kamelet_doc(
@ToolArg(description = "Kamelet name (e.g., aws-s3-source,
kafka-sink, log-action)") String kamelet,
- @ToolArg(description = "Apache Camel Kamelets version. If not
specified, uses the default version.") String kameletsVersion) {
+ @ToolArg(description = "Apache Camel Kamelets version. If not
specified, uses the default version.",
+ required = false) String kameletsVersion) {
if (kamelet == null || kamelet.isBlank()) {
throw new ToolCallException("Kamelet name is required", null);
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
index 23b1ec5365fb..eb4b15e933d6 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationTools.java
@@ -58,7 +58,8 @@ public class MigrationTools {
@ToolArg(description = "The pom.xml file content. "
+ "IMPORTANT: Avoid including sensitive
data such as passwords, tokens, or API keys. "
+ "Sensitive content is automatically
detected and masked.") String pomContent,
- @ToolArg(description = "If true (default), automatically sanitize
POM content by masking credentials") Boolean sanitizePom) {
+ @ToolArg(description = "If true (default), automatically sanitize
POM content by masking credentials",
+ required = false) Boolean sanitizePom) {
if (pomContent == null || pomContent.isBlank()) {
throw new ToolCallException("pomContent is required", null);
@@ -114,7 +115,7 @@ public class MigrationTools {
@ToolArg(description = "Current Camel version (e.g., 3.20.0)")
String currentVersion,
@ToolArg(description = "Target Camel version (e.g., 4.18.0)")
String targetVersion,
@ToolArg(description = ToolArgDocs.RUNTIME_REQUIRED) String
runtime,
- @ToolArg(description = "Current Java version (e.g., 11, 17, 21)")
String javaVersion) {
+ @ToolArg(description = "Current Java version (e.g., 11, 17, 21)",
required = false) String javaVersion) {
if (camelComponents == null || camelComponents.isBlank()) {
throw new ToolCallException("camelComponents is required", null);
@@ -214,8 +215,9 @@ public class MigrationTools {
@ToolArg(description = ToolArgDocs.RUNTIME_REQUIRED) String
runtime,
@ToolArg(description = "Current Camel version (e.g., 4.4.0)")
String currentVersion,
@ToolArg(description = "Target Camel version (e.g., 4.18.0)")
String targetVersion,
- @ToolArg(description = "Current Java version (e.g., 11, 17)")
String javaVersion,
- @ToolArg(description = "If true, perform a dry run without making
changes (default: true)") Boolean dryRun) {
+ @ToolArg(description = "Current Java version (e.g., 11, 17)",
required = false) String javaVersion,
+ @ToolArg(description = "If true, perform a dry run without making
changes (default: true)",
+ required = false) Boolean dryRun) {
if (runtime == null || runtime.isBlank()) {
throw new ToolCallException("runtime is required", null);
@@ -298,7 +300,7 @@ public class MigrationTools {
public GuideSearchResult camel_migration_guide_search(
@ToolArg(description = "Search query — component name, API class,
method, or keyword "
+ "(e.g., direct-vm, getOut, camel-http4,
ExchangePattern)") String query,
- @ToolArg(description = "Maximum number of results to return
(default: 3)") Integer limit) {
+ @ToolArg(description = "Maximum number of results to return
(default: 3)", required = false) Integer limit) {
if (query == null || query.isBlank()) {
throw new ToolCallException("query is required", null);
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationWildflyKarafTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationWildflyKarafTools.java
index 5d11a943f7be..3d1c0fd29b08 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationWildflyKarafTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/MigrationWildflyKarafTools.java
@@ -57,9 +57,11 @@ public class MigrationWildflyKarafTools {
@ToolArg(description = "The pom.xml file content of the
WildFly/Karaf project. "
+ "IMPORTANT: Avoid including sensitive
data such as passwords, tokens, or API keys. "
+ "Sensitive content is automatically
detected and masked.") String pomContent,
- @ToolArg(description = "Target runtime: spring-boot or quarkus
(default: quarkus)") String targetRuntime,
+ @ToolArg(description = "Target runtime: spring-boot or quarkus
(default: quarkus)",
+ required = false) String targetRuntime,
@ToolArg(description = "Target Camel version (e.g., 4.18.0)")
String targetVersion,
- @ToolArg(description = "If true (default), automatically sanitize
POM content by masking credentials") Boolean sanitizePom) {
+ @ToolArg(description = "If true (default), automatically sanitize
POM content by masking credentials",
+ required = false) Boolean sanitizePom) {
if (pomContent == null || pomContent.isBlank()) {
throw new ToolCallException("pomContent is required", null);
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/OpenApiTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/OpenApiTools.java
index 6a84882c8625..71505833a632 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/OpenApiTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/OpenApiTools.java
@@ -136,10 +136,12 @@ public class OpenApiTools {
public ScaffoldResult camel_openapi_scaffold(
@ToolArg(description = "OpenAPI 3.x specification content (JSON or
YAML string)") String spec,
@ToolArg(description = "Filename of the OpenAPI spec file as it
will be referenced at runtime "
- + "(default: 'openapi.json')") String
specFilename,
+ + "(default: 'openapi.json')",
+ required = false) String specFilename,
@ToolArg(description = "Behavior when a route is missing for an
operationId: "
+ "'fail' (default, throw error), 'ignore'
(skip silently), "
- + "or 'mock' (return mock responses)")
String missingOperation) {
+ + "or 'mock' (return mock responses)",
+ required = false) String missingOperation) {
OpenAPI openAPI = parseSpec(spec);
@@ -207,7 +209,8 @@ public class OpenApiTools {
public MockGuidanceResult camel_openapi_mock_guidance(
@ToolArg(description = "OpenAPI 3.x specification content (JSON or
YAML string)") String spec,
@ToolArg(description = "The missingOperation mode to get guidance
for: "
- + "'mock' (default), 'fail', or 'ignore'")
String mode) {
+ + "'mock' (default), 'fail', or 'ignore'",
+ required = false) String mode) {
OpenAPI openAPI = parseSpec(spec);
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateTools.java
index 57e5fd519e3a..65652b8c48e9 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateTools.java
@@ -64,10 +64,14 @@ public class RouteCostEstimateTools {
+ "Cost data is approximate based on published AWS
pricing (2025-Q2).")
public CostEstimateResult camel_route_cost_estimate(
@ToolArg(description = "The Camel route definition (YAML or XML)")
String route,
- @ToolArg(description = "Expected messages per hour for cost
projection (default: 100)") Integer messagesPerHour,
- @ToolArg(description = "Average document pages per message for
Textract/Docling (default: 5)") Integer avgPages,
- @ToolArg(description = "Average LLM input tokens per request
(default: 1000)") Integer avgInputTokens,
- @ToolArg(description = "Average LLM output tokens per request
(default: 500)") Integer avgOutputTokens) {
+ @ToolArg(description = "Expected messages per hour for cost
projection (default: 100)",
+ required = false) Integer messagesPerHour,
+ @ToolArg(description = "Average document pages per message for
Textract/Docling (default: 5)",
+ required = false) Integer avgPages,
+ @ToolArg(description = "Average LLM input tokens per request
(default: 1000)",
+ required = false) Integer avgInputTokens,
+ @ToolArg(description = "Average LLM output tokens per request
(default: 500)",
+ required = false) Integer avgOutputTokens) {
if (route == null || route.isBlank()) {
throw new ToolCallException("Route content is required", null);
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 e7a5bd920ab6..9d4e5a56491d 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
@@ -50,19 +50,25 @@ public class RouteDiagramTools {
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 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,
+ + "file is written. If not specified, a
temporary file is created.",
+ required = false) 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,
+ + "Use 'ascii' or 'unicode' to get a text
diagram that can be read directly.",
+ required = false) 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
(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,
+ + "matches the given pattern (supports
wildcards)",
+ required = false) String filter,
+ @ToolArg(description = "Image width in pixels; 0 (or unset) = auto
(only used for image themes)",
+ required = false) Integer width,
+ @ToolArg(description = "Font size in logical pixels for node text
(default 12)", required = false) Integer fontSize,
+ @ToolArg(description = "Node box width in logical pixels (default
180)", required = false) Integer boxWidth,
@ToolArg(description = "What text to display in diagram nodes:
'code' (default), 'description' (prefer "
- + "description over code if available), or
'both' (show description and code)") String nodeLabel,
- @ToolArg(description = "Whether to ignore route loading and
compilation errors (use with care)") Boolean ignoreLoadingError) {
+ + "description over code if available), or
'both' (show description and code)",
+ required = false) String nodeLabel,
+ @ToolArg(description = "Whether to ignore route loading and
compilation errors (use with care)",
+ required = false) Boolean ignoreLoadingError) {
if (sourceFile == null || sourceFile.isBlank()) {
throw new ToolCallException("'sourceFile' parameter is required",
null);
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 f379b2165651..35afe7ebd77c 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
@@ -195,7 +195,7 @@ public class RuntimeTools {
description = "Get the source code of routes in the running Camel
application.")
public JsonObject camel_runtime_route_source(
@ToolArg(description = NAME_OR_PID_DESC, required = false) String
nameOrPid,
- @ToolArg(description = "Filter source files by name (supports
wildcards)") String filter) {
+ @ToolArg(description = "Filter source files by name (supports
wildcards)", required = false) String filter) {
return delegateToRegistry("get_route_source", nameOrPid,
Map.of("filter", filter != null ? filter : "*"));
}
@@ -204,8 +204,8 @@ public class RuntimeTools {
description = "Dump route definitions in XML, YAML, or Java DSL
format.")
public JsonObject camel_runtime_route_dump(
@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) {
+ @ToolArg(description = "Route ID to dump (use * for all routes)",
required = false) String routeId,
+ @ToolArg(description = "Output format: xml, yaml, or java
(default: yaml)", required = false) String format) {
Map<String, String> args = new HashMap<>();
args.put("routeId", routeId != null ? routeId : "*");
args.put("format", format != null ? format : "yaml");
@@ -216,7 +216,7 @@ public class RuntimeTools {
description = "Show the route structure as a tree of processors.")
public JsonObject camel_runtime_route_structure(
@ToolArg(description = NAME_OR_PID_DESC, required = false) String
nameOrPid,
- @ToolArg(description = "Route ID to inspect (use * for all
routes)") String routeId) {
+ @ToolArg(description = "Route ID to inspect (use * for all
routes)", required = false) String routeId) {
return delegateToRegistry("get_route_structure", nameOrPid,
Map.of("routeId", routeId != null ? routeId : "*"));
}
@@ -229,8 +229,9 @@ public class RuntimeTools {
for each EIP option and component endpoint option.""")
public JsonObject camel_runtime_processor_detail(
@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) {
+ @ToolArg(description = "Route ID to inspect (use * for all
routes)", required = false) String routeId,
+ @ToolArg(description = "If true, enrich each processor's options
with documentation from the Camel catalog",
+ required = false) Boolean includeDocs) {
Map<String, String> args = new HashMap<>();
args.put("routeId", routeId != null ? routeId : "*");
if (includeDocs != null && includeDocs) {
@@ -441,8 +442,9 @@ public class RuntimeTools {
public JsonObject camel_runtime_send(
@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) {
+ @ToolArg(description = "Message body to send", required = false)
String body,
+ @ToolArg(description = "Message headers as key=value pairs
separated by newlines",
+ required = false) String headers) {
if (endpoint == null || endpoint.isBlank()) {
throw new ToolCallException("endpoint is required", null);
}
@@ -481,8 +483,10 @@ public class RuntimeTools {
and to external endpoints. Returns nodes and edges
describing the route graph.""")
public JsonObject camel_runtime_route_topology(
@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) {
+ @ToolArg(description = "Include live metrics (message counts,
throughput) on nodes and edges",
+ required = false) Boolean metric,
+ @ToolArg(description = "Include external systems (databases,
messaging brokers, etc.) as nodes",
+ required = false) Boolean external) {
Map<String, String> args = new HashMap<>();
args.put("metric", metric == null || metric ? "true" : "false");
args.put("external", external == null || external ? "true" : "false");
@@ -511,8 +515,10 @@ public class RuntimeTools {
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, 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) {
+ @ToolArg(description = "File name for the heap dump (without
.hprof extension). Defaults to heap-dump-<timestamp>",
+ required = false) String name,
+ @ToolArg(description = "Whether to dump only live objects (default
true). Live dumps trigger a GC first",
+ required = false) String live) {
RuntimeService.ProcessInfo p =
runtimeService.findSingleProcess(nameOrPid);
return runtimeService.executeAction(p.pid(), "heap-dump", root -> {
if (name != null && !name.isBlank()) {
@@ -540,16 +546,22 @@ public class RuntimeTools {
public JsonObject camel_runtime_memory_leak(
@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,
- @ToolArg(description = "Include allocation stack traces in results
(default false, set true for detailed analysis)") String stacktrace,
- @ToolArg(description = "Minimum total size in bytes to include a
sample (e.g. 1024 for 1KB). Filters out small allocations to reduce noise.
Default 1024 (1KB) in dual mode") String minSize) {
+ @ToolArg(description = "Recording duration in seconds (only for
start command, default 60, use 0 for manual stop)",
+ required = false) String duration,
+ @ToolArg(description = "Recording mode: dual (default, two
recordings at Xs and 2Xs with trend comparison) or single (one recording)",
+ required = false) String mode,
+ @ToolArg(description = "Include allocation stack traces in results
(default false, set true for detailed analysis)",
+ required = false) String stacktrace,
+ @ToolArg(description = "Minimum total size in bytes to include a
sample (e.g. 1024 for 1KB). Filters out small allocations to reduce noise.
Default 1024 (1KB) in dual mode",
+ required = false) String minSize) {
if (command == null || command.isBlank()) {
throw new ToolCallException("command is required (start, stop,
status, or query)", null);
}
RuntimeService.ProcessInfo p =
runtimeService.findSingleProcess(nameOrPid);
- if ("start".equals(command) && "dual".equalsIgnoreCase(mode)) {
+ // dual is the documented default: an omitted or blank mode records
twice too
+ boolean dual = mode == null || mode.isBlank() ||
"dual".equalsIgnoreCase(mode);
+ if ("start".equals(command) && dual) {
return doDualJfrRecording(p.pid(), duration, stacktrace, minSize);
}
@@ -701,7 +713,7 @@ public class RuntimeTools {
public JsonObject camel_runtime_browse(
@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) {
+ @ToolArg(description = "Maximum number of messages to return
(default: 50)", required = false) Integer limit) {
if (endpoint == null || endpoint.isBlank()) {
throw new ToolCallException("endpoint is required", null);
}
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanTools.java
index ca872b096ca0..8c720d85c957 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanTools.java
@@ -64,7 +64,7 @@ public class SecurityScanTools {
+ "and CVE advisories.")
public SecurityScanResult camel_security_scan(
@ToolArg(description = "The Camel route content (YAML, XML, or
Java DSL)") String route,
- @ToolArg(description = "Route format: yaml, xml, or java (default:
yaml)") String format) {
+ @ToolArg(description = "Route format: yaml, xml, or java (default:
yaml)", required = false) String format) {
if (route == null || route.isBlank()) {
throw new ToolCallException("Route content is required", null);
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldTools.java
index ad0b078da2f8..af5620e544fc 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldTools.java
@@ -81,8 +81,8 @@ public class TestScaffoldTools {
+ "and @RegisterExtension stubs for infrastructure
components (Kafka, AWS, etc.).")
public String camel_route_test_scaffold(
@ToolArg(description = "The Camel route definition (YAML or XML)")
String route,
- @ToolArg(description = "Route format: yaml or xml (default:
yaml)") String format,
- @ToolArg(description = "Target runtime: main or spring-boot
(default: main)") String runtime,
+ @ToolArg(description = "Route format: yaml or xml (default:
yaml)", required = false) String format,
+ @ToolArg(description = "Target runtime: main or spring-boot
(default: main)", required = false) String runtime,
@ToolArg(description = ToolArgDocs.CAMEL_VERSION, required =
false) String camelVersion,
@ToolArg(description = ToolArgDocs.PLATFORM_BOM, required = false)
String platformBom) {
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/VersionTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/VersionTools.java
index 39aa96e8f2e1..503014445f1b 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/VersionTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/VersionTools.java
@@ -47,9 +47,9 @@ public class VersionTools {
"Returns version information including release date,
JDK requirements, and LTS status.")
public VersionListResult camel_version_list(
@ToolArg(description = ToolArgDocs.RUNTIME, required = false)
String runtime,
- @ToolArg(description = "Only show LTS (Long Term Support) releases
(default: false)") Boolean lts,
- @ToolArg(description = "Minimum Camel version to include (e.g.,
4.0)") String fromVersion,
- @ToolArg(description = "Maximum number of versions to return
(default: 10)") Integer limit) {
+ @ToolArg(description = "Only show LTS (Long Term Support) releases
(default: false)", required = false) Boolean lts,
+ @ToolArg(description = "Minimum Camel version to include (e.g.,
4.0)", required = false) String fromVersion,
+ @ToolArg(description = "Maximum number of versions to return
(default: 10)", required = false) Integer limit) {
try {
StringPrinter printer = new StringPrinter();
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogServiceTest.java
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogServiceTest.java
index 304e00e1ddbf..e5065610abd7 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogServiceTest.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/CatalogServiceTest.java
@@ -78,7 +78,7 @@ class CatalogServiceTest {
void platformBomInvalidFormatThrows() {
CatalogService service = createService(null);
- assertThatThrownBy(() -> service.loadCatalog(null, null,
"invalid-format"))
+ assertThatThrownBy(() -> service.loadCatalog("spring-boot", null,
"invalid-format"))
.isInstanceOf(ToolCallException.class)
.hasMessageContaining("GAV format");
}
@@ -87,11 +87,38 @@ class CatalogServiceTest {
void platformBomInvalidFormatTwoPartsThrows() {
CatalogService service = createService(null);
- assertThatThrownBy(() -> service.loadCatalog(null, null,
"group:artifact"))
+ assertThatThrownBy(() -> service.loadCatalog("spring-boot", null,
"group:artifact"))
.isInstanceOf(ToolCallException.class)
.hasMessageContaining("GAV format");
}
+ @Test
+ void platformBomThatIsNotAGavIsIgnoredForMain() {
+ CatalogService service = createService(null);
+
+ assertThat(version(service, null, null,
"invalid-format")).isEqualTo(BUILTIN_VERSION);
+ assertThat(version(service, "main", null,
"none")).isEqualTo(BUILTIN_VERSION);
+ assertThat(version(service, "main", null,
"group:artifact")).isEqualTo(BUILTIN_VERSION);
+ }
+
+ @Test
+ void platformBomOfAnotherRuntimeIsIgnoredForMain() {
+ CatalogService service = createService(null);
+
+ assertThat(version(service, "main", null,
"io.quarkus.platform:quarkus-camel-bom:3.31.3")).isEqualTo(BUILTIN_VERSION);
+ assertThat(version(service, "main", BUILTIN_VERSION,
"org.springframework.boot:spring-boot-dependencies:3.5.0"))
+ .isEqualTo(BUILTIN_VERSION);
+ }
+
+ @Test
+ void camelGav() {
+
assertThat(CatalogService.isCamelGav("org.apache.camel:camel-bom:4.22.1")).isTrue();
+ assertThat(CatalogService.isCamelGav("
org.apache.camel:camel-catalog:4.22.1 ")).isTrue();
+
assertThat(CatalogService.isCamelGav("io.quarkus.platform:quarkus-camel-bom:3.31.3")).isFalse();
+
assertThat(CatalogService.isCamelGav("org.apache.camel:camel-bom")).isFalse();
+ assertThat(CatalogService.isCamelGav("none")).isFalse();
+ }
+
@Test
void platformBomEmptyOrBlankIsTheDefaultCatalog() {
CatalogService service = createService(null);