Skip to content

MCP Protocol-Version Ceiling for the C# Client SDK #1868

Description

@anushree1808

Summary

Add an optional protocol-version ceiling to McpClientOptions. The option would mean:

Negotiate this MCP protocol version, or the highest mutually supported lower version.

This differs from the existing exact ProtocolVersion option. An exact version remains a strict pin; the proposed ceiling establishes a maximum while allowing compatible downgrade negotiation.

Proposed API

The exact property name is open for discussion. One possible shape is:

var options = new McpClientOptions
{
    MaximumProtocolVersion = "2025-11-25"
};

MaximumProtocolVersion would be optional and mutually exclusive with an exact ProtocolVersion pin.

Proposed Semantics

When MaximumProtocolVersion is set, the client should:

  1. Never negotiate a version newer than the configured ceiling.
  2. Prefer the ceiling when the server supports it.
  3. Otherwise negotiate the highest mutually supported older version.
  4. Fail with a clear protocol-negotiation error when no mutually supported version exists.
  5. Expose the selected value through NegotiatedProtocolVersion, as it does today.

For example, with a ceiling of 2025-11-25:

  • A server supporting 2025-11-25 selects 2025-11-25.
  • A server supporting only 2025-06-18 selects 2025-06-18.
  • A server supporting only a newer, incompatible version fails negotiation rather than silently exceeding the ceiling.

Existing behavior should remain unchanged when the option is absent.

Current Limitation

Today, callers have two choices:

  • Leave ProtocolVersion unset and rely on the SDK's default discovery and fallback behavior. This may negotiate the newest server-supported version, even when the application cannot safely use that version.
  • Set ProtocolVersion to pin one exact version. If the server cannot serve that exact version, connection establishment fails even when both sides support an older compatible version.

There is no way to express: “Use this version if possible, but negotiate an older mutually supported version when necessary.”

Current Workaround and Pitfalls

A caller that needs legacy-first, flexible negotiation must currently manipulate discovery behavior—for example, configure a roughly one-microsecond server/discover probe timeout so discovery is effectively cancelled and the SDK falls back to initialize without an exact protocol pin.

This workaround is fragile because:

  • It depends on timeout and fallback implementation details rather than an explicit negotiation contract.
  • One microsecond is below practical timer and network resolution, so behavior is indirect rather than deterministic by design.
  • It introduces avoidable cancellation, exception, retry, latency, and telemetry noise.
  • It can be affected by future SDK changes to discovery or fallback handling.
  • The intent is difficult for maintainers to understand and easy to regress.
  • Pinning instead is not an equivalent workaround because it prevents negotiation with otherwise compatible older servers.

Why This Is Beneficial

A protocol ceiling is useful whenever an application supports a bounded range of MCP revisions rather than exactly one revision or every revision known to the SDK. Common cases include:

  • Gradual protocol rollouts where the client application has not enabled newer wire semantics yet.
  • Aggregators, gateways, and proxies that must preserve an inbound or configured compatibility contract while connecting to heterogeneous downstream servers.
  • Long-lived clients that need interoperability with servers deployed on different MCP revisions.
  • Applications that support several older revisions but must fail closed against newer revisions whose capabilities or payload semantics have not been validated.
  • Compatibility testing across mixed-version server fleets.

The feature would make negotiation policy explicit, deterministic, observable, and independent of transport timing hacks.

Compatibility Considerations

  • Keep ProtocolVersion as the exact-version pin with its current behavior.
  • Treat MaximumProtocolVersion as optional; omitting both properties preserves current automatic negotiation.
  • Reject configuration that sets both an exact version and a ceiling, unless precedence is explicitly documented.
  • Compare versions using the SDK's supported MCP protocol-version ordering, not lexical string ordering.
  • Document how the ceiling interacts with server/discover, initialize, cached versions, and transport fallback.
  • Ensure the client never sends or accepts a negotiated version above the configured ceiling.

Acceptance Criteria

  • A client can configure a maximum MCP protocol version without pinning an exact version.
  • The SDK negotiates the ceiling or the highest mutually supported lower version.
  • Servers supporting only newer versions do not cause the ceiling to be exceeded.
  • Servers supporting a compatible older version connect successfully.
  • No-overlap failures produce a clear, actionable exception.
  • Existing default negotiation and exact-pin behavior remain backward compatible.
  • Unit and integration tests cover ceiling match, downgrade, no overlap, malformed server responses, discovery fallback, and conflicts with exact pinning.

Activity

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

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions