Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

func_metadata raises uncaught PydanticSchemaGenerationError for Iterator/AsyncIterator tool return annotations instead of the unstructured fallback

Open Beginner friendly
#3,573 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
65/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
api, backend

Research direction

The issue is in src/mcp/server/mcpserver/utilities/func_metadata.py. Look at line 444 where _create_output_model is called outside the try/except block. The fix is to move that call inside the existing try/except block that catches PydanticUserError and pydantic_core.SchemaError. Test with the provided reproduction script to ensure Iterator/AsyncIterator return types now either fall back to unstructured output or raise InvalidSignature as documented.

Written by the indexing model from the issue text.

Description

v1 v2
Initial Checks
Release line

2.x (current stable)

Description

Registering a tool whose function is annotated -> Iterator[...] or -> AsyncIterator[...] — the PEP 484 spelling for generator functions — raises a raw pydantic.errors.PydanticSchemaGenerationError at registration time, instead of either falling back to an unstructured tool (structured_output=None, the default) or raising the SDK's InvalidSignature (structured_output=True). The same happens via @server.tool() / Tool.from_function(), so a properly typed generator tool cannot be registered at all.

Actual output of the script in "Example Code" (error text truncated at 80 chars by the script):

func_metadata(search): UNCAUGHT pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for typing.Iterator[str]. Set `arbitrary
func_metadata(search, structured_output=True): UNCAUGHT pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for typing.Iterator[str]. Set `arbitrary
Tool.from_function(search): UNCAUGHT pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for typing.Iterator[str]. Set `arbitrary

Full traceback (captured with the collections.abc spelling of the same annotation, so the error names it accordingly):

  File "src/mcp/server/mcpserver/utilities/func_metadata.py", line 444, in func_metadata
    output_model, wrap_output = _create_output_model(original_annotation, return_type_expr, func.__name__)
  File "src/mcp/server/mcpserver/utilities/func_metadata.py", line 550, in _create_output_model
    model = _create_wrapped_model(func_name, original_annotation)
  File "src/mcp/server/mcpserver/utilities/func_metadata.py", line 621, in _create_wrapped_model
    return create_model(model_name, result=annotation)
pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for collections.abc.Iterator[str]. Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it.

What I expected is what already happens for other unserializable return types, pinned by test_structured_output_unserializable_type_error (tests/server/mcpserver/test_func_metadata.py:1233, passes on main) and documented in docs/servers/structured-output.md: with structured_output=None, registration succeeds and output_schema is None (fallback to text); with structured_output=True, InvalidSignature: Function search: return type ... is not serializable for structured output. For contrast, Iterable[str] and Generator[str, None, None] both register successfully through the same wrapped-model path — only the PEP 484-recommended spellings for generators crash.

Root cause: _create_output_model(...) is called at src/mcp/server/mcpserver/utilities/func_metadata.py:444, outside the try/except at lines 446–470 whose except tuple (PydanticUserError, pydantic_core.SchemaError, ...) exists exactly so that "an unsupported return type surfaces here, at registration" as a clean failure. _create_output_model_create_wrapped_modelcreate_model(model_name, result=annotation) (line 621) builds a schema itself, and its PydanticSchemaGenerationError (a PydanticUserError subclass) escapes uncaught. Moving the line 444 call inside the existing try/except looks like it would restore both documented behaviours; I'd be happy to be assigned and open a PR with that approach.

Related: the guard was added in #2434 (for #1131), but it wraps only the FuncMetadata construction, not this call. #1060 reports the same error class for a different type (Image, 1.x fastmcp) and looks unrelated to this code path.

AI disclosure: this issue and its reproduction were prepared with AI assistance.

Example Code
from typing import Iterator

from mcp.server.mcpserver.tools import Tool
from mcp.server.mcpserver.utilities.func_metadata import func_metadata


def search(n: int) -> Iterator[str]:
    yield from ["a"] * n


for label, call in [
    ("func_metadata(search)", lambda: func_metadata(search)),
    ("func_metadata(search, structured_output=True)", lambda: func_metadata(search, structured_output=True)),
    ("Tool.from_function(search)", lambda: Tool.from_function(search)),
]:
    try:
        call()
        print(f"{label}: OK")
    except Exception as e:
        print(f"{label}: UNCAUGHT {type(e).__module__}.{type(e).__name__}: {str(e)[:80]}")
# AsyncIterator[str] return annotations behave identically
Python & MCP Python SDK
mcp: main @ 6affe5c0d3588fd1705713b3703dc68015cfe3eb
     func_metadata.py is identical in v2.2.0 (latest 2.x release);
     the same crash reproduces on a fresh `pip install mcp==2.2.0`
Python 3.13.15
pydantic 2.12.5
macOS 26.6.2 (arm64)
Dominant language
Python
Stars
24.3k
Forks
4k
Avg merge
1d 16h
Merged PRs (30d)
25

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from modelcontextprotocol/python-sdk

All issues in modelcontextprotocol/python-sdk

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.