Federico Mariani created CAMEL-25642:
----------------------------------------
Summary: camel-jbang-mcp - defects in the tools outside the
catalog path, found in a code review: runtime wiring (receive, routeId,
prompts), migration recipe data, OpenAPI scaffold
Key: CAMEL-25642
URL: https://issues.apache.org/jira/browse/CAMEL-25642
Project: Camel
Issue Type: Bug
Components: camel-jbang-mcp
Reporter: Federico Mariani
Umbrella for what a code review of all 86 tools (October 2026, main
4.23.0-SNAPSHOT) found in tools that no session of the coding-agent evaluation
ever called, so none of it has eval evidence; everything below was verified by
reading the code. Three independent PRs, one per section; the full per-tool
review with file:line anchors is attached to the consolidation issue's thread.
h2. A. Runtime tools wiring
Found while reviewing all 86 tools of camel-jbang-mcp on main
(4.23.0-SNAPSHOT). Five wiring defects in the runtime group, one PR.
h3. 1. {{camel_runtime_receive}} starts a permanent consumer, steals messages
and returns none
{{RuntimeTools.java:693-709}} sends {{enabled=true, endpoint}} to the
{{receive}} console and returns its answer.
{{core/camel-console/.../ReceiveDevConsole.java:245-253}} then creates and
starts a {{Consumer}} on the matching endpoint that keeps running until
{{enabled=false}} is sent, which no MCP tool ever sends; received messages go
into the console's queue, read only with {{dump=true}}, which is never sent
either. So the tool consumes messages from the real route (seda, jms, kafka,
...), leaks a consumer per call, and the answer is just {{{enabled,
endpoints}}} while the description says "consumes one message from the
endpoint". It is annotated {{readOnlyHint=false, destructiveHint=false}}, so a
read-write client may call it.
Fix: either drop the tool, or implement it as enable, wait for one message with
a timeout, dump, disable, in one call, and mark it destructive.
h3. 2. {{routeId}} is silently ignored by route_dump, route_structure,
route_analysis (and the {{routeFilter}} of ai_trace)
{{camel-jbang-core/.../commands/ai/ToolRegistry.java:250, 261, 691, 694}} put
the pattern under the key {{id}};
{{dsl/camel-cli-connector/.../LocalCliConnector.java:750}}
({{doActionRouteDumpTask}}) reads {{root.getString("filter")}} and {{:775}}
({{doActionRouteStructureTask}}) reads {{getStringOrDefault("filter", "*")}}.
The CLI's own commands send {{filter}} ({{CamelRouteDumpAction.java:120}}). Net
effect: every call dumps all routes regardless of {{routeId}}, which with the
unbounded output of these consoles is the largest answer the server gives. Only
{{processor-detail}} works because {{LocalCliConnector.java:808-811}} accepts
both {{routeId}} and {{id}}. No test in camel-jbang-core or camel-jbang-mcp
covers these registry tools. The same tools never pass the {{limit}}/{{brief}}
the consoles support ({{RouteDumpDevConsole.java:75}},
{{RouteStructureDevConsole.java:78}}).
h3. 3. The {{camel_diagnose_route}} and {{camel_optimize_route}} prompts call
tools that do not exist
{{PromptDefinitions.java:242-266, 322-342}} instruct the model to call
{{get_context}}, {{get_routes}}, {{get_health}}, {{get_errors}},
{{get_history}}, {{get_route_source}}, {{get_top_processors}},
{{get_inflight}}, {{get_blocked}}, {{get_memory}}, {{get_endpoints}},
{{get_route_analysis}}, {{get_eip_stats}}, {{get_route_dump}}. Those are
registry names; the MCP tools are {{camel_runtime_context}},
{{camel_runtime_routes}}, ..., and {{get_top_processors}} has no counterpart at
all ({{camel_runtime_top}}). Both prompts are dead on arrival.
h3. 4. {{camel_runtime_ai_trace}}
{{AiTraceTools.java:77}}: {{nameOrPid}} has no {{required = false}}
({{ToolArg.required()}} defaults to true in quarkus-mcp-server 2.0.2),
contradicting the doc ("all tools accept an optional nameOrPid") and the other
41 runtime tools. {{:112-120}} swallows {{ToolExecutionException}} (including
IPC timeouts) and returns {{{}}}, so a dead process yields the success answer
"No AI components detected".
h3. 5. Smaller
* {{camel_runtime_http_request}} ({{RuntimeTools.java:322-341}}) drops the
{{timeoutSeconds}} argument the registry declares ({{ToolRegistry.java:479}}),
so the TUI and the MCP server differ.
* {{camel_runtime_memory_leak}}: default mode {{dual}}
({{RuntimeTools.java:564}}) runs two JFR recordings synchronously with
{{Thread.sleep(3000)}} polling ({{:582-669}}), about 90 s, longer than most MCP
client timeouts; the argument description says "default 60" but dual uses 30
({{:583}}); {{Integer.parseInt(duration)}} at {{:585}} is unguarded.
* {{camel_runtime_history}} says "always captured (no need to enable tracing)"
({{:685-687}}); {{BacklogTracer.java:139}} records only when {{(enabled ||
standby) && isMessageHistory()}}. To verify at runtime and document.
h3. Hints while here
{{camel_runtime_send}} is {{destructiveHint=true}} in MCP ({{:440}}) but not in
the registry ({{:330}}); {{camel_runtime_route_control}} is destructive for all
four commands ({{:243}}) while the registry marks only {{stop}} ({{:562}});
{{camel_runtime_trace}} is {{readOnlyHint=false}} for the {{dump}} action too
({{:462}}), so read-only clients cannot dump traces;
{{camel_runtime_heap_dump}} does not validate {{name}} for path separators
({{:524-526}}).
h2. B. Migration and dependency tools answer with wrong data
Found while reviewing all tools of camel-jbang-mcp on main (4.23.0-SNAPSHOT);
all in the migration/dependency group
({{dsl/camel-jbang/camel-jbang-mcp/.../mcp/}}), verified by reading.
h3. camel_migration_recipes ({{MigrationTools.java}})
* {{:241-244}}: the Quarkus command uses the *Camel* {{targetVersion}} ("e.g.
4.18.0", {{:217}}) as the {{quarkus-maven-plugin}} version:
{{io.quarkus.platform:quarkus-maven-plugin:4.18.0:update}} does not exist. It
needs the Quarkus platform version ({{camel_version_list}} already returns
{{quarkusVersion}} per release).
* {{:265-269}}: the Spring Boot command activates
{{org.apache.camel.upgrade.CamelMigrationRecipe}} for both artifacts. In
{{camel-spring-boot-upgrade-recipes}} the recipe is
{{org.apache.camel.upgrade.CamelSpringBootMigrationRecipe}} (verified in
apache/camel-upgrade-recipes, {{META-INF/rewrite/*.yaml}}), so OpenRewrite
fails with "recipe not found".
* {{:41}}: {{OPENREWRITE_VERSION = "6.29.0"}} hardcoded; the recipes README
uses the unversioned {{rewrite-maven-plugin:run}}.
h3. camel_migration_compatibility ({{MigrationTools.java}})
* {{:146-151}} and {{:277-281}}: "Camel 4.19+ requires Java 21+", reported as a
*blocker* ({{compatible=false}}) for every Java 17 user targeting 4.19 or
later. The catalog's {{camel-releases.json}} says jdk {{17,21}} for 4.19.0 and
{{17,21,25}} for 4.20 to 4.22, and {{camel_version_list}} reads exactly that,
so the two tools contradict each other. Derive from {{catalog.camelReleases()}}.
* {{:120}}: the required {{camelComponents}} argument is validated and never
used; the answer is two static guide URLs plus the wrong Java rule. With the
Java check moved to {{camel_migration_recipes}} the tool can go (see the
consolidation issue).
h3. camel_dependency_check / camel_dependency_security_audit /
camel_migration_analyze
* {{DependencyCheckTools.java:179}} compares the catalog {{artifactId}}
({{camel-kafka}}) with the POM artifactIds exactly. Spring Boot POMs have
{{camel-kafka-starter}} and Quarkus {{camel-quarkus-kafka}}, so every component
is reported "missing" there. The runtime mapping that
{{camel_dependency_for_class}} has ({{DependencyLookup.java}}) is what this
needs.
* {{DependencyData.java:55-57}} recommends
{{org.apache.camel.quarkus:camel-quarkus-bom:<camelVersion>}}; the Camel
version is not a camel-quarkus-bom version.
* {{MigrationData.java:234-237}} collects artifactIds from
{{<dependencyManagement>}} and plugin dependencies too, so a managed-but-unused
component counts as declared.
* {{DependencySecurityAuditTools.java:78}}: when the POM has no detectable
Camel version (parent-managed, the normal Spring Boot/Quarkus case) the audit
uses the *server's own* catalog version and reports {{clean=true}} ({{:149}})
with no warning ({{DependencyCheckTools.java:128-133}} at least says
"unknown"). {{AdvisoryService.java:119-128}} matches by
{{advisory.getComponents()}} only, and 16 of the 76 bundled advisories carry no
components, so they can never be reported here nor by
{{camel_route_harden_context}} ({{HardenTools.java:151-171}}): "clean" is not
"no CVEs". {{isReachable}} returns true when no routes are passed
({{:174-176}}) and the recommendation still says "directly used in routes"
({{:200-205}}). The upgrade recommendation ({{:214-218}},
{{DependencyCheckTools.java:135-142}}) compares against
{{catalog.getCatalogVersion()}}, so a SNAPSHOT server recommends upgrading
4.22.1 to 4.23.0-SNAPSHOT; {{camelReleases()}} has the real latest.
h3. Runtime detection ({{MigrationData.java}})
* {{:155-158}} sets {{isWildfly}} on {{<packaging>war}} and {{runtimeType()}}
({{:527-529}}) checks WildFly first, so a Spring Boot WAR (Tomcat deploy) is
sent to {{camel_migration_wildfly_karaf}}, told "WildFly Camel subsystem is
discontinued" and instructed to recreate the project from an archetype
({{MigrationWildflyKarafTools.java:50-53}}).
* The markers {{maven-war-plugin}}, {{maven-bundle-plugin}},
{{org.wildfly.plugins}} ({{:86-95}}) are compared against {{<dependency>}}
elements only ({{:221-232}}), never {{<plugin>}}: dead markers.
h3. camel_properties_translate ({{PropertiesTranslateTools.java:274-280}})
Every {{camel.springboot.*}} key is rewritten to {{camel.main.*}}, although the
4.5 guide says only the special Spring Boot options keep the
{{camel.springboot}} name ({{camel.springboot.lenient-configuration-binding}}
still exists), which produces an invalid
{{camel.main.lenient-configuration-binding}}. {{:198}} also calls
{{camel.server.*}} "jbang-only"; it is camel-main.
Related: CAMEL-25536 (guide search ranking), the consolidation issue (drop
{{camel_migration_compatibility}}, fold {{camel_migration_analyze}} into
{{camel_dependency_check}}).
h2. C. camel_openapi_scaffold and camel_openapi_mock_guidance disagree with
camel-rest-openapi
{{OpenApiTools.java}} (camel-jbang-mcp, main) scaffolds routes and mock files
for the {{rest-openapi}} component, with rules that do not match what
{{components/camel-rest-openapi/.../DefaultRestOpenapiProcessorStrategy.java}}
does.
* *Generated operation id*: for an operation without {{operationId}} the tool
builds {{GENOPID_GET_pets_id}} ({{OpenApiTools.java:98}}: {{"GENOPID_" + method
+ path.replace("/", "_").replace("{", "").replace("}", "")}}, and
{{:376-377}}); the component builds {{GENOPID_GET.pets._id_}}
({{DefaultRestOpenapiProcessorStrategy.java:169-171}}: {{/}} becomes {{.}},
{{\{}}/{{\}}}} become {{_}}). The scaffolded {{direct:GENOPID_...}} routes are
never bound, so every spec operation without an id answers 404 or falls into
the missing-operation mode.
* *Mock files*: the tool says {{camel-mock/<path>.<method><ext>}} with {{_id_}}
placeholders ({{:279-282}}) and returns a {{directoryStructure}}/{{mockFiles}}
listing built that way; the component matches a resource whose
extension-stripped location *ends with the request path* ({{:296-299}}), with
no method suffix and the real path values. The whole mock listing is wrong.
* {{:436-439}}: "apiKey in query is supported by Camel" reads as enforcement;
the component enforces none of the security schemes.
* {{:66-71}}: "OpenAPI 3.1 ... may not be supported" is unverified;
swagger-parser 2.1 parses 3.1 and the component has no 3.0-only path.
{{camel_openapi_mock_guidance}} is static mode text ({{:486-500}}) plus a
per-operation walk that duplicates {{camel_openapi_scaffold}}'s; the
consolidation issue proposes folding it into the scaffold's answer when
{{missingOperation=mock}}.
h3. Fix
Take the id and mock-location rules from the component (expose them as static
helpers in camel-rest-openapi if needed, so the two cannot drift), and a test
that scaffolds the petstore spec and binds the routes with the real component.
_Claude Code on behalf of Croway_
--
This message was sent by Atlassian Jira
(v8.20.10#820010)