Skip to content

Client rejects valid server protocol version during negotiation when ProtocolVersion is explicitly set #1536

@mikekistler

Description

@mikekistler

Bug Description

When McpClientOptions.ProtocolVersion is explicitly set, the client requires the server to respond with that exact version. If the server responds with a different but supported version (e.g., negotiating down), the client throws McpException: Server protocol version mismatch.

This violates proper MCP protocol negotiation, where the server may respond with any version it supports — which may be lower than the version the client requested.

Reproduction

Set McpClientOptions.ProtocolVersion = "DRAFT-2026-v1" and connect to a server that responds with "2025-11-25" (a valid supported version). The client throws:

McpException: Server protocol version mismatch. Expected DRAFT-2026-v1, got 2025-11-25

This was discovered when running the client conformance tests with MCP_CONFORMANCE_PROTOCOL_VERSION=DRAFT-2026-v1. 18 of 34 tests failed because the conformance mock server responds with "2025-11-25" for scenarios originally tagged for that version, even when the test suite runs under DRAFT-2026-v1.

Root Cause

In McpClientImpl.cs, the protocol version validation uses a ternary that enforces an exact match when ProtocolVersion is explicitly set:

bool isResponseProtocolValid =
    _options.ProtocolVersion is { } optionsProtocol ? optionsProtocol == initializeResponse.ProtocolVersion :
    McpSessionHandler.SupportedProtocolVersions.Contains(initializeResponse.ProtocolVersion);

Expected Behavior

The client should accept any server response version that is in SupportedProtocolVersions, regardless of whether ProtocolVersion was explicitly set. The explicit version should still be accepted as a fallback (for forward compatibility with versions not yet in the supported list).

Fix

Change the validation to:

bool isResponseProtocolValid =
    McpSessionHandler.SupportedProtocolVersions.Contains(initializeResponse.ProtocolVersion) ||
    (_options.ProtocolVersion is { } optionsProtocol && optionsProtocol == initializeResponse.ProtocolVersion);

Why This Was Not Caught

  1. No conformance scenario explicitly tests protocol version downgrade negotiation.
  2. The SDK's own ReturnsNegotiatedProtocolVersion test uses ClientServerTestBase where the server always echoes back the client's requested version.
  3. The bug only manifests when ProtocolVersion is explicitly set and the server responds with a different (but supported) version.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions