Skip to content

fix(server): forward aliased field input under the Python parameter name - #3416

Closed
mturac wants to merge 1 commit into
modelcontextprotocol:mainfrom
mturac:fix/issue-3099
Closed

fix(server): forward aliased field input under the Python parameter name#3416
mturac wants to merge 1 commit into
modelcontextprotocol:mainfrom
mturac:fix/issue-3099

Conversation

@mturac

@mturac mturac commented Aug 30, 2026

Copy link
Copy Markdown

Summary

Fixes #3099Field(alias="externalX") publishes the alias in the tool JSON schema (correct), but at runtime the aliased wire name is forwarded directly to the Python function, causing f() got an unexpected keyword argument 'externalX'.

Root cause: ArgModelBase.model_dump_one_level() returns the Pydantic field alias as the dict key when one exists, and call_fn() passes this dict as fn(**kwargs). The function's actual parameter is the Python name (x), not the alias (externalX), so the call fails.

Fix: Track the original inspect.Parameter.name for each model field in a class-level param_names mapping, populated during func_metadata() construction. model_dump_one_level() now uses this mapping to return the Python parameter name. The SDK-internal reserved-name aliases (e.g. field_model_dump with alias model_dump) continue to work because param_names records the original parameter name, which is the alias value in that case.

The resolver system's tool_arg_names set is updated to use param_names too, so a by-name resolver parameter matches the function's Python parameter name rather than the wire alias.

Changed files

  • src/mcp/server/mcpserver/utilities/func_metadata.py — add param_names ClassVar to ArgModelBase; populate it in func_metadata(); use it in model_dump_one_level()
  • src/mcp/server/mcpserver/tools/base.py — derive tool_arg_names from param_names instead of field aliases
  • tests/server/mcpserver/tools/test_base.py — add regression test test_field_alias_maps_wire_name_back_to_python_parameter

Test plan

  • uv run --frozen pytest tests/server/mcpserver/ -q — 632 passed
  • uv run --frozen pytest tests/ -q — 5842 passed (4943 + 899)
  • uv run --frozen ruff check — all checks passed
  • uv run --frozen pyright — 0 errors

Field(alias=...) publishes the alias as the wire key (correct), but
model_dump_one_level returns that alias as the kwargs key too.  The
function's actual parameter is the Python name, so fn(**kwargs) fails
with "unexpected keyword argument".

Track the original parameter name for each model field in
ArgModelBase.param_names (populated during func_metadata) and use it
in model_dump_one_level instead of the alias.  The SDK-internal
reserved-name aliases (field_model_dump -> model_dump) continue to
work because param_names records the original inspect.Parameter.name,
which is the alias in that case.

Resolvers' tool_arg_names set now uses param_names too, so a
by-name resolver parameter matches the function's parameter name
rather than the wire alias.

Fixes modelcontextprotocol#3099
@github-actions github-actions Bot added the missing-issue-link Auto-closed: PR needs a linked issue assigned to its author (see CONTRIBUTING.md) label Aug 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR has been closed automatically. This repo only keeps pull requests open when they come from a maintainer, or from a contributor a maintainer has assigned to the linked issue, and you aren't currently assigned to #3099.

If a maintainer assigns you to #3099, this PR reopens on its own and there's nothing more you need to do here. Assignment is a maintainer call based on capacity; comments that only ask to be assigned don't factor in. What does help is engaging on the issue itself by confirming the repro, explaining why it matters for your use case, or describing the approach you'd take.

You're welcome to keep pushing commits here (just avoid force-pushing, since GitHub can't reopen a rewritten branch), but that on its own won't get the PR reviewed or the issue assigned, and realistically most auto-closed PRs stay closed. There's no need to open a new PR either way.

CONTRIBUTING.md has the full reasoning, but in short:

  • We're a small team with very little capacity to review community PRs right now.
  • Many recent PRs are AI-generated with little human review, and reviewing one carefully still costs a maintainer as much time as it ever did. A well-described issue is usually more useful to us than the code.

Maintainers: reopen, remove missing-issue-link, or add bypass-issue-check to override.

@github-actions github-actions Bot closed this Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

missing-issue-link Auto-closed: PR needs a linked issue assigned to its author (see CONTRIBUTING.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Field alias is published in the tool schema but forwarded as an invalid Python keyword

1 participant