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
  3. Gowthaman90 commented on Nov 4, 2026

    @Gowthaman90

    I hit this from a different direction, and I think it needs a decision on intended behaviour
    before a fix.

    I was scoring a stdio security proxy with my benchmark
    (mcp-defense-bench-py). When the proxy
    blocks a call, it writes its own {"content": [...], "isError": true} with no resultType, on
    a session that negotiated 2026-07-28 (the proxy forwards server/discover to a v2 server).
    FastMCP 4.1 on mcp 2.3.0 raises the ValidationError described here. I reported the missing
    tag to the proxy (vdalal/agentx-security-sdk#1).

    Two things point to rejection being the intended behaviour:

    • The 2026-07-28 schema says servers implementing that version MUST include resultType, and
      scopes the absent-means-complete fallback to servers on earlier versions.
      sep-2322 absent-resultType probe is an invalid stimulus on the 2026-07-28 wire it negotiates conformance#475 argues that the conformance probe this issue relies on
      is invalid on the 2026-07-28 wire it negotiates.
    • The TypeScript client (@modelcontextprotocol/client 2.4.0, versionNegotiation: { mode: "auto" })
      rejects the same reply: SdkError: Invalid result for tools/call: missing required resultType — servers implementing protocol revision 2026-07-28 MUST include it (the absent-means-complete bridge applies only to earlier-revision servers).

    If rejection stays, the Python error could be as direct as the TypeScript one. Today it reads
    2 validation errors for union[CallToolResult,InputRequiredResult], and its second line,
    InputRequiredResult.resultType Field required, sent me looking at input-required handling.
    The actual cause was a missing tag from a non-conformant intermediary.

    Minimal repro (plain-Python stdio server, no SDK, so the reply bytes are exact):

    repro.py
    """A 2026-07-28 tools/call result without `resultType`: what the Python client raises.
    
    The "server" is a few lines of plain Python speaking JSON-RPC over stdio, so the reply
    bytes are exact. It answers server/discover (2026-07-28) and returns an isError tool
    result with no resultType, the shape a stdio security proxy writes when it blocks a call.
    """
    import sys
    
    import anyio
    from mcp import Client, StdioServerParameters
    
    SERVER = r'''
    import json, sys
    for line in sys.stdin:
        msg = json.loads(line)
        if "id" not in msg:
            continue
        reply = {"jsonrpc": "2.0", "id": msg["id"]}
        if msg["method"] == "server/discover":
            reply["result"] = {"resultType": "complete", "supportedVersions": ["2026-07-28"],
                               "capabilities": {"tools": {}}, "ttlMs": 0, "cacheScope": "private"}
        elif msg["method"] == "tools/call":
            reply["result"] = {"content": [{"type": "text", "text": "blocked by policy"}], "isError": True}
        else:
            reply["error"] = {"code": -32601, "message": "Method not found"}
        print(json.dumps(reply), flush=True)
    '''
    
    
    async def main() -> None:
        async with Client(StdioServerParameters(command=sys.executable, args=["-c", SERVER])) as client:
            print("negotiated:", client.protocol_version)
            await client.call_tool("echo", {"text": "hi"})
    
    
    anyio.run(main)

    On a 2025-11-25 session the same untagged reply is accepted as complete, as the spec says.

    mcp 2.3.0, mcp-types 2.3.0, pydantic 2.14.2, Python 3.12.13, macOS arm64.

    AI disclosure: I used Claude Code to search the SDK source, write the repro and run it on my machine; I reviewed the reproduction and output and can answer questions on it.

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