Treat `typing.Dict[str, X]` return annotations like `dict[str, X]`

Merged
KL
9d ago
+31-8

Fixes #3745

-> typing.Dict[str, X] now gets the same output schema and structuredContent as -> dict[str, X], instead of being wrapped in {"result": ...}.

Motivation and Context

_create_output_model detected generics with isinstance(type_expr, types.GenericAlias). typing.Dict[str, X] is a typing._GenericAlias, so it fell through to the catch-all branch and got wrapped. Rewriting Dict to dict (e.g. ruff UP006) therefore silently changed a tool's output on the wire.

The branch now checks get_origin(type_expr) is not None.

How Has This Been Tested?

  • Added a typing.Dict[str, str] case to test_structured_output_dict_str_types; it fails without the fix.
  • Added a NewType case to test_structured_output_generic_types, which is now what reaches the catch-all branch.
  • func_metadata.py at 100% coverage, strict-no-cover, ruff and pyright pass; test file passes on 3.11, 3.13 and 3.14.

Breaking Changes

Tools annotated -> typing.Dict[str, X] stop wrapping their result in {"result": ...}, matching the builtin spelling. Union, Optional, Literal and typing.List/Tuple now take the generic branch instead of the catch-all, but are still wrapped as before.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I am assigned to the linked issue (or it is labeled help wanted, or I'm a maintainer)
  • I have disclosed any AI assistance and can explain the change in my own words
  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Related: #3725 (bare dict/list/tuple), which touches the same function.

AI Disclaimer

This PR was developed with the assistance of either Claude or Codex. I've reviewed and verified the changes.