Skip to content

Commit e0b058f

Browse files
authored
Improve protocol version handling (#468)
Right now by default, the client and server hardcode the initial spec version, and if there's a mismatch, the request fails. With this change, by default both client and server are allowed to float to any supported version.
1 parent 703b0fe commit e0b058f

File tree

8 files changed

+45
-12
lines changed

8 files changed

+45
-12
lines changed

src/ModelContextProtocol.Core/Client/McpClient.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,12 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default)
129129
try
130130
{
131131
// Send initialize request
132+
string requestProtocol = _options.ProtocolVersion ?? McpSession.LatestProtocolVersion;
132133
var initializeResponse = await this.SendRequestAsync(
133134
RequestMethods.Initialize,
134135
new InitializeRequestParams
135136
{
136-
ProtocolVersion = _options.ProtocolVersion,
137+
ProtocolVersion = requestProtocol,
137138
Capabilities = _options.Capabilities ?? new ClientCapabilities(),
138139
ClientInfo = _options.ClientInfo ?? DefaultImplementation,
139140
},
@@ -154,10 +155,13 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default)
154155
_serverInstructions = initializeResponse.Instructions;
155156

156157
// Validate protocol version
157-
if (initializeResponse.ProtocolVersion != _options.ProtocolVersion)
158+
bool isResponseProtocolValid =
159+
_options.ProtocolVersion is { } optionsProtocol ? optionsProtocol == initializeResponse.ProtocolVersion :
160+
McpSession.SupportedProtocolVersions.Contains(initializeResponse.ProtocolVersion);
161+
if (!isResponseProtocolValid)
158162
{
159-
LogServerProtocolVersionMismatch(EndpointName, _options.ProtocolVersion, initializeResponse.ProtocolVersion);
160-
throw new McpException($"Server protocol version mismatch. Expected {_options.ProtocolVersion}, got {initializeResponse.ProtocolVersion}");
163+
LogServerProtocolVersionMismatch(EndpointName, requestProtocol, initializeResponse.ProtocolVersion);
164+
throw new McpException($"Server protocol version mismatch. Expected {requestProtocol}, got {initializeResponse.ProtocolVersion}");
161165
}
162166

163167
// Send initialized notification

src/ModelContextProtocol.Core/Client/McpClientOptions.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,18 @@ public class McpClientOptions
3434
/// Gets or sets the protocol version to request from the server, using a date-based versioning scheme.
3535
/// </summary>
3636
/// <remarks>
37+
/// <para>
3738
/// The protocol version is a key part of the initialization handshake. The client and server must
38-
/// agree on a compatible protocol version to communicate successfully. If the server doesn't support
39-
/// the requested version, it will respond with a version mismatch error.
39+
/// agree on a compatible protocol version to communicate successfully.
40+
/// </para>
41+
/// <para>
42+
/// If non-<see langword="null"/>, this version will be sent to the server, and the handshake
43+
/// will fail if the version in the server's response does not match this version.
44+
/// If <see langword="null"/>, the client will request the latest version supported by the server
45+
/// but will allow any supported version that the server advertizes in its response.
46+
/// </para>
4047
/// </remarks>
41-
public string ProtocolVersion { get; set; } = "2024-11-05";
48+
public string? ProtocolVersion { get; set; }
4249

4350
/// <summary>
4451
/// Gets or sets a timeout for the client-server initialization handshake sequence.

src/ModelContextProtocol.Core/McpSession.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ internal sealed partial class McpSession : IDisposable
2828
private static readonly Histogram<double> s_serverOperationDuration = Diagnostics.CreateDurationHistogram(
2929
"mcp.server.operation.duration", "Measures the duration of inbound message processing.", longBuckets: false);
3030

31+
/// <summary>The latest version of the protocol supported by this implementation.</summary>
32+
internal const string LatestProtocolVersion = "2025-03-26";
33+
34+
/// <summary>All protocol versions supported by this implementation.</summary>
35+
internal static readonly string[] SupportedProtocolVersions =
36+
[
37+
"2024-11-05",
38+
LatestProtocolVersion,
39+
];
40+
3141
private readonly bool _isServer;
3242
private readonly string _transportKind;
3343
private readonly ITransport _transport;

src/ModelContextProtocol.Core/Protocol/PaginatedRequest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace ModelContextProtocol.Protocol;
66
/// Provides a base class for paginated requests.
77
/// </summary>
88
/// <remarks>
9-
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
9+
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
1010
/// </remarks>
1111
public class PaginatedRequestParams : RequestParams
1212
{

src/ModelContextProtocol.Core/Server/McpServer.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,20 @@ private void ConfigureInitialize(McpServerOptions options)
161161
UpdateEndpointNameWithClientInfo();
162162
GetSessionOrThrow().EndpointName = EndpointName;
163163

164+
// Negotiate a protocol version. If the server options provide one, use that.
165+
// Otherwise, try to use whatever the client requested as long as it's supported.
166+
// If it's not supported, fall back to the latest supported version.
167+
string? protocolVersion = options.ProtocolVersion;
168+
if (protocolVersion is null)
169+
{
170+
protocolVersion = request?.ProtocolVersion is string clientProtocolVersion && McpSession.SupportedProtocolVersions.Contains(clientProtocolVersion) ?
171+
clientProtocolVersion :
172+
McpSession.LatestProtocolVersion;
173+
}
174+
164175
return new InitializeResult
165176
{
166-
ProtocolVersion = options.ProtocolVersion,
177+
ProtocolVersion = protocolVersion,
167178
Instructions = options.ServerInstructions,
168179
ServerInfo = options.ServerInfo ?? DefaultImplementation,
169180
Capabilities = ServerCapabilities ?? new(),

src/ModelContextProtocol.Core/Server/McpServerOptions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@ public class McpServerOptions
3232
/// <remarks>
3333
/// The protocol version defines which features and message formats this server supports.
3434
/// This uses a date-based versioning scheme in the format "YYYY-MM-DD".
35+
/// If <see langword="null"/>, the server will advertize to the client the version requested
36+
/// by the client if that version is known to be supported, and otherwise will advertize the latest
37+
/// version supported by the server.
3538
/// </remarks>
36-
public string ProtocolVersion { get; set; } = "2024-11-05";
39+
public string? ProtocolVersion { get; set; }
3740

3841
/// <summary>
3942
/// Gets or sets a timeout used for the client-server initialization handshake sequence.

tests/ModelContextProtocol.TestServer/Program.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ private static async Task Main(string[] args)
4646
Logging = ConfigureLogging(),
4747
Completions = ConfigureCompletions(),
4848
},
49-
ProtocolVersion = "2024-11-05",
5049
ServerInstructions = "This is a test server with only stub functionality",
5150
};
5251

tests/ModelContextProtocol.TestSseServer/Program.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ private static void ConfigureOptions(McpServerOptions options)
3434
Resources = new(),
3535
Prompts = new(),
3636
};
37-
options.ProtocolVersion = "2024-11-05";
3837
options.ServerInstructions = "This is a test server with only stub functionality";
3938

4039
Console.WriteLine("Registering handlers.");

0 commit comments

Comments
 (0)