Repository navigation
Description
Initial Checks
- Reproduced with the newest 2.x release, 2.3.0.
- Searched the issue tracker for an existing report.
Release line
2.x (current stable)
Description
Registering a function with two ordinary parameters, model_dump and field_model_dump, succeeds. However, Client.list_tools() advertises only field_model_dump; the required Python parameter model_dump disappears from the generated input schema. I expected both parameters to remain available to clients and schema-valid inputs to bind to their original Python parameter names.
The SDK protects reserved Pydantic names by internally prefixing model_dump as field_model_dump. A real parameter already named field_model_dump collides with that generated name. The test stops at the missing schema property, before its follow-up invocation assertion.
This is adjacent to #3099 and closed PR #3416, but no user-defined Field(alias=...) is involved: the collision is between an internal generated name and a literal second parameter. Merely mapping an existing model field back to its Python name does not recover a field already overwritten during model construction.
Test: standalone failing reproduction, branch repro/tool-reserved-name-collision (diff).
From that branch, after installing its development dependencies:
uv run --frozen pytest tests/server/mcpserver/tools/test_base.py::test_tool_reserved_parameter_does_not_collide_with_prefixed_field_name -qObserved pytest failure:
AssertionError: assert {'field_model_dump', 'model_dump'} <= dict_keys(['field_model_dump'])
Example Code
import anyio
from mcp import Client
from mcp.server.mcpserver import MCPServer
async def main() -> None:
server = MCPServer()
@server.tool()
def inspect(model_dump: int, field_model_dump: int) -> str:
return f"seen:{model_dump}:{field_model_dump}"
async with Client(server) as client:
(tool,) = (await client.list_tools()).tools
assert {"model_dump", "field_model_dump"} <= tool.input_schema["properties"].keys()
anyio.run(main)Python & MCP Python SDK
Python 3.14.7 / Pydantic 2.12.5. Fails on latest stable mcp/mcp-types 2.3.0 (2118f14) and current main 754254c. Each targeted run: 1 intentional failure, 2 passing existing controls. The same test runs against each version’s source.
AI-assisted investigation and test reproduction, with a human in the loop.
Activity
Ben-Home commentedon Oct 15, 2026
Naeemeh146 commentedon Oct 17, 2026
I'd like to take this one — I've reproduced it locally and traced the root cause.
Diagnosis: In
func_metadata(src/mcp/server/mcpserver/utilities/func_metadata.py), a parameter shadowing aBaseModelattribute gets renamed tofield_<name>with its original name kept as the alias. But the rename isn't collision-checked: with paramsmodel_dumpandfield_model_dump, the first becomes fieldfield_model_dump(aliasmodel_dump), and the second also lands on field namefield_model_dump— the dict assignment silently overwrites the first, somodel_dumpdisappears from the generated schema entirely. I confirmed the schema only advertisesfield_model_dump.Approach: Make the rename collision-proof — after the
field_prefixing, loop the prefix until the field name is unique within the model's fields, and set the alias to the original parameter name so the schema keys and the kwargs frommodel_dump_one_level()keep using the natural names. This preserves the existing contract (verified againsttest_basemodel_reserved_names: schema and call kwargs still use original names) and is order-independent — whichever parameter is renamed, both stay visible.One question: is there any consumer that reads
arg_model.model_fieldskeys directly (rather than via alias/schema), where the extrafield_prefix on a non-shadowing parameter could surprise it? I checkedmodel_dump_one_leveland the schema path, but wanted to confirm there's no other field-name reader before I write it up.If that approach sounds right, I'd appreciate being assigned.
inanna-malick commentedon Oct 18, 2026
That approach sounds solid, but my work here has mainly been on the automated proptesting framework that found these bugs - I don't have any detailed context wrt the internals of this repo, so a maintainer should provide this guidance.