Croway opened a new pull request, #28677: URL: https://github.com/apache/camel/pull/28677
_Claude Code on behalf of Croway_ [CAMEL-26399](https://issues.apache.org/jira/browse/CAMEL-26399) ## Problem The catalog tools name their main argument differently (`camel_catalog_doc` takes `name`, `camel_catalog_find` takes `term`, `camel_catalog_example_file` takes `example`, `camel_validate_source` takes `file` and `content`), and models carry one tool's names over to the next. Quarkus MCP rejects such a call before the tool runs with a bare `Missing required argument: term`, and drops an argument it does not know without a word, so the model learns which name is missing but not that its own argument was taken for something else. In the eval this was the only failure Sonnet 5.5 had on the 4.24 server, and in 6 of the 8 `camel_validate_source` episodes the agent gave up on the tool. ## Fix - `ToolArgumentAliases` (camel-jbang-core, next to `ToolRegistry`) keeps the table of the names models use and resolves a call against the arguments a tool declares: | Tool | Argument | Also accepted | |---|---|---| | `camel_catalog_find` | `term` | `query`, `name` | | `camel_catalog_example_file` (`get_example_file` in `camel ask`) | `example` | `name` | | `camel_validate_source` | `file` | `path`, `filename`, `name` | | `camel_validate_source` | `content` | `source` | An alias is taken only when the call does not give the declared argument and the tool has no argument of that name (the `name` of `camel_catalog_doc` and `camel_catalog_sample` is never touched). When a call gives several aliases of one argument, the first in the table wins and the others are reported as ignored; `path` comes first because it says more than a bare file name. A `path` is passed on as the `file` unchanged; how an absolute `file` is handled (accepted only inside the project directory) is CAMEL-26398. - `McpArgumentGuardrail`, a `ToolInputGuardrail` and `ToolOutputGuardrail` declared with `@ToolGuardrails` on every `@Tool` method of the server (85 tools; a test fails when one lacks it). The input side runs before Quarkus checks the arguments: it renames the aliases, and a call that still misses a required argument, of any tool, gets a tool error with the tool's own argument list: `camel_catalog_find takes term (required), kind, limit, camelVersion; got q` (`got no arguments` when empty). The output side adds an `argumentNote` as the first field of a JSON object answer, e.g. `"term is the argument name (got query)"`, and names arguments the tool ignored: `"ignored: bogus; camel_catalog_find takes term (required), kind, limit, camelVersion"`. Errors and non-JSON answers are left as they are. The note is handed from input to output through a `@RequestScoped` bean (each tool call runs in a request context of its own). The guardrail does not block, so it supports every execution model; all tools run on a worker thread. - `camel ask` resolves the same aliases before it confirms and runs a shared tool, and adds the same note to JSON answers. The missing-argument message is MCP only: `camel ask` does not send required flags to the model, and the shared tools keep answering a missing argument themselves. - The tool schemas are unchanged: `term`, `example`/`file` and `file` stay required in `tools/list`. - Docs: "Argument names" in `camel-jbang-mcp.adoc`, a pointer in `camel-jbang-ai.adoc`. Not changed: `camel tui --mcp` and the TUI AI panel run the shared tools through `TuiToolRegistry`, which does not resolve aliases yet (same failure, with the shared tools' own messages such as `file is required`); its file tools have their own argument handling, so that is left for a follow-up. ## Testing The six calls of the issue over stdio against the runner jar (origin/main 017f4fd11c4a, then this branch): | Call | Before | After | |---|---|---| | `camel_catalog_find {"query":"activemq classic 6 jms"}` | `Missing required argument: term` | answered (no match for that term), `argumentNote: term is the argument name (got query)` | | `camel_catalog_find {"name":"groovy"}` | `Missing required argument: term` | the matches of `groovy`, `argumentNote: term is the argument name (got name)` | | `camel_catalog_example_file {"name":"contracts/rest-code-first","file":"rest-code-first.camel.yaml"}` | `Missing required argument: example` | the file content, `argumentNote: example is the argument name (got name)` | | `camel_validate_source {"name":"hr-api-call.yaml","content":"- route: ..."}` | `Missing required argument: file` | `valid: true`, `argumentNote: file is the argument name (got name)` | | `camel_validate_source {"filename":"routes.yaml","source":"- route: ..."}` | `Missing required argument: file` | `valid: true`, `argumentNote: file is the argument name (got filename); content is the argument name (got source)` | | `camel_validate_source {"path":"/abs/camel/salesleads.yaml","filename":"salesleads.yaml"}` | `Missing required argument: file` | runs with `file` = the path: `directory is required: the project directory with the source files`; a call without `directory` still needs one (or an MCP root that holds the file, CAMEL-26398) | Also checked end to end: `{"term":"mqtt","limit":1,"bogus":"x"}` answers with `ignored: bogus; ...`; `{"term":"mqtt","query":"s3"}` keeps `term` and notes `query` as ignored; `camel_catalog_find {"q":"mqtt"}`, `camel_catalog_example_file {"name":"timer-log"}` and `camel_write_file {"file":"x.yaml"}` answer with the tool's argument list; `camel_catalog_doc {"name":"kafka"}` is answered as before; `tools/list` marks the same arguments required as on main. - `ToolArgumentAliasesTest` (new, camel-jbang-core): each alias, declared argument wins, null counts as not given, first alias wins, an alias that is a real argument is left alone, unknown arguments, the missing-argument message, the table matches the registry tools, the note in a JSON answer. - `AskToolsTest#anArgumentNamedAsAnotherToolNamesItRunsAndTheAnswerSaysTheName` (fails on main). - `McpArgumentGuardrailTest` (new, camel-jbang-mcp): every `@Tool` method declares the guardrail; the table matches the MCP tools and their arguments stay required; the six calls; the missing-argument message for any tool; the note on JSON object answers only; no note carried to the next call. The tools are described from their real declarations, as the server describes them. - Whole camel-jbang-core (2526 + 244 tests, 2 skipped) and camel-jbang-mcp (515 tests) suites pass. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
