Skip to content

fix(mcpserver): preserve Annotated/Field metadata for dict[str, T] return types#2939

Open
anneheartrecord wants to merge 2 commits into
modelcontextprotocol:mainfrom
anneheartrecord:fix/2935-dict-annotated-metadata
Open

fix(mcpserver): preserve Annotated/Field metadata for dict[str, T] return types#2939
anneheartrecord wants to merge 2 commits into
modelcontextprotocol:mainfrom
anneheartrecord:fix/2935-dict-annotated-metadata

Conversation

@anneheartrecord

Copy link
Copy Markdown

Summary

When a tool declares a dict[str, T] return type wrapped in Annotated with
Pydantic Field metadata (e.g. a description), that metadata was silently dropped
from the generated output schema.

def get_config() -> Annotated[dict[str, int], Field(description="Configuration values")]:
    return {"timeout": 30}

print(func_metadata(get_config).output_schema)
# Before: {'type': 'object', 'additionalProperties': {'type': 'integer'}, 'title': 'get_configDictOutput'}
# After:  {'type': 'object', 'additionalProperties': {'type': 'integer'}, 'title': 'get_configDictOutput', 'description': 'Configuration values'}

Root cause

In _try_create_model_and_schema, the dict[str, T] branch called
_create_dict_model(func_name, type_expr) where type_expr is the
Annotated-stripped type. The existing TODO comment on that line even flagged
the issue. The fix is to pass original_annotation instead, so
RootModel[Annotated[dict[str, T], Field(...)]] picks up the metadata.

Changes

  • src/mcp/server/mcpserver/utilities/func_metadata.py: pass original_annotation
    instead of type_expr to _create_dict_model; replace TODO comment with a
    clarifying one
  • tests/server/mcpserver/test_func_metadata.py: add
    test_structured_output_dict_str_preserves_annotated_metadata regression test
    covering Field(description=...) and Field(description=..., title=...)

Fixes #2935

…turn types

When a tool returns `Annotated[dict[str, T], Field(description="...")]`, the
`_try_create_model_and_schema` dict branch was passing the unwrapped `type_expr`
(i.e. `dict[str, T]`) to `_create_dict_model` instead of `original_annotation`,
so any `Field` description or other Pydantic metadata was dropped from the output
schema. Fix by passing `original_annotation` so the `RootModel` picks it up.

Fixes modelcontextprotocol#2935
Pre-commit ruff-format check failed because the return type annotation
for get_headers() in the test exceeded line-length limits. Wrap it to
three lines to satisfy the formatter.
@anneheartrecord

Copy link
Copy Markdown
Author

Fixed the pre-commit failure — ruff-format wrapped a long return-type annotation in the test file. All other checks were already green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dict[str, T] tool return types lose Annotated/Field metadata in output schema

1 participant