Follow-ups to #1610: de-draft 2026-07-28 terminology, renumber error codes, ProtocolVersion floor (#1671)

This commit is contained in:
Stephen Halter 2026-06-25 14:07:52 -07:00 • committed by GitHub
commit d6b1615988
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 785 additions and 898 deletions

View file

@ -76,9 +76,9 @@ internal sealed partial class AutoDetectingClientSessionTransport : ITransport
}
else if (await StreamableHttpClientSessionTransport.TryReadJsonRpcErrorAsync(response, cancellationToken).ConfigureAwait(false) is { } parsedError)
{
// A JSON-RPC error envelope in the body means the peer IS a Streamable HTTP server
// — it just rejected our specific request (e.g., -32004 UnsupportedProtocolVersion,
// -32003 MissingRequiredClientCapability, -32001 HeaderMismatch, or any other
// A JSON-RPC error envelope in the body means the peer IS a Streamable HTTP server.
// It just rejected our specific request (e.g., -32022 UnsupportedProtocolVersion,
// -32021 MissingRequiredClientCapability, -32020 HeaderMismatch, or any other
// application-level error). Don't fall back to SSE — that would mask the real signal
// and surface a misleading "session id required" error from the SSE GET path.
// Adopt the Streamable HTTP transport and throw the structured exception so the

View file

@ -1174,10 +1174,10 @@ public abstract partial class McpClient : McpSession
{
Name = requestParams.Name,
Arguments = requestParams.Arguments,
// The SEP-2663 Tasks extension is draft-only. On a legacy session, send a plain tools/call
// The SEP-2663 Tasks extension requires the 2026-07-28 or later protocol revision. On an older session, send a plain tools/call
// (no task capability envelope) so the server returns a direct CallToolResult and never
// creates a task.
Meta = IsDraftProtocol() ? GetMetaWithTaskCapability(requestParams.Meta) : requestParams.Meta,
Meta = IsJuly2026OrLaterProtocol() ? GetMetaWithTaskCapability(requestParams.Meta) : requestParams.Meta,
};
JsonRpcRequest jsonRpcRequest = new()
@ -1405,19 +1405,18 @@ public abstract partial class McpClient : McpSession
}
/// <summary>
/// Throws when the negotiated protocol version is not the draft revision. The SEP-2663 Tasks
/// extension is draft-only, and a task id only ever exists when the session negotiated draft, so
/// invoking <c>tasks/get</c>, <c>tasks/update</c>, or <c>tasks/cancel</c> on a legacy session is a
/// programming error rather than a recoverable protocol condition.
/// Throws when the negotiated protocol version does not support the SEP-2663 Tasks extension. Tasks
/// require the 2026-07-28 or later protocol revision, and a task id only ever exists when the session
/// negotiated such a revision, so invoking <c>tasks/get</c>, <c>tasks/update</c>, or <c>tasks/cancel</c>
/// on an older session is a programming error rather than a recoverable protocol condition.
/// </summary>
private void ThrowIfTasksNotSupported(string operationName)
{
if (!IsDraftProtocol())
if (!IsJuly2026OrLaterProtocol())
{
throw new InvalidOperationException(
$"'{operationName}' requires the draft protocol revision ('{DraftProtocolVersion}'). " +
$"The negotiated protocol version is '{NegotiatedProtocolVersion ?? "(none)"}'. " +
"The Tasks extension is only available under the draft revision.");
$"'{operationName}' requires a newer protocol revision that supports tasks. " +
$"The negotiated protocol version is '{NegotiatedProtocolVersion ?? "(none)"}'.");
}
}
}

View file

@ -289,21 +289,21 @@ internal sealed partial class McpClientImpl : McpClient
try
{
// The draft protocol revision (SEP-2575) is the default: there is no initialize
// The 2026-07-28 revision (SEP-2575) is the default: there is no initialize
// handshake. Instead, the client calls server/discover to learn the server's
// capabilities and then begins sending normal RPCs that carry protocolVersion /
// clientInfo / clientCapabilities in their per-request _meta. A null ProtocolVersion
// prefers the draft revision and automatically falls back to the legacy initialize
// handshake when the server doesn't support it. The legacy branch below runs only
// when the caller explicitly pins a non-draft version (opting out of draft).
if (_options.ProtocolVersion is null || _options.ProtocolVersion == McpSessionHandler.DraftProtocolVersion)
// prefers the 2026-07-28 revision and automatically falls back to the legacy initialize
// handshake when the server doesn't support it. The legacy branch below runs only when
// the caller explicitly pins a version that still supports Streamable HTTP sessions (opting out of the default).
if (_options.ProtocolVersion is null || McpHttpHeaders.IsJuly2026OrLaterProtocolVersion(_options.ProtocolVersion))
{
string draftVersion = McpSessionHandler.DraftProtocolVersion;
string preferredVersion = _options.ProtocolVersion ?? McpHttpHeaders.July2026ProtocolVersion;
// Eagerly set the negotiated version so InjectDraftMetaIfNeeded recognizes us as
// a draft client when SendRequestAsync is invoked for server/discover.
_negotiatedProtocolVersion = draftVersion;
_sessionHandler.NegotiatedProtocolVersion = draftVersion;
// Eagerly set the negotiated version so InjectRequestMetaIfNeeded recognizes us as being
// on the 2026-07-28 revision when SendRequestAsync is invoked for server/discover.
_negotiatedProtocolVersion = preferredVersion;
_sessionHandler.NegotiatedProtocolVersion = preferredVersion;
DiscoverResult? discoverResult = null;
bool fallbackToLegacy = false;
@ -331,7 +331,7 @@ internal sealed partial class McpClientImpl : McpClient
}
catch (UnsupportedProtocolVersionException ex)
{
// Spec-recognized modern-server signal: -32004 with data.supported[]. The server is
// Spec-recognized modern-server signal: -32022 with data.supported[]. The server is
// modern but doesn't speak our preferred version. Retry with a mutually supported
// version from data.supported[] instead of falling back to legacy initialize.
fallbackToLegacy = true;
@ -339,13 +339,13 @@ internal sealed partial class McpClientImpl : McpClient
}
catch (MissingRequiredClientCapabilityException)
{
// Spec-recognized modern-server signal: -32003. The server is modern but rejected
// Spec-recognized modern-server signal: -32021. The server is modern but rejected
// our capability set. Surface as-is (no fallback): the user must add capabilities.
throw;
}
catch (McpProtocolException ex) when (ex.ErrorCode == McpErrorCode.HeaderMismatch)
{
// Spec-recognized modern-server signal: -32001. The server is modern but rejected
// Spec-recognized modern-server signal: -32020. The server is modern but rejected
// our request envelope (e.g., the MCP-Protocol-Version HTTP header didn't match
// the body _meta.io.modelcontextprotocol/protocolVersion). Surface as-is (no
// fallback): falling back to legacy initialize wouldn't fix a malformed envelope.
@ -353,14 +353,14 @@ internal sealed partial class McpClientImpl : McpClient
}
catch (McpProtocolException)
{
// Per spec PR #2844, the fallback MUST NOT be keyed to a single error code —
// any non-modern JSON-RPC error from the probe indicates a legacy server.
// Per spec PR #2844, the fallback MUST NOT be keyed to a single error code.
// Any non-modern JSON-RPC error from the probe indicates a legacy server.
// Common causes include MethodNotFound from a server that has no
// server/discover handler, InvalidParams from a server confused by the
// SEP-2575 _meta envelope, ParseError from a server that can't handle our
// payload shape, or any other transport-defined error. The three modern-server
// signals (-32004 UnsupportedProtocolVersion, -32003
// MissingRequiredClientCapability, -32001 HeaderMismatch) are caught above and
// signals (-32022 UnsupportedProtocolVersion, -32021
// MissingRequiredClientCapability, -32020 HeaderMismatch) are caught above and
// never reach here.
fallbackToLegacy = true;
}
@ -371,10 +371,10 @@ internal sealed partial class McpClientImpl : McpClient
fallbackToLegacy = true;
}
if (discoverResult is not null && !discoverResult.SupportedVersions.Contains(draftVersion))
if (discoverResult is not null && !discoverResult.SupportedVersions.Contains(preferredVersion))
{
// Server is reachable and supports server/discover, but doesn't support the
// experimental version. Fall back to legacy initialize with the highest
// 2026-07-28 version. Fall back to legacy initialize with the highest
// mutually-supported version from supportedVersions[].
fallbackToLegacy = true;
serverSupportedVersions = discoverResult.SupportedVersions;
@ -390,15 +390,17 @@ internal sealed partial class McpClientImpl : McpClient
.Where(McpSessionHandler.SupportedProtocolVersions.Contains)
.OrderByDescending(v => v, StringComparer.Ordinal)
.FirstOrDefault()
?? McpSessionHandler.LatestProtocolVersion;
?? McpHttpHeaders.November2025ProtocolVersion;
// Honor MinProtocolVersion: refuse to fall back below the configured minimum.
// String.Compare is the spec's prescribed ordering for ISO-8601 date-based versions.
if (_options.MinProtocolVersion is { } minVersion &&
StringComparer.Ordinal.Compare(fallbackVersion, minVersion) < 0)
// A non-null ProtocolVersion is also the minimum: refuse to fall back below the
// explicitly requested version. String.Compare is the spec's prescribed ordering
// for ISO-8601 date-based versions.
if (_options.ProtocolVersion is { } pinnedVersion &&
StringComparer.Ordinal.Compare(fallbackVersion, pinnedVersion) < 0)
{
throw new McpException(
$"Server does not support the configured minimum protocol version '{minVersion}'. " +
$"The server does not support the requested protocol version '{pinnedVersion}'. " +
"Leave McpClientOptions.ProtocolVersion unset to allow automatic fallback to an older version. " +
(serverSupportedVersions is null
? "The server appears to be a legacy server that requires the deprecated initialize handshake."
: $"Server-supported versions: {string.Join(", ", serverSupportedVersions)}."));
@ -423,9 +425,9 @@ internal sealed partial class McpClientImpl : McpClient
else
{
// Legacy initialize handshake. Reached only when the caller explicitly pinned a
// non-draft ProtocolVersion (opting out of the draft default), so
// ProtocolVersion that still supports Streamable HTTP sessions (opting out of the default), so
// _options.ProtocolVersion is non-null here.
string requestProtocol = _options.ProtocolVersion ?? McpSessionHandler.LatestProtocolVersion;
string requestProtocol = _options.ProtocolVersion ?? McpHttpHeaders.November2025ProtocolVersion;
await PerformLegacyInitializeAsync(requestProtocol, initializationCts.Token).ConfigureAwait(false);
}
}
@ -475,13 +477,13 @@ internal sealed partial class McpClientImpl : McpClient
_serverInfo = initializeResponse.ServerInfo;
_serverInstructions = initializeResponse.Instructions;
// When the user explicitly pinned a legacy (non-draft) protocol version, the server MUST
// respect it. When the user pinned the draft version but we fell back (e.g., legacy server
// rejected server/discover), or when no version was pinned, accept any supported response.
// This is the spec-mandated behavior: a draft client must be able to downgrade to whatever
// legacy version the server advertises.
// When the user explicitly pinned a version that supports Streamable HTTP sessions, the server MUST respect it.
// When the user pinned the 2026-07-28 version but we fell back (e.g., legacy server rejected
// server/discover), or when no version was pinned, accept any supported response. This is the
// spec-mandated behavior: a 2026-07-28 client must be able to downgrade to whatever
// version the server advertises.
bool isResponseProtocolValid;
if (_options.ProtocolVersion is { } optionsProtocol && optionsProtocol != McpSessionHandler.DraftProtocolVersion)
if (_options.ProtocolVersion is { } optionsProtocol && !McpHttpHeaders.IsJuly2026OrLaterProtocolVersion(optionsProtocol))
{
isResponseProtocolValid = optionsProtocol == initializeResponse.ProtocolVersion;
}
@ -495,15 +497,6 @@ internal sealed partial class McpClientImpl : McpClient
throw new McpException($"Server protocol version mismatch. Expected {requestProtocol}, got {initializeResponse.ProtocolVersion}");
}
// If the user set a MinProtocolVersion, also enforce it against the negotiated response
// (the server could have downgraded further than the version we asked for).
if (_options.MinProtocolVersion is { } minVersion &&
StringComparer.Ordinal.Compare(initializeResponse.ProtocolVersion, minVersion) < 0)
{
throw new McpException(
$"Server negotiated protocol version '{initializeResponse.ProtocolVersion}' is below the configured minimum '{minVersion}'.");
}
_negotiatedProtocolVersion = initializeResponse.ProtocolVersion;
_sessionHandler.NegotiatedProtocolVersion = _negotiatedProtocolVersion;
@ -531,7 +524,7 @@ internal sealed partial class McpClientImpl : McpClient
_serverInstructions = resumeOptions.ServerInstructions;
_negotiatedProtocolVersion = resumeOptions.NegotiatedProtocolVersion
?? _options.ProtocolVersion
?? McpSessionHandler.LatestProtocolVersion;
?? McpHttpHeaders.November2025ProtocolVersion;
// Update session handler with the negotiated protocol version for telemetry
_sessionHandler.NegotiatedProtocolVersion = _negotiatedProtocolVersion;
@ -626,7 +619,7 @@ internal sealed partial class McpClientImpl : McpClient
const int maxRetries = 10;
InjectDraftMetaIfNeeded(request);
InjectRequestMetaIfNeeded(request);
for (int attempt = 0; attempt <= maxRetries; attempt++)
{
@ -665,7 +658,7 @@ internal sealed partial class McpClientImpl : McpClient
}
request = new JsonRpcRequest { Method = request.Method, Params = paramsObj, Context = request.Context };
InjectDraftMetaIfNeeded(request);
InjectRequestMetaIfNeeded(request);
}
else if (inputRequiredResult.RequestState is not null)
{
@ -675,7 +668,7 @@ internal sealed partial class McpClientImpl : McpClient
paramsObj.Remove("inputResponses");
request = new JsonRpcRequest { Method = request.Method, Params = paramsObj, Context = request.Context };
InjectDraftMetaIfNeeded(request);
InjectRequestMetaIfNeeded(request);
}
else
{
@ -695,25 +688,25 @@ internal sealed partial class McpClientImpl : McpClient
}
/// <summary>
/// Injects the draft-protocol per-request <c>_meta</c> fields (protocol version, client info,
/// client capabilities) into the request when this client is using the draft protocol revision
/// (SEP-2575). No-op for legacy clients.
/// Injects the 2026-07-28 protocol's per-request <c>_meta</c> fields (protocol version, client info,
/// client capabilities) into the request when this client negotiated the 2026-07-28 or later revision
/// (SEP-2575). No-op on a legacy session.
/// </summary>
private void InjectDraftMetaIfNeeded(JsonRpcRequest request)
private void InjectRequestMetaIfNeeded(JsonRpcRequest request)
{
if (!IsDraftProtocol())
if (!IsJuly2026OrLaterProtocol())
{
return;
}
// Initialize is never sent under the draft revision, but guard defensively in case a caller
// Initialize is never sent on a 2026-07-28 session, but guard defensively in case a caller
// routes it through here (e.g., during back-compat fallback negotiation).
if (request.Method == RequestMethods.Initialize)
{
return;
}
McpSessionHandler.InjectDraftMeta(
McpSessionHandler.InjectRequestMeta(
request,
_negotiatedProtocolVersion!,
_options.ClientInfo ?? DefaultImplementation,
@ -755,7 +748,7 @@ internal sealed partial class McpClientImpl : McpClient
/// <summary>Logs a warning if the session negotiated MRTR but the server sent a legacy JSON-RPC request.</summary>
private void WarnIfLegacyRequestOnMrtrSession(string method)
{
if (IsDraftProtocol())
if (IsJuly2026OrLaterProtocol())
{
LogLegacyRequestOnMrtrSession(_endpointName, method);
}
@ -764,7 +757,7 @@ internal sealed partial class McpClientImpl : McpClient
/// <summary>Logs a warning if the session did not negotiate MRTR but the server sent an InputRequiredResult.</summary>
private void WarnIfInputRequiredResultOnNonMrtrSession(string method)
{
if (!IsDraftProtocol())
if (!IsJuly2026OrLaterProtocol())
{
LogInputRequiredResultOnNonMrtrSession(_endpointName, method, _negotiatedProtocolVersion);
}

View file

@ -52,52 +52,23 @@ public sealed class McpClientOptions
/// </summary>
/// <remarks>
/// <para>
/// When non-<see langword="null"/>, this version is requested from the server. Setting it to a
/// legacy (non-draft) version such as <c>2025-11-25</c> opts out of the draft revision and forces
/// the <c>initialize</c> handshake; the handshake then fails if the server's negotiated version
/// does not match.
/// When <see langword="null"/> (the default), the client prefers the latest revision (<c>2026-07-28</c>),
/// which removed the <c>initialize</c> handshake and Streamable HTTP sessions. It probes with
/// <c>server/discover</c> and automatically falls back to the legacy <c>initialize</c> handshake,
/// downgrading to any version the server advertises, when the server does not support that revision.
/// </para>
/// <para>
/// When <see langword="null"/> (the default), the client prefers the draft revision
/// (<see cref="McpSession.DraftProtocolVersion"/>): it probes with <c>server/discover</c> and
/// automatically falls back to a legacy <c>initialize</c> handshake, downgrading to any version
/// the server advertises, when the server does not support the draft revision.
/// When non-<see langword="null"/>, this value is both the requested version and the minimum the client
/// will accept: the client requests exactly this version and refuses to downgrade below it, throwing an
/// <see cref="McpException"/> instead of falling back. Setting it to <c>2026-07-28</c> therefore disables
/// the automatic legacy-server fallback, and setting it to a version that still supports Streamable HTTP
/// sessions, such as <c>2025-11-25</c>, forces the <c>initialize</c> handshake and fails if the server
/// negotiates a different version. To try more than one version, leave this unset for automatic fallback
/// or retry the connection with a different value.
/// </para>
/// </remarks>
public string? ProtocolVersion { get; set; }
/// <summary>
/// Gets or sets the minimum protocol version the client will accept during version negotiation.
/// </summary>
/// <remarks>
/// <para>
/// When negotiating with a server that advertises multiple supported versions, or when falling back
/// to a legacy server, the client will refuse any version older than this minimum and surface an
/// <see cref="McpException"/> instead.
/// </para>
/// <para>
/// This is useful when the client requires features (such as the draft revision's removal of the
/// <c>initialize</c> handshake or <c>Mcp-Session-Id</c>) that are not available in older protocol
/// revisions. Because the client already prefers the draft revision by default, setting this to
/// <see cref="McpSession.DraftProtocolVersion"/> disables the automatic legacy-server fallback
/// that otherwise switches to the <c>initialize</c> handshake.
/// </para>
/// <para>
/// If <see langword="null"/> (the default), the client falls back to any version the server
/// advertises, including legacy versions such as 2025-11-25.
/// </para>
/// <example>
/// <code>
/// // The draft revision is already the default; pin the minimum to refuse the legacy fallback.
/// var clientOptions = new McpClientOptions
/// {
/// MinProtocolVersion = McpSession.DraftProtocolVersion,
/// };
/// </code>
/// </example>
/// </remarks>
public string? MinProtocolVersion { get; set; }
/// <summary>
/// Gets or sets a timeout for the client-server initialization handshake sequence.
/// </summary>
@ -128,10 +99,10 @@ public sealed class McpClientOptions
/// </value>
/// <remarks>
/// <para>
/// This timeout only has an effect when the client prefers the draft protocol revision &#8212; that is,
/// when <see cref="ProtocolVersion"/> is <see langword="null"/> (the default) or
/// <see cref="McpSession.DraftProtocolVersion"/>. In that mode the client first probes the server
/// with a <c>server/discover</c> request. A legacy server that predates the draft revision may
/// This timeout only has an effect when the client prefers the <c>2026-07-28</c> protocol revision, that is,
/// when <see cref="ProtocolVersion"/> is <see langword="null"/> (the default) or <c>2026-07-28</c>.
/// In that mode the client first probes the server with a
/// <c>server/discover</c> request. A legacy server that predates the <c>2026-07-28</c> revision may
/// silently drop the unknown method, so the probe is bounded by this timeout; when it elapses the
/// client concludes the server is legacy and falls back to the <c>initialize</c> handshake on the
/// same connection. When the caller pins a legacy <see cref="ProtocolVersion"/>, no probe is issued
@ -140,7 +111,7 @@ public sealed class McpClientOptions
/// <para>
/// The default is intentionally short so that dual-era clients fall back quickly against legacy
/// servers. Increase it for high-latency environments (for example, cold-start serverless peers or
/// satellite links) where a short probe could trigger the legacy fallback before a draft-capable
/// satellite links) where a short probe could trigger the legacy fallback before a server on the new revision
/// server has had a chance to respond. The probe is always also bounded by
/// <see cref="InitializationTimeout"/>, which governs the overall connect budget: if this value is
/// greater than or equal to <see cref="InitializationTimeout"/>, the probe is effectively bounded by

View file

@ -67,19 +67,19 @@ internal sealed partial class StreamableHttpClientSessionTransport : TransportBa
// Per spec PR #2844 (HTTP backwards compatibility), a 400 Bad Request that carries a
// JSON-RPC error envelope means the peer is signalling something application-level about
// our request. Surface ANY JSON-RPC error on a 400 as McpProtocolException so the
// connect-time logic can react — for example, the three modern draft-protocol error codes
// (-32004 UnsupportedProtocolVersion, -32003 MissingRequiredClientCapability,
// -32001 HeaderMismatch) lead to typed exceptions, while other codes (e.g. -32600 from
// legacy servers that don't understand the draft _meta envelope) become generic
// connect-time logic can react. For example, the three modern protocol error codes
// (-32022 UnsupportedProtocolVersion, -32021 MissingRequiredClientCapability,
// -32020 HeaderMismatch) lead to typed exceptions, while other codes (e.g. -32600 from
// legacy servers that don't understand the SEP-2575 _meta envelope) become generic
// McpProtocolException instances and trigger the fallback-to-legacy-initialize path.
// Other status codes (401 auth, 403 forbidden, 404 session-not-found, 5xx server) continue
// to surface as HttpRequestException to preserve back-compat with transport-layer behaviors.
// The three modern draft-protocol error codes are also surfaced for non-400 status codes
// for robustness — servers occasionally emit them with 4xx codes other than 400.
// The three modern protocol error codes are also surfaced for non-400 status codes
// for robustness. Servers occasionally emit them with 4xx codes other than 400.
if (!response.IsSuccessStatusCode &&
await TryReadJsonRpcErrorAsync(response, cancellationToken).ConfigureAwait(false) is { } parsedError &&
(response.StatusCode == HttpStatusCode.BadRequest ||
IsModernDraftErrorCode((McpErrorCode)parsedError.Error.Code)))
IsModernProtocolErrorCode((McpErrorCode)parsedError.Error.Code)))
{
throw McpSessionHandler.CreateRemoteProtocolExceptionFromError(parsedError);
}
@ -87,7 +87,7 @@ internal sealed partial class StreamableHttpClientSessionTransport : TransportBa
await response.EnsureSuccessStatusCodeWithResponseBodyAsync(cancellationToken).ConfigureAwait(false);
}
private static bool IsModernDraftErrorCode(McpErrorCode code) =>
private static bool IsModernProtocolErrorCode(McpErrorCode code) =>
code is McpErrorCode.UnsupportedProtocolVersion
or McpErrorCode.MissingRequiredClientCapability
or McpErrorCode.HeaderMismatch;
@ -144,9 +144,9 @@ internal sealed partial class StreamableHttpClientSessionTransport : TransportBa
LogTransportSendingMessageSensitive(message);
// Under the draft protocol revision (SEP-2575), every request carries its protocol version in
// Under the 2026-07-28 or later protocol revision (SEP-2575), every request carries its protocol version in
// _meta/io.modelcontextprotocol/protocolVersion (and the matching MCP-Protocol-Version HTTP
// header). Pick the value off the message so the first draft request (server/discover) can
// header). Pick the value off the message so the first request (server/discover) can
// include the header even before we've recorded a negotiated version from an initialize reply.
var protocolVersionForRequest = ExtractProtocolVersionFromMeta(message) ?? _negotiatedProtocolVersion;
@ -229,7 +229,7 @@ internal sealed partial class StreamableHttpClientSessionTransport : TransportBa
}
else if (rpcRequest.Method == RequestMethods.ServerDiscover && rpcResponseOrError is JsonRpcResponse)
{
// Under the draft protocol revision (SEP-2575), server/discover replaces the initialize
// Under the 2026-07-28 or later protocol revision (SEP-2575), server/discover replaces the initialize
// handshake. The transport caches the protocol version from the outgoing request's _meta
// so subsequent requests carry the matching MCP-Protocol-Version header without re-parsing.
_negotiatedProtocolVersion ??= ExtractProtocolVersionFromMeta(message);
@ -240,7 +240,7 @@ internal sealed partial class StreamableHttpClientSessionTransport : TransportBa
/// <summary>
/// Reads the protocol version from a request's <c>_meta/io.modelcontextprotocol/protocolVersion</c> field,
/// introduced by the draft protocol revision (SEP-2575). Returns <see langword="null"/> for messages that
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). Returns <see langword="null"/> for messages that
/// don't have that field.
/// </summary>
private static string? ExtractProtocolVersionFromMeta(JsonRpcMessage message)

View file

@ -23,7 +23,7 @@ public enum McpErrorCode
/// This error code is in the JSON-RPC implementation-defined server error range (<c>-32000</c> to <c>-32099</c>).
/// </para>
/// </remarks>
HeaderMismatch = -32001,
HeaderMismatch = -32020,
/// <summary>
/// Indicates that the requested resource could not be found.
@ -49,24 +49,24 @@ public enum McpErrorCode
/// </summary>
/// <remarks>
/// <para>
/// Introduced by the draft protocol revision (SEP-2575). The error data MUST include a
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). The error data MUST include a
/// <c>requiredCapabilities</c> object describing the capabilities the server requires from the client
/// to process the request. For HTTP, the response status code is <c>400 Bad Request</c>.
/// </para>
/// </remarks>
MissingRequiredClientCapability = -32003,
MissingRequiredClientCapability = -32021,
/// <summary>
/// Indicates that the request's declared protocol version is not supported by the server.
/// </summary>
/// <remarks>
/// <para>
/// Introduced by the draft protocol revision (SEP-2575). The error data MUST include a
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). The error data MUST include a
/// <c>supported</c> array of protocol version strings the server supports and the original
/// <c>requested</c> protocol version. For HTTP, the response status code is <c>400 Bad Request</c>.
/// </para>
/// </remarks>
UnsupportedProtocolVersion = -32004,
UnsupportedProtocolVersion = -32022,
/// <summary>
/// Indicates that URL-mode elicitation is required to complete the requested operation.

View file

@ -89,7 +89,7 @@ public static partial class McpJsonUtilities
// matching JSON Schema 2020-12: a schema may be either a JSON object (the usual form
// with keywords like "type", "properties", etc.) or a boolean (`true` matches anything,
// `false` matches nothing). Stricter keyword-level validation is intentionally not
// performed. Pre-2026-06-30 clients still receive the legacy wrapped wire shape — that
// performed. Pre-2026-07-28 clients still receive the legacy wrapped wire shape — that
// wiring lives in AIFunctionMcpServerTool.CreateStructuredResponse and McpServerImpl's
// listToolsHandler.
internal static bool IsValidToolOutputSchema(JsonElement element) =>

View file

@ -28,27 +28,6 @@ namespace ModelContextProtocol;
/// </remarks>
public abstract partial class McpSession : IAsyncDisposable
{
/// <summary>The latest stable protocol revision this SDK supports.</summary>
/// <remarks>
/// Set <see cref="McpClientOptions.ProtocolVersion"/> or <see cref="McpServerOptions.ProtocolVersion"/>
/// to this value to explicitly pin to the current stable revision instead of accepting whatever
/// the runtime negotiates.
/// </remarks>
public const string LatestProtocolVersion = McpSessionHandler.LatestProtocolVersion;
/// <summary>The in-progress draft protocol revision this SDK supports.</summary>
/// <remarks>
/// The draft revision removes the <c>initialize</c> handshake (SEP-2575) and the
/// <c>Mcp-Session-Id</c> header (SEP-2567), so it is sessionless on the wire and over HTTP is only
/// served when the server is stateless. A stateful (<c>HttpServerTransportOptions.Stateless = false</c>)
/// server refuses a sessionless draft request so that a dual-era client downgrades to the legacy
/// <c>initialize</c> flow. Clients prefer this revision by default and automatically fall back to the
/// legacy flow when the server does not support it; pin <see cref="McpClientOptions.ProtocolVersion"/>
/// to a legacy version to opt out, or set <see cref="McpClientOptions.MinProtocolVersion"/> to this
/// value to keep the draft preference while refusing the legacy fallback.
/// </remarks>
public const string DraftProtocolVersion = McpSessionHandler.DraftProtocolVersion;
/// <summary>Gets an identifier associated with the current MCP session.</summary>
/// <remarks>
/// Typically populated in transports supporting multiple sessions, such as Streamable HTTP or SSE.
@ -67,15 +46,16 @@ public abstract partial class McpSession : IAsyncDisposable
public abstract string? NegotiatedProtocolVersion { get; }
/// <summary>
/// Gets a value indicating whether the negotiated protocol version is the draft revision
/// (<see cref="DraftProtocolVersion"/>, which carries SEP-2575 + SEP-2567 + MRTR).
/// Gets a value indicating whether the negotiated protocol version is <c>2026-07-28</c> or later: the
/// revision that removed the <c>initialize</c> handshake (SEP-2575) and <c>Mcp-Session-Id</c> (SEP-2567)
/// and enabled MRTR (SEP-2322).
/// </summary>
/// <remarks>
/// Returns <see langword="false"/> when no version has been negotiated yet. This is the shared
/// definition of "is this peer speaking the draft revision" used by both the client and server.
/// definition of "is this peer speaking the 2026-07-28 or later revision" used by both the client and server.
/// </remarks>
internal bool IsDraftProtocol() =>
NegotiatedProtocolVersion == DraftProtocolVersion;
internal bool IsJuly2026OrLaterProtocol() =>
McpHttpHeaders.IsJuly2026OrLaterProtocolVersion(NegotiatedProtocolVersion);
/// <summary>
/// Sends a JSON-RPC request to the connected session and waits for a response.

View file

@ -28,22 +28,9 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
private static readonly Histogram<double> s_serverOperationDuration = Diagnostics.CreateDurationHistogram(
"mcp.server.operation.duration", "MCP request or notification duration as observed on the receiver from the time it was received until the result or ack is sent.");
/// <summary>The latest version of the protocol supported by this implementation.</summary>
internal const string LatestProtocolVersion = "2025-11-25";
/// <summary>
/// The draft protocol version (SEP-2575 + SEP-2567) that removes the <c>initialize</c> handshake
/// and <c>Mcp-Session-Id</c> and enables MRTR (Multi Round-Trip Requests) per SEP-2322.
/// Clients prefer this revision by default and fall back to the legacy <c>initialize</c> handshake
/// when the server does not support it; pin <see cref="McpClientOptions.ProtocolVersion"/> to a
/// legacy version to opt out. Servers remain reactive: with
/// <see cref="McpServerOptions.ProtocolVersion"/> left <see langword="null"/> they honor whichever
/// supported revision each peer requests, so a single server serves both draft and legacy clients.
/// </summary>
internal const string DraftProtocolVersion = "2026-07-28";
/// <summary>
/// All protocol versions supported by this implementation.
/// All protocol versions supported by this implementation. The version constants live on
/// <see cref="McpHttpHeaders"/> so the shared source file is the single source of truth.
/// Keep in sync with s_supportedProtocolVersions in StreamableHttpHandler.
/// </summary>
internal static readonly string[] SupportedProtocolVersions =
@ -51,8 +38,8 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
"2024-11-05",
"2025-03-26",
"2025-06-18",
LatestProtocolVersion,
DraftProtocolVersion,
McpHttpHeaders.November2025ProtocolVersion,
McpHttpHeaders.July2026ProtocolVersion,
];
/// <summary>
@ -66,7 +53,7 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
/// </remarks>
internal static bool SupportsPrimingEvent(string? protocolVersion)
{
const string MinResumabilityProtocolVersion = "2025-11-25";
const string MinResumabilityProtocolVersion = McpHttpHeaders.November2025ProtocolVersion;
if (protocolVersion is null)
{
@ -82,22 +69,19 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
/// </summary>
/// <param name="protocolVersion">The negotiated protocol version, or <c>null</c> if
/// negotiation has not completed.</param>
/// <returns><c>true</c> if the version is <c>"2026-06-30"</c> or later (including the
/// in-flight <c>"DRAFT-2026-06-v1"</c>, since <c>'D' &gt; '2'</c> ordinally); <c>false</c>
/// otherwise. A <c>false</c> return signals that the wire emission boundary must apply
/// the <c>{"result": &lt;value&gt;}</c> envelope expected by clients on protocol versions
/// that pre-date SEP-2106's widening of <c>outputSchema</c> to any JSON Schema 2020-12
/// document.</returns>
/// <returns><c>true</c> if the version is the <c>2026-07-28</c> revision or later, which is where
/// SEP-2106 widened <c>outputSchema</c> to any JSON Schema 2020-12 document; <c>false</c> otherwise.
/// A <c>false</c> return signals that the wire emission boundary must apply the
/// <c>{"result": &lt;value&gt;}</c> envelope expected by clients on protocol versions that pre-date
/// SEP-2106.</returns>
internal static bool SupportsNaturalOutputSchemas(string? protocolVersion)
{
const string MinNaturalOutputSchemasProtocolVersion = "2026-06-30";
if (protocolVersion is null)
{
return false;
}
return string.Compare(protocolVersion, MinNaturalOutputSchemasProtocolVersion, StringComparison.Ordinal) >= 0;
return string.Compare(protocolVersion, McpHttpHeaders.July2026ProtocolVersion, StringComparison.Ordinal) >= 0;
}
private readonly bool _isServer;
@ -169,17 +153,16 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
_outgoingMessageFilter = outgoingMessageFilter ?? (next => next);
_logger = logger;
// ping was removed in the draft protocol revision (SEP-2575). Under draft, return
// MethodNotFound; under legacy, the per-spec behavior is to always answer with PingResult.
// Liveness on draft sessions belongs to transport- and request-level timeouts, not a
// dedicated MCP RPC.
// ping was removed in the 2026-07-28 protocol revision (SEP-2575). On the 2026-07-28 or later version,
// return MethodNotFound; on an older version, the per-spec behavior is to always answer
// with PingResult. Liveness on those requests belongs to transport- and request-level
// timeouts, not a dedicated MCP RPC.
_requestHandlers.Set(
RequestMethods.Ping,
(request, jsonRpcRequest, cancellationToken) =>
{
string? perRequestVersion = jsonRpcRequest?.Context?.ProtocolVersion ?? NegotiatedProtocolVersion;
if (perRequestVersion is not null &&
StringComparer.Ordinal.Compare(perRequestVersion, DraftProtocolVersion) >= 0)
if (McpHttpHeaders.IsJuly2026OrLaterProtocolVersion(perRequestVersion))
{
throw new McpProtocolException(
$"Method '{RequestMethods.Ping}' is not available on protocol version '{perRequestVersion}'.",
@ -426,7 +409,7 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
private async Task HandleMessageAsync(JsonRpcMessage message, CancellationToken cancellationToken)
{
// Project the draft-protocol per-request _meta fields onto the message context before any
// Project the 2026-07-28 protocol's per-request _meta fields onto the message context before any
// filters run so they (and downstream handlers) can read client info / capabilities /
// protocol version / log level without re-parsing.
if (_isServer && message is JsonRpcRequest incomingRequest)
@ -570,7 +553,7 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
}
/// <summary>
/// Reads the draft-protocol per-request <c>_meta</c> fields off the request and projects them onto
/// Reads the 2026-07-28 protocol's per-request <c>_meta</c> fields off the request and projects them onto
/// <see cref="JsonRpcMessage.Context"/> so they're available without re-parsing throughout the pipeline.
/// </summary>
/// <remarks>
@ -599,8 +582,8 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
{
// If a transport-level header (e.g., the Streamable HTTP MCP-Protocol-Version header) already
// populated this, validate the body _meta matches per SEP-2575. A disagreement is reported with
// -32001 HeaderMismatch (the same code used for the Mcp-Method/Mcp-Name header-vs-body checks),
// which conformant draft clients recognize as a modern-server signal and surface as-is rather
// -32020 HeaderMismatch (the same code used for the Mcp-Method/Mcp-Name header-vs-body checks),
// which conformant 2026-07-28 clients recognize as a modern-server signal and surface as-is rather
// than mistaking it for a legacy server and falling back to the initialize handshake.
if (context.ProtocolVersion is { } existing && !string.Equals(existing, protocolVersionValue, StringComparison.Ordinal))
{
@ -629,16 +612,16 @@ internal sealed partial class McpSessionHandler : IAsyncDisposable
}
/// <summary>
/// Injects the draft-protocol per-request <c>_meta</c> fields into an outgoing request.
/// Injects the 2026-07-28 protocol's per-request <c>_meta</c> fields into an outgoing request.
/// Protocol version and client info overwrite any existing values; client capabilities are merged
/// so per-request capability opt-ins already present in the envelope are preserved.
/// </summary>
/// <remarks>
/// Used by <see cref="Client.McpClient"/> in draft mode to carry protocol version, client info, and
/// client capabilities on every outgoing request (replacing what the legacy <c>initialize</c> handshake
/// previously negotiated once).
/// Used by <see cref="Client.McpClient"/> on a 2026-07-28 or later session to carry protocol version, client
/// info, and client capabilities on every outgoing request (replacing what the legacy
/// <c>initialize</c> handshake previously negotiated once).
/// </remarks>
internal static void InjectDraftMeta(
internal static void InjectRequestMeta(
JsonRpcRequest request,
string protocolVersion,
Implementation clientInfo,

View file

@ -10,9 +10,9 @@ namespace ModelContextProtocol;
/// in the request's per-request <c>_meta/io.modelcontextprotocol/clientCapabilities</c> field.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). Servers throw this exception when a handler cannot
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). Servers throw this exception when a handler cannot
/// proceed because the client did not declare a required capability for the request. The exception is converted
/// to a JSON-RPC error response with code <see cref="McpErrorCode.MissingRequiredClientCapability"/> (<c>-32003</c>)
/// to a JSON-RPC error response with code <see cref="McpErrorCode.MissingRequiredClientCapability"/> (<c>-32021</c>)
/// and a <see cref="MissingRequiredClientCapabilityErrorData"/> payload.
/// </remarks>
public sealed class MissingRequiredClientCapabilityException : McpProtocolException

View file

@ -8,7 +8,7 @@ namespace ModelContextProtocol.Protocol;
/// The discover RPC takes no payload of its own. Per-request metadata
/// (protocol version, client info, client capabilities) flows through the
/// inherited <see cref="RequestParams.Meta"/> property under the
/// <c>io.modelcontextprotocol/*</c> keys defined by the draft protocol revision (SEP-2575).
/// <c>io.modelcontextprotocol/*</c> keys defined by the 2026-07-28 protocol revision (SEP-2575).
/// </para>
/// </remarks>
public sealed class DiscoverRequestParams : RequestParams

View file

@ -7,7 +7,7 @@ namespace ModelContextProtocol.Protocol;
/// </summary>
/// <remarks>
/// <para>
/// Introduced by the draft protocol revision (SEP-2575) as the canonical way for a client
/// Introduced by the 2026-07-28 protocol revision (SEP-2575) as the canonical way for a client
/// to learn what a server supports without performing the legacy <c>initialize</c> handshake.
/// </para>
/// </remarks>
@ -47,8 +47,9 @@ public sealed class DiscoverResult : Result, ICacheableResult
/// <inheritdoc />
/// <remarks>
/// Spec PR #2855 makes <c>ttlMs</c> a required field on <see cref="DiscoverResult"/>. The
/// server emits a safe default (<see cref="TimeSpan.Zero"/>, i.e. immediately stale) on
/// draft sessions when the application has not set an explicit value, preserving today's
/// server emits a safe default (<see cref="TimeSpan.Zero"/>, i.e. immediately stale) for the
/// 2026-07-28 and later protocol revisions when the application has not set an explicit value,
/// preserving today's
/// "do not cache" behavior while satisfying the wire requirement.
/// </remarks>
[JsonPropertyName("ttlMs")]
@ -58,7 +59,8 @@ public sealed class DiscoverResult : Result, ICacheableResult
/// <inheritdoc />
/// <remarks>
/// Spec PR #2855 makes <c>cacheScope</c> a required field on <see cref="DiscoverResult"/>. The
/// server emits a safe default (<see cref="Protocol.CacheScope.Private"/>) on draft sessions
/// server emits a safe default (<see cref="Protocol.CacheScope.Private"/>) for the 2026-07-28 and
/// later protocol revisions
/// when the application has not set an explicit value.
/// </remarks>
[JsonPropertyName("cacheScope")]

View file

@ -91,7 +91,7 @@ public sealed class JsonRpcMessageContext
/// <c>_meta/io.modelcontextprotocol/clientInfo</c> field.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). When the request was made under the draft revision,
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). When the request was made under the 2026-07-28 or later revision,
/// the server uses this in lieu of the value previously captured during the <c>initialize</c> handshake.
/// </remarks>
public Implementation? ClientInfo { get; set; }
@ -101,7 +101,7 @@ public sealed class JsonRpcMessageContext
/// <c>_meta/io.modelcontextprotocol/clientCapabilities</c> field.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). Per the spec, the server MUST NOT infer client
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). Per the spec, the server MUST NOT infer client
/// capabilities from previous requests; the authoritative value is the one declared on each request.
/// </remarks>
public ClientCapabilities? ClientCapabilities { get; set; }
@ -111,7 +111,7 @@ public sealed class JsonRpcMessageContext
/// <c>_meta/io.modelcontextprotocol/logLevel</c> field.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). Replaces the legacy
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). Replaces the legacy
/// <see cref="RequestMethods.LoggingSetLevel"/> RPC. When absent, the server MUST NOT emit log notifications
/// for the request.
/// </remarks>

View file

@ -9,9 +9,9 @@ public static class MetaKeys
/// The metadata key used to carry the MCP protocol version in a request's <c>_meta</c> field.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). For HTTP transports, the value MUST
/// match the <c>MCP-Protocol-Version</c> header. Servers reject mismatched versions with
/// <see cref="McpErrorCode.UnsupportedProtocolVersion"/>.
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). For HTTP transports, the value MUST
/// match the <c>MCP-Protocol-Version</c> header. Servers reject a header/body mismatch with
/// <see cref="McpErrorCode.HeaderMismatch"/>.
/// </remarks>
public const string ProtocolVersion = "io.modelcontextprotocol/protocolVersion";
@ -19,7 +19,7 @@ public static class MetaKeys
/// The metadata key used to identify the client software in a request's <c>_meta</c> field.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). Carries an <see cref="Protocol.Implementation"/>
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). Carries an <see cref="Protocol.Implementation"/>
/// describing the client; replaces the <c>clientInfo</c> previously sent only with <c>initialize</c>.
/// </remarks>
public const string ClientInfo = "io.modelcontextprotocol/clientInfo";
@ -28,7 +28,7 @@ public static class MetaKeys
/// The metadata key used to declare client capabilities in a request's <c>_meta</c> field.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). Carries a <see cref="Protocol.ClientCapabilities"/>
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). Carries a <see cref="Protocol.ClientCapabilities"/>
/// describing what optional features the client supports for this specific request. Servers MUST NOT
/// infer capabilities from previous requests.
/// </remarks>
@ -38,7 +38,7 @@ public static class MetaKeys
/// The metadata key used to specify the desired log level for a request's resulting log notifications.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). Carries a <see cref="Protocol.LoggingLevel"/>.
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). Carries a <see cref="Protocol.LoggingLevel"/>.
/// Replaces the legacy <see cref="RequestMethods.LoggingSetLevel"/> RPC. When absent, the server
/// MUST NOT send log notifications for the request.
/// </remarks>
@ -49,7 +49,7 @@ public static class MetaKeys
/// <see cref="RequestMethods.SubscriptionsListen"/> subscription.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). Allows clients to demultiplex notifications
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). Allows clients to demultiplex notifications
/// belonging to different subscriptions on a shared channel (especially STDIO).
/// </remarks>
public const string SubscriptionId = "io.modelcontextprotocol/subscriptionId";

View file

@ -6,7 +6,7 @@ namespace ModelContextProtocol.Protocol;
/// Represents the payload for the <see cref="McpErrorCode.MissingRequiredClientCapability"/> JSON-RPC error.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). When a server cannot fulfill a request because
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). When a server cannot fulfill a request because
/// the client did not declare a required capability in its per-request
/// <c>_meta/io.modelcontextprotocol/clientCapabilities</c> field, it MUST return this error so clients
/// know which capabilities to advertise on a retry.

View file

@ -159,7 +159,7 @@ public static class NotificationMethods
/// response stream to indicate which notification types the server agreed to deliver.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). The notification's params mirror the shape
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). The notification's params mirror the shape
/// of the requested notifications and include only the entries the server actually supports.
/// </remarks>
public const string SubscriptionsAcknowledgedNotification = "notifications/subscriptions/acknowledged";

View file

@ -158,7 +158,7 @@ public static class RequestMethods
/// </summary>
/// <remarks>
/// <para>
/// This RPC is introduced in the draft protocol revision (SEP-2575) as the canonical way for a client
/// This RPC is introduced in the 2026-07-28 protocol revision (SEP-2575) as the canonical way for a client
/// to learn what a server supports without performing the legacy <c>initialize</c> handshake.
/// </para>
/// <para>
@ -166,7 +166,7 @@ public static class RequestMethods
/// information, and optional usage instructions.
/// </para>
/// <para>
/// Servers SHOULD implement this method. Legacy clients MAY ignore it. Draft-revision clients
/// Servers SHOULD implement this method. Legacy clients MAY ignore it. Clients on the 2026-07-28 revision
/// typically call this once during connection establishment.
/// </para>
/// </remarks>
@ -178,7 +178,7 @@ public static class RequestMethods
/// </summary>
/// <remarks>
/// <para>
/// This RPC is introduced in the draft protocol revision (SEP-2575) and replaces the unsolicited
/// This RPC is introduced in the 2026-07-28 protocol revision (SEP-2575) and replaces the unsolicited
/// HTTP GET endpoint and the legacy <see cref="ResourcesSubscribe"/> / <see cref="ResourcesUnsubscribe"/>
/// request methods.
/// </para>

View file

@ -7,7 +7,7 @@ namespace ModelContextProtocol.Protocol;
/// </summary>
/// <remarks>
/// <para>
/// Introduced by the draft protocol revision (SEP-2575). This notification is the first message on a
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). This notification is the first message on a
/// <see cref="RequestMethods.SubscriptionsListen"/> response stream and informs the client which
/// subset of requested notification types the server has agreed to deliver.
/// </para>

View file

@ -7,7 +7,7 @@ namespace ModelContextProtocol.Protocol;
/// </summary>
/// <remarks>
/// <para>
/// Introduced by the draft protocol revision (SEP-2575). The client uses this request to open a
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). The client uses this request to open a
/// long-lived channel for receiving notifications outside the context of a specific request.
/// </para>
/// <para>

View file

@ -6,7 +6,7 @@ namespace ModelContextProtocol.Protocol;
/// Represents the payload for the <see cref="McpErrorCode.UnsupportedProtocolVersion"/> JSON-RPC error.
/// </summary>
/// <remarks>
/// Introduced by the draft protocol revision (SEP-2575). When a server receives a request whose
/// Introduced by the 2026-07-28 protocol revision (SEP-2575). When a server receives a request whose
/// declared protocol version it does not implement, it MUST return this error so clients can
/// fall back to a mutually supported version.
/// </remarks>

Some files were not shown because too many files have changed in this diff Show more