Skip to content

Ordinary-class structured outputs discard Annotated field constraints and accept invalid values #3712

Open

Description

@inanna-malick

Initial Checks

Release line

2.x (current stable)

Description

An ordinary class's Annotated field constraints disappear when its return annotation is converted into a structured output model. A field declared Annotated[int, Field(gt=0)] produces a schema with only type: integer, and an instance containing zero is accepted as structured_content={"value": 0}.

I expected the generated property to retain exclusiveMinimum: 0 and output conversion to reject zero. The reproduction first proves that Pydantic validates the exact field annotation and rejects that value, then fails because SDK conversion does not raise ValidationError. A BaseModel with the same constraint rejects zero, and the existing ordinary-class output test still passes.

This is a class-field path, separate from the string-keyed dictionary return annotation metadata loss tracked in #2935. The relevant class path calls get_type_hints(type_annotation) without retaining extras before synthesizing the model. A tool author relying on the declared bound therefore gets neither the advertised constraint nor its validation.

Example Code

from typing import Annotated
import pytest
from pydantic import Field, TypeAdapter, ValidationError
from mcp.server.mcpserver.utilities.func_metadata import func_metadata

class Result:
    value: Annotated[int, Field(gt=0)]

    def __init__(self, value: int) -> None:
        self.value = value

def produce() -> Result:
    return Result(0)

with pytest.raises(ValidationError):
    TypeAdapter(Annotated[int, Field(gt=0)]).validate_python(0)

with pytest.raises(ValidationError):  # Fails: DID NOT RAISE
    func_metadata(produce).convert_result(produce())

The deterministic failing test is on a test-only branch.

uv run --frozen pytest tests/server/mcpserver/test_func_metadata.py::test_ordinary_class_output_rejects_values_outside_annotated_field_bounds -q

Python & MCP Python SDK

Python 3.14.7; Pydantic 2.12.5; MCP 2.3.0 (tag v2.3.0, 2118f14f8a19bc158d8a1cf90af58d85d187f849). Also reproduced using main source at 754254c08fe1c3eda18b69da3d336106fe8d72d6.

AI-assisted investigation and test reproduction, with a human in the loop.

Activity

  1. added
    bugSomething isn't working
    v2Affects the v2 line (2.x on main)
    v1Affects the v1.x maintenance line
    on Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingv1Affects the v1.x maintenance linev2Affects the v2 line (2.x on main)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions