Skip to content

Client 2026-07-28: missing resultType causes ValidationError despite required complete fallback #3767

Open

Description

@saigonbaddielover

Problem

With mcp==2.3.0, mcp-types==2.3.0, and protocol 2026-07-28, the official @modelcontextprotocol/conformance@0.2.0-alpha.12 client scenario sep-2322-client-request-state sends a successful tools/call result without resultType to verify the client fallback to complete.

The modern strict union validator runs before any normalization. ClientSession.send_request raises pydantic.ValidationError (CallToolResult.resultType Field required, InputRequiredResult.resultType Field required), and clients using PydanticAI MCPToolset / FastMCP 4.1.3 exit 1. The conformance harness reports all 5/5 message-exchange checks PASS but marks the scenario overall FAILED because the client process exits nonzero.

Reproduce

Use the official runner 0.2.0-alpha.12 with --scenario sep-2322-client-request-state --spec-version 2026-07-28; run a PydanticAI MCPToolset client that calls the scenario's test_mrtr_echo_state, test_mrtr_unrelated, test_mrtr_no_state, test_mrtr_no_result_type tools. The final call returns an omitted discriminator and triggers the exception in mcp_types.methods.validate_server_result.

Expected

For an inbound modern result with no resultType, inputRequests, or requestState, default the discriminator to complete before strict per-version validation. Preserve explicit discriminator values, untagged pending-input envelopes, and legacy protocol behavior. Do not alter server output or the MCP profile.

Evidence and proposed change

A 7-case SDK regression suite passes with this normalization. All four official scenarios driven through PydanticAI MCPToolset pass (2/2, 6/6, 9/9, 5/5 checks; process exit 0), and the full official Python SDK scored client baseline remains 32/32 PASS. Candidate fix: #3766 (automatically closed pending this issue / maintainer assignment).

Activity

  1. added
    bugSomething isn't working
    spec-2026-07-28Concerns the SDK's implementation of the 2026-07-28 MCP spec revision
    v2Affects the v2 line (2.x on main)
    on Oct 26, 2026
  2. Ben-Home commented on Oct 28, 2026

    @Ben-Home

    The conformance result here is the useful signal and it is easy to misread: five of five exchange checks pass while the scenario is marked failed, because the client process exits nonzero on the validation error. The harness is telling you the wire behaviour is correct and the client is being punished for being strict about a discriminator the scenario deliberately omits. That is a normalization ordering problem, not a union design problem.

    The seam matters. A per-class default of resultType: "complete" will not fix this, because in a strict discriminated union the discriminator is what selects the class, so InputRequiredResult cannot default its own way into existence. The place that works is a pre-validator on the inbound envelope, ahead of the union: if resultType is absent and the payload carries neither inputRequests nor requestState, then treat it as complete, while leaving any payload that does carry those markers to select its own class and leaving an explicit discriminator untouched.

    Keeping that asymmetry is what protects the rest of the behaviour you describe. Normalization should be inbound only, gated on the modern spec version, and it must not weaken outbound validation, since the server side is where a malformed result still needs to fail loudly.

    Two cases worth adding to the seven, because they are where a normalization like this usually goes wrong. A result that omits resultType but includes a non-empty inputRequests must still raise, otherwise the fallback has swallowed a pending-input envelope. And a result that omits resultType while matching neither the complete nor the input-required shape should surface the original validation error, not a missing-field error, or reporters will chase the discriminator instead of the actual schema violation.

    With PR 3766 auto-closed, reopening against the envelope pre-validator plus your suite is probably the shortest path, and referencing this conformance failure in the PR description should stop it being closed again for lack of a link to a live defect.

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 workingspec-2026-07-28Concerns the SDK's implementation of the 2026-07-28 MCP spec revisionv2Affects 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