You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Guillaume Nodet (Jira)" <ji...@apache.org> on 2026/10/14 13:09:00 UTC

[jira] [Work stopped] (CAMEL-25640) camel-jbang-mcp - catalog built per call for the authoring tools, Kamelet tools reload per call and return a hash-ordered subset, repeated-call detection counts failed calls

     [ https://issues.apache.org/jira/browse/CAMEL-25640?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Work on CAMEL-25640 stopped by Guillaume Nodet.
-----------------------------------------------
> camel-jbang-mcp - catalog built per call for the authoring tools, Kamelet tools reload per call and return a hash-ordered subset, repeated-call detection counts failed calls
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25640
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25640
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-jbang-mcp
>            Reporter: Federico Mariani
>            Assignee: Guillaume Nodet
>            Priority: Major
>
> Found while reviewing all tools of camel-jbang-mcp on main (4.23.0-SNAPSHOT).
> h3. 1. A catalog per call
> The 15 shared authoring tools ({{camel_catalog_doc}}, {{camel_catalog_find}}, {{camel_validate_source}}, {{camel_error_diagnose}} ...) go through {{MCP/AuthoringTools.java:347}}: {{ToolRegistry.execute(tool, new ToolContext(), args)}}. A new {{ToolContext}} means a new {{DefaultCamelCatalog()}} with the cache *off* ({{camel-jbang-core/.../ai/ToolContext.java:174-177}}), so every call re-parses the JSON it touches ({{ErrorDiagnoser}} iterates all EIP models per call), and with {{camelVersion}} a fresh Maven resolution plus a {{DependencyDownloaderClassLoader}} per call ({{CatalogLoader.java:70-100}}) that is never cached nor closed. The server's own {{CatalogService}} (cached per version/runtime, honours {{camel.catalog.repos}}) is not used by these tools. Fix: a per-version {{ToolContext}}/catalog cache in the MCP wrapper, or route {{ctx.catalog()}} through {{CatalogService}}.
> h3. 2. Kamelet tools
> * {{camel_catalog_kamelets}} ({{KameletTools.java:84-92}}) applies {{limit}} while iterating the {{HashMap}} of {{KameletsCatalog}} and sorts afterwards, so the default answer is the first 50 of 200+ Kamelets in hash order, with no {{total}} to signal the truncation.
> * Both Kamelet tools run {{KameletCatalogHelper.loadKamelets}} (new downloader and classloader) on every call ({{:62, 120}}), while {{KameletDefinitions}} in camel-jbang-core already caches the same catalog per version for {{camel_catalog_doc kind=kamelet}}.
> * {{:148-151}} reports any {{Throwable}} (network, Maven) as "Kamelet not found".
> (The consolidation issue proposes folding both into {{camel_catalog_doc}}/{{camel_catalog_find}}; if that lands first, only the cache part remains.)
> h3. 3. Repeated-call detection
> {{RepeatedToolCalls.java:64}} increments the per-session count *before* the tool runs, so a call that throws (catalog download failure, unsupported file type in {{camel_validate_source}}, missing required argument) counts as answered in full, and the third attempt gets "it is in your earlier tool result" for an answer that never existed. Count after a successful answer only. Also not covered although deterministic: {{camel_catalog_docs}}, {{camel_component_properties}}, the Kamelet and example tools, {{camel_configuration_validate}}, {{camel_transform_route}}.
> h3. 4. Smaller
> * {{CatalogService.java:109-120, 207-211}}: {{runtime=quarkus}} with {{camelVersion}} and no {{platformBom}} skips the BOM lookup and calls {{loadQuarkusCatalog(null, ...)}}; {{ToolArgDocs.VERSION_QUERY}} explicitly invites that input. {{CatalogServiceTest}} covers BOM forms only.
> * {{LAST_REFUSED}} ({{camel-jbang-core/.../ai/AuthoringTools.java:1203-1210}}) is a static map keyed by path, cleared only on a successful write, shared across all MCP connections: unbounded, and one client's refusal count leaks into another's message.
> * {{CatalogTools.java:74-76}}: a negative {{limit}} ends in {{IllegalArgumentException}} ("Failed to list") instead of the default; {{ExampleTools}} treats {{<= 0}} as default and {{KameletTools}} uses it raw.
> _Claude Code on behalf of Croway_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)