Repository navigation
Commit 4497e7c
authored
fix(mcp): alias MCP tool properties that pydantic cannot use as field names (#2442)
Closes #2441
`_model_from_mcp_schema` used the property names of an MCP tool schema as Pydantic field names. Pydantic rejects names with a leading underscore and the names of its own `model_` members, so a tool taking `_id` failed with `NameError: Fields must not use names with leading underscores` and one taking `model_config` failed with a `TypeError`. The input models are built inside `MCPBaseClient.get_tools()`, so one such tool made the whole `mcp_client` / `per_user_mcp_client` function group fail and every tool on the server was lost.
Such a property now gets a field named after it with the leading underscores stripped and a trailing underscore added (`_id` becomes `id_`, `model_config` becomes `model_config_`, with more underscores if that name is already a property), and the original name is the field alias. Those models set `validate_by_name`, because the input arrives keyed by the schema's names from the LLM and keyed by field name when `FunctionInfo` passes the validated model on as keyword arguments. The JSON schema the LLM sees still lists `_id`. `_dump_tool_args` now dumps with `by_alias=True`, and `_drop_optional_none_values` maps each dumped key back to its field, so the server receives `_id` again, also in nested objects. Properties with ordinary names get no alias and their models get the same config as before, so nothing changes for them. The `model_` rule also covers names that built before but broke at call time. On develop a `model_post_init` property made every validation fail with a TypeError, and a `model_extra` property was silently left out of the arguments sent to the server. Names such as `json` or `copy`, which only shadow a deprecated `BaseModel` method with a warning, keep working as they did.
This is the client side counterpart of #2079, which handled property names that are not Python identifiers in the server's tool converter. I kept the same idea of a safe name plus a mapping back to the original, but here the mapping lives in the model as a Pydantic alias, which also covers nested objects.
The new tests are in `packages/nvidia_nat_mcp/tests/client/test_mcp_schema.py` (models for `_id` and `model_config`, validation by alias and by field name, a renamed field that would collide with another property, a nested `_id`, and that ordinary names get no alias) and `packages/nvidia_nat_mcp/tests/client/test_mcp_client_impl.py` (the arguments a per-user and a session tool send keep `_id` and `model_config` as keys at both levels, and unset renamed optional arguments are left out). On develop 8 of them fail, and the ordinary-names check passes as it should. With the change all 102 tests in those two files pass. The whole `packages/nvidia_nat_mcp/tests` run gives 450 passed and 8 skipped, plus `test_mcp_plugin_discovered` and `test_mcp_command_registration`, which fail the same way on develop in my environment because the package is not installed and the `mcp` CLI entry point is not found. I also built the `mcp_client` group against a small stdio server with an `echo` tool and a `get_document(_id)` tool. Both tools are registered now, and calling `get_document` through `ainvoke`, `acall_invoke` and the LangChain tool wrapper delivered `{'_id': ...}` to the server each time. yapf 0.43.0 and ruff 0.15.0 check are clean on the four files.
## By Submitting this PR I confirm:
- I am familiar with the [Contributing Guidelines](https://github.com/NVIDIA/NeMo-Agent-Toolkit/blob/develop/docs/source/resources/contributing/index.md).
- We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license.
- Any contribution which contains commits that are not Signed-Off will not be accepted.
- When the PR is ready for review, new or existing tests cover these changes.
- When the PR is ready for review, the documentation is up to date with these changes.
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed handling of tool schemas with underscore-prefixed names or names that conflict with model attributes. These names are now preserved in server arguments, including in nested fields.
* Optional renamed fields that are unset are omitted from arguments, while required fields continue to be validated.
* **Compatibility**
* Improved validation and schema output for fields with special names without changing how ordinary field names are handled.
Authors:
- Dmitry Voropaev (https://github.com/v0ropaev)
Approvers:
- Will Killian (https://github.com/willkill07)
URL: #24421 parent 4c219e2 commit 4497e7c
4 files changed
Lines changed: 138 additions & 10 deletions
File tree
- packages/nvidia_nat_mcp
- src/nat/plugins/mcp
- client
- tests/client
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
| 84 | + | |
| 85 | + | |
84 | 86 | | |
85 | | - | |
86 | 87 | | |
87 | | - | |
| 88 | + | |
| 89 | + | |
88 | 90 | | |
89 | | - | |
| 91 | + | |
90 | 92 | | |
91 | 93 | | |
92 | 94 | | |
| |||
108 | 110 | | |
109 | 111 | | |
110 | 112 | | |
111 | | - | |
| 113 | + | |
112 | 114 | | |
113 | 115 | | |
114 | 116 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
178 | 178 | | |
179 | 179 | | |
180 | 180 | | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
181 | 204 | | |
182 | 205 | | |
183 | 206 | | |
| |||
403 | 426 | | |
404 | 427 | | |
405 | 428 | | |
406 | | - | |
| 429 | + | |
407 | 430 | | |
408 | 431 | | |
409 | 432 | | |
| |||
444 | 467 | | |
445 | 468 | | |
446 | 469 | | |
| 470 | + | |
| 471 | + | |
447 | 472 | | |
448 | | - | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
449 | 477 | | |
| 478 | + | |
450 | 479 | | |
451 | | - | |
452 | | - | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
453 | 484 | | |
454 | | - | |
| 485 | + | |
455 | 486 | | |
456 | | - | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
457 | 492 | | |
458 | 493 | | |
459 | 494 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
480 | 480 | | |
481 | 481 | | |
482 | 482 | | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
483 | 507 | | |
484 | 508 | | |
485 | 509 | | |
| |||
582 | 606 | | |
583 | 607 | | |
584 | 608 | | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1692 | 1692 | | |
1693 | 1693 | | |
1694 | 1694 | | |
| 1695 | + | |
| 1696 | + | |
| 1697 | + | |
| 1698 | + | |
| 1699 | + | |
| 1700 | + | |
| 1701 | + | |
| 1702 | + | |
| 1703 | + | |
| 1704 | + | |
| 1705 | + | |
| 1706 | + | |
| 1707 | + | |
| 1708 | + | |
| 1709 | + | |
| 1710 | + | |
| 1711 | + | |
| 1712 | + | |
| 1713 | + | |
| 1714 | + | |
| 1715 | + | |
| 1716 | + | |
| 1717 | + | |
| 1718 | + | |
| 1719 | + | |
| 1720 | + | |
| 1721 | + | |
| 1722 | + | |
| 1723 | + | |
| 1724 | + | |
| 1725 | + | |
| 1726 | + | |
| 1727 | + | |
| 1728 | + | |
| 1729 | + | |
| 1730 | + | |
| 1731 | + | |
| 1732 | + | |
| 1733 | + | |
| 1734 | + | |
| 1735 | + | |
| 1736 | + | |
| 1737 | + | |
| 1738 | + | |
| 1739 | + | |
| 1740 | + | |
| 1741 | + | |
| 1742 | + | |
| 1743 | + | |
| 1744 | + | |
| 1745 | + | |
| 1746 | + | |
| 1747 | + | |
| 1748 | + | |
| 1749 | + | |
0 commit comments