test(mcpserver): cover PEP 604 union return annotations (#2591)#2906
Open
Bartok9 wants to merge 1 commit into
Open
test(mcpserver): cover PEP 604 union return annotations (#2591)#2906Bartok9 wants to merge 1 commit into
Bartok9 wants to merge 1 commit into
Conversation
…protocol#2591) Closes modelcontextprotocol#2591. A tool whose return type uses a multi-member Python 3.10+ union mixing container and scalar types (dict | list | str) previously crashed at registration with PydanticUserError, because the bare types.UnionType was passed to create_model() as a field value. This is already fixed on main: such a union is neither a types.GenericAlias nor a type, so _try_create_model_and_schema falls through to the catch-all branch and wraps the result under {"result": ...}; modelcontextprotocol#2434 additionally guards the schema-generation path. But there was no regression test for the exact reported signature -- the existing func_union test only covers a 2-member all-scalar union (str | int), not a container+scalar mix with bare generics. Adds test_structured_output_pep604_union_return asserting the wrapped anyOf output_schema for the issue's exact signature, so the fix can't silently regress. Verification: uv run pytest tests/server/mcpserver/test_func_metadata.py -q -> 34 passed; ruff check/format clean; pyright 0 errors.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
dict | list | str).Motivation
Closes #2591.
FastMCP/MCPServerused to crash at registration withPydanticUserErrorwhen a tool's return type was a bare PEP 604 union likedict | list | str, because thetypes.UnionTypewas passed tocreate_model()as a field value.This already works on current
main(734746a): such a union is neither atypes.GenericAliasnor atype, so_try_create_model_and_schema(func_metadata.py) falls through to the catch-all branch that calls_create_wrapped_model(...)withwrap_output=True; #2434 (5cbd259) additionally guards the schema-generation path. But there is no test covering the reported signature — the existingtest_structured_output_generic_typesonly exercises a 2-member, all-scalar union (func_union() -> str | int), not a container+scalar mix with bare (unparametrized) generics, which is a different branch interaction (thedictmember touches the RootModel dict special-casing before the union wraps).The three prior fix attempts (#2592, #2599, #2669) were all closed during backlog cleanup rather than for an approach problem, and one of them switched the repro to typed generics to satisfy pyright — which masked the exact reported case. This PR keeps the bare-generic signature (with scoped
# type: ignore) so the test reproduces the issue faithfully.Verification
uv run pytest tests/server/mcpserver/test_func_metadata.py -q— 34 passeduv run ruff check tests/server/mcpserver/test_func_metadata.py— cleanuv run ruff format --check tests/server/mcpserver/test_func_metadata.py— already formatteduv run pyright tests/server/mcpserver/test_func_metadata.py— 0 errorsmain.Real behavior proof
@mcp.tool() async def my_tool(flag: bool) -> dict | list | strregistering withoutPydanticUserError, and producing a wrappedanyOfoutput_schema.uv run, branch offupstream/main734746a.uv run python -c "..."invokingfunc_metadata(func, structured_output=True).output_schemafor() -> dict | list | str.{ "properties": { "result": { "anyOf": [ {"additionalProperties": true, "type": "object"}, {"items": {}, "type": "array"}, {"type": "string"} ], "title": "Result" } }, "required": ["result"], "title": "func_pep604_unionOutput", "type": "object" }tests/server/mcpserver/test_func_metadata.py::test_structured_output_pep604_union_return— asserts the exact wrappedanyOfshape above for the issue's signature.