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)

Reply via email to