You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Pydantic model parameter not flattened in MCP tool schema — breaks SDK clients that send flat argument dicts #3637
When a FastMCP tool is defined with a Pydantic model as its parameter, FastMCP 4.x generates a JSON schema that wraps the model's fields under a "request" key rather than flattening them to the top level. This breaks MCP clients that send the fields flat — including the official adcp Python SDK, which serialises request objects with model.model_dump() and sends the result as a flat dict.
{ "adcp_version": "3.2", "protocols": null }
FastMCP validates this against the schema and raises:
1 validation error for call[get_adcp_capabilities]
adcp_version
Unexpected keyword argument [type=unexpected_keyword_argument, ...]
What should happen:
Either:
FastMCP should flatten the fields of a Pydantic model parameter into the tool's top-level inputSchema (matching how bare field: type = default kwargs work today), or
FastMCP should accept both the flat form {"adcp_version": "3.2"} and the nested form {"request": {"adcp_version": "3.2"}} when the parameter is a Pydantic model.
The spec (GetAdcpCapabilitiesRequest) already defines the full wire shape including extra: 'allow' for forward compatibility. Using the model type as the parameter should be the idiomatic approach — it avoids re-declaring every field individually.
Workaround: Redeclare every field from the Pydantic model as individual kwargs on the tool function (defeats the purpose of having the model type).
Example Code
frompydanticimportBaseModelfrommcp.server.fastmcpimportFastMCPmcp=FastMCP("example")
classMyRequest(BaseModel):
model_config= {"extra": "allow"}
adcp_version: str|None=Noneprotocols: list[str] |None=None@mcp.tool()asyncdefmy_tool(request: MyRequest=MyRequest()) ->str:
returnf"got: {request.adcp_version}"# Client sends: {"adcp_version": "3.2"}# FastMCP raises: Unexpected keyword argument 'adcp_version'# Client must send: {"request": {"adcp_version": "3.2"}}# — but the SDK and spec generate flat dicts from model_dump()
Confirm scope: reproduced unexpected_keyword_argument in standalone FastMCP 4.0.3; SDK 2.x MCPServer instead ignores flat fields when the model parameter has a default.
Preserve the documented nested contract; clarify model envelopes and the low-level Server route for flat wire schemas. Draft docs: clarify Pydantic tool argument envelopes #3638 contains documentation and regression coverage; 90 relevant tests passed locally.
If flat/dual-shape runtime support is preferred, agree on the published schema and conflict rules first, while preserving existing nested callers.
Investigation and draft prepared with Codex assistance.
Thanks for the report. I'm going to close this one, because the error you're seeing comes from the standalone FastMCP package (4.0.3 in your environment) rather than this SDK. Unexpected keyword argument is raised by its own argument validation, so https://github.com/PrefectHQ/fastmcp is the right place for it.
Activity
aritejhg commentedon Oct 3, 2026
Could I take this up with the following approach?
unexpected_keyword_argumentin standalone FastMCP 4.0.3; SDK 2.xMCPServerinstead ignores flat fields when the model parameter has a default.Serverroute for flat wire schemas. Draft docs: clarify Pydantic tool argument envelopes #3638 contains documentation and regression coverage; 90 relevant tests passed locally.Investigation and draft prepared with Codex assistance.
maxisbey commentedon Oct 6, 2026
Thanks for the report. I'm going to close this one, because the error you're seeing comes from the standalone FastMCP package (4.0.3 in your environment) rather than this SDK.
Unexpected keyword argumentis raised by its own argument validation, so https://github.com/PrefectHQ/fastmcp is the right place for it.AI Disclaimer
Generated by Claude Code