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]

Reply via email to