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:
- Never negotiate a version newer than the configured ceiling.
- Prefer the ceiling when the server supports it.
- Otherwise negotiate the highest mutually supported older version.
- Fail with a clear protocol-negotiation error when no mutually supported version exists.
- 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.
Summary
Add an optional protocol-version ceiling to
McpClientOptions. The option would mean:This differs from the existing exact
ProtocolVersionoption. 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:
MaximumProtocolVersionwould be optional and mutually exclusive with an exactProtocolVersionpin.Proposed Semantics
When
MaximumProtocolVersionis set, the client should:NegotiatedProtocolVersion, as it does today.For example, with a ceiling of
2025-11-25:2025-11-25selects2025-11-25.2025-06-18selects2025-06-18.Existing behavior should remain unchanged when the option is absent.
Current Limitation
Today, callers have two choices:
ProtocolVersionunset 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.ProtocolVersionto 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/discoverprobe timeout so discovery is effectively cancelled and the SDK falls back toinitializewithout an exact protocol pin.This workaround is fragile because:
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:
The feature would make negotiation policy explicit, deterministic, observable, and independent of transport timing hacks.
Compatibility Considerations
ProtocolVersionas the exact-version pin with its current behavior.MaximumProtocolVersionas optional; omitting both properties preserves current automatic negotiation.server/discover,initialize, cached versions, and transport fallback.Acceptance Criteria