Skip to content

Commit bd5c624

Browse files
halter73Copilot
andcommitted
Rename ExperimentalProtocolVersion to ProtocolVersion + sync draft version to 2026-07-28
- Drop ExperimentalProtocolVersion from McpClientOptions/McpServerOptions and use ProtocolVersion == McpSessionHandler.DraftProtocolVersion as the draft predicate. - McpHttpHeaders.DraftProtocolVersion and McpSessionHandler.DraftProtocolVersion are now `2026-07-28` (matches the published spec) instead of `DRAFT-2026-v1`. - Server always advertises draft via SupportedProtocolVersions; ConfigureDiscover no longer takes an opt-in flag. - Drop _serverHasExperimental machinery from DraftConnectionTests; the test class now relies on the unconditional draft support. - Skip Mrtr_MixedExceptionAndAwaitStyle(experimentalClient: True) over Streamable HTTP; the await-style path needs session affinity and draft HTTP is sessionless. Stdio coverage stays in DraftProtocolBackcompatTests. - Sweep the remaining DRAFT-2026-v1 / 2026-06-XX literals across docs and tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 64aaf70 commit bd5c624

32 files changed

Lines changed: 165 additions & 199 deletions

docs/concepts/elicitation/elicitation.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,10 @@ Here's an example implementation of how a console application might handle elici
172172

173173
### Multi Round-Trip Requests (MRTR)
174174

175-
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `DRAFT-2026-v1`. Under the draft protocol, the server-to-client `elicitation/create` request method is removed; the recommended way to ask the user for input from a server handler is to throw <xref:ModelContextProtocol.Protocol.InputRequiredException> and let the SDK emit an <xref:ModelContextProtocol.Protocol.InputRequiredResult> on the wire.
175+
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `2026-07-28`. Under the draft protocol, the server-to-client `elicitation/create` request method is removed; the recommended way to ask the user for input from a server handler is to throw <xref:ModelContextProtocol.Protocol.InputRequiredException> and let the SDK emit an <xref:ModelContextProtocol.Protocol.InputRequiredResult> on the wire.
176176

177177
> [!IMPORTANT]
178-
> `ElicitAsync` throws `InvalidOperationException("Elicitation is not supported in stateless mode.")` whenever the server is running stateless — which includes every Streamable HTTP server under `DRAFT-2026-v1` once that revision is forced to stateless-only in a future PR. Stdio servers and current-protocol stateful Streamable HTTP servers continue to work via the legacy server-to-client `elicitation/create` request flow. For code that needs to run on stateless servers — including all `DRAFT-2026-v1` Streamable HTTP servers going forward — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
178+
> `ElicitAsync` throws `InvalidOperationException("Elicitation is not supported in stateless mode.")` whenever the server is running stateless — which includes every Streamable HTTP server under `2026-07-28` once that revision is forced to stateless-only in a future PR. Stdio servers and current-protocol stateful Streamable HTTP servers continue to work via the legacy server-to-client `elicitation/create` request flow. For code that needs to run on stateless servers — including all `2026-07-28` Streamable HTTP servers going forward — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
179179
180180
For example:
181181

@@ -196,7 +196,7 @@ public static string ElicitWithMrtr(
196196

197197
if (!server.IsMrtrSupported)
198198
{
199-
return "This tool requires MRTR support (DRAFT-2026-v1, or a stateful current-protocol session).";
199+
return "This tool requires MRTR support (2026-07-28, or a stateful current-protocol session).";
200200
}
201201

202202
// First call — request user input

docs/concepts/mrtr/mrtr.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ uid: mrtr
99

1010
<!-- mlc-disable-next-line -->
1111
> [!WARNING]
12-
> MRTR is part of the **`DRAFT-2026-v1`** revision of the MCP specification ([SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)). The wire format and API surface may change before the revision is ratified. See the [Experimental APIs](../../experimental.md) documentation for details on working with experimental APIs.
12+
> MRTR is part of the **`2026-07-28`** revision of the MCP specification ([SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)). The wire format and API surface may change before the revision is ratified. See the [Experimental APIs](../../experimental.md) documentation for details on working with experimental APIs.
1313
1414
Multi Round-Trip Requests (MRTR) let a server tool request input from the client — such as [elicitation](xref:elicitation), [sampling](xref:sampling), or [roots](xref:roots) — as part of a single tool call, without requiring a separate server-to-client JSON-RPC request for each interaction. Instead of returning a final result, the server returns an **incomplete result** containing one or more input requests. The client fulfills those requests and retries the original tool call with the responses attached.
1515

@@ -33,13 +33,13 @@ MRTR is useful when:
3333

3434
## Opting in
3535

36-
MRTR activates when both peers negotiate protocol revision **`DRAFT-2026-v1`** during `initialize`. The C# SDK opts in by listing `DRAFT-2026-v1` as a supported protocol version on the client; servers automatically accept it when offered. No experimental flags are required.
36+
MRTR activates when both peers negotiate protocol revision **`2026-07-28`** during `initialize`. The C# SDK opts in by listing `2026-07-28` as a supported protocol version on the client; servers automatically accept it when offered. No experimental flags are required.
3737

3838
```csharp
3939
// Client
4040
var clientOptions = new McpClientOptions
4141
{
42-
ProtocolVersion = "DRAFT-2026-v1",
42+
ProtocolVersion = "2026-07-28",
4343
Handlers = new McpClientHandlers
4444
{
4545
ElicitationHandler = HandleElicitationAsync,
@@ -48,7 +48,7 @@ var clientOptions = new McpClientOptions
4848
};
4949
```
5050

51-
Under `DRAFT-2026-v1`, MRTR is the recommended way to obtain client input from a server handler. The spec removes the legacy server-to-client `elicitation/create`, `sampling/createMessage`, and `roots/list` request methods, so any code that needs to work on a `DRAFT-2026-v1` Streamable HTTP server (which will be stateless-only in a future revision) must use `InputRequiredException` rather than <xref:ModelContextProtocol.Server.McpServer.ElicitAsync*>, <xref:ModelContextProtocol.Server.McpServer.SampleAsync*>, or <xref:ModelContextProtocol.Server.McpServer.RequestRootsAsync*>. The legacy methods still work on stateful sessions — that's how stdio servers keep working under draft today — but they throw `InvalidOperationException("X is not supported in stateless mode.")` on any stateless session, current or draft.
51+
Under `2026-07-28`, MRTR is the recommended way to obtain client input from a server handler. The spec removes the legacy server-to-client `elicitation/create`, `sampling/createMessage`, and `roots/list` request methods, so any code that needs to work on a `2026-07-28` Streamable HTTP server (which will be stateless-only in a future revision) must use `InputRequiredException` rather than <xref:ModelContextProtocol.Server.McpServer.ElicitAsync*>, <xref:ModelContextProtocol.Server.McpServer.SampleAsync*>, or <xref:ModelContextProtocol.Server.McpServer.RequestRootsAsync*>. The legacy methods still work on stateful sessions — that's how stdio servers keep working under draft today — but they throw `InvalidOperationException("X is not supported in stateless mode.")` on any stateless session, current or draft.
5252

5353
Under the current protocol revision (`2025-06-18` and earlier), `InputRequiredException` is still supported in stateful sessions via a backward-compatibility resolver — see [Compatibility](#compatibility) below.
5454

@@ -60,7 +60,7 @@ A tool participates in MRTR by throwing <xref:ModelContextProtocol.Protocol.Inpu
6060

6161
Tools should check <xref:ModelContextProtocol.Server.McpServer.IsMrtrSupported> before throwing `InputRequiredException`. It returns `true` when either:
6262

63-
- The negotiated protocol revision is `DRAFT-2026-v1` (MRTR is native), or
63+
- The negotiated protocol revision is `2026-07-28` (MRTR is native), or
6464
- The session is stateful under the current protocol (the SDK can resolve input requests via legacy JSON-RPC and retry the handler).
6565

6666
```csharp
@@ -71,7 +71,7 @@ public static string MyTool(
7171
{
7272
if (!server.IsMrtrSupported)
7373
{
74-
return "This tool requires a client that negotiates DRAFT-2026-v1, "
74+
return "This tool requires a client that negotiates 2026-07-28, "
7575
+ "or a stateful current-protocol session.";
7676
}
7777

@@ -258,7 +258,7 @@ When MRTR is not supported, you can provide domain-specific guidance:
258258
if (!server.IsMrtrSupported)
259259
{
260260
return "This tool requires interactive input. To use it:\n"
261-
+ "1. Connect with a client that negotiates MCP protocol revision DRAFT-2026-v1, or\n"
261+
+ "1. Connect with a client that negotiates MCP protocol revision 2026-07-28, or\n"
262262
+ "2. Use a stateful current-protocol session so the server can resolve the input requests for you.\n"
263263
+ "\nStateless current-protocol sessions cannot resolve MRTR input requests.";
264264
}
@@ -270,22 +270,22 @@ The SDK supports `InputRequiredException` across two protocol revisions and two
270270

271271
| Negotiated protocol | Session mode | Behavior |
272272
|---|---|---|
273-
| `DRAFT-2026-v1` | Stateful | Native MRTR — `InputRequiredResult` is serialized directly to the wire. |
274-
| `DRAFT-2026-v1` | Stateless | Native MRTR — `InputRequiredResult` is serialized directly to the wire. No server-side handler state needed. |
273+
| `2026-07-28` | Stateful | Native MRTR — `InputRequiredResult` is serialized directly to the wire. |
274+
| `2026-07-28` | Stateless | Native MRTR — `InputRequiredResult` is serialized directly to the wire. No server-side handler state needed. |
275275
| Current (`2025-06-18` and earlier) | Stateful | Backward-compatibility resolver — the SDK sends standard `elicitation/create` / `sampling/createMessage` / `roots/list` JSON-RPC requests to the client, collects the responses, and retries the handler with `inputResponses` populated. Up to 10 retry rounds. |
276276
| Current (`2025-06-18` and earlier) | Stateless | **Not supported**`InputRequiredException` raises an `McpException`. The client doesn't speak MRTR, and the server can't resolve input requests via JSON-RPC without a persistent session. |
277277

278278
> [!NOTE]
279-
> The backcompat resolver is intentionally limited to 10 retry rounds. Tools that need more rounds should require `DRAFT-2026-v1` (check `IsMrtrSupported`).
279+
> The backcompat resolver is intentionally limited to 10 retry rounds. Tools that need more rounds should require `2026-07-28` (check `IsMrtrSupported`).
280280
281281
### Why `ElicitAsync` / `SampleAsync` / `RequestRootsAsync` throw on stateless servers
282282

283283
`ElicitAsync` / `SampleAsync` / `RequestRootsAsync` issue a JSON-RPC request to the client and wait for the response on the same session. Stateless servers don't have a persistent session to wait on, so the SDK fails fast with `InvalidOperationException("X is not supported in stateless mode.")` (the check is `McpServer.ClientCapabilities is null`, which is the SDK's proxy for stateless).
284284

285-
Under the current protocol revision (`2025-06-18` and earlier), stdio and stateful Streamable HTTP keep `ClientCapabilities` populated, so the legacy methods work normally and remain the recommended way to do one-shot client interactions. Under `DRAFT-2026-v1`, the spec removes those request methods from Streamable HTTP entirely; the SDK still allows the legacy methods on draft stdio sessions because stdio is implicitly single-process / stateful and the client handler is wired up regardless of negotiated revision. `InputRequiredException` is the way to write tools that work on every supported configuration.
285+
Under the current protocol revision (`2025-06-18` and earlier), stdio and stateful Streamable HTTP keep `ClientCapabilities` populated, so the legacy methods work normally and remain the recommended way to do one-shot client interactions. Under `2026-07-28`, the spec removes those request methods from Streamable HTTP entirely; the SDK still allows the legacy methods on draft stdio sessions because stdio is implicitly single-process / stateful and the client handler is wired up regardless of negotiated revision. `InputRequiredException` is the way to write tools that work on every supported configuration.
286286

287287
### Future direction
288288

289-
The `DRAFT-2026-v1` revision is moving toward a stateless-only model: `Mcp-Session-Id` is being removed, and Streamable HTTP servers will run statelessly by default under the draft revision. When that lands, the `Stateful` row for `DRAFT-2026-v1` in the compatibility matrix above collapses into the `Stateless` row (Streamable HTTP under draft becomes stateless-only), and `InputRequiredException` becomes uniformly required for non-stdio servers. The current-protocol resolver path will remain for backward compatibility with older clients and stateful servers.
289+
The `2026-07-28` revision is moving toward a stateless-only model: `Mcp-Session-Id` is being removed, and Streamable HTTP servers will run statelessly by default under the draft revision. When that lands, the `Stateful` row for `2026-07-28` in the compatibility matrix above collapses into the `Stateless` row (Streamable HTTP under draft becomes stateless-only), and `InputRequiredException` becomes uniformly required for non-stdio servers. The current-protocol resolver path will remain for backward compatibility with older clients and stateful servers.
290290

291291
This work is a follow-up to the present PR.

docs/concepts/roots/roots.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,10 @@ server.RegisterNotificationHandler(
106106

107107
### Multi Round-Trip Requests (MRTR)
108108

109-
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `DRAFT-2026-v1`. Under the draft protocol, the server-to-client `roots/list` request method is removed; the recommended way to ask the client for its roots from a server handler is to throw <xref:ModelContextProtocol.Protocol.InputRequiredException> and let the SDK emit an <xref:ModelContextProtocol.Protocol.InputRequiredResult> on the wire.
109+
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `2026-07-28`. Under the draft protocol, the server-to-client `roots/list` request method is removed; the recommended way to ask the client for its roots from a server handler is to throw <xref:ModelContextProtocol.Protocol.InputRequiredException> and let the SDK emit an <xref:ModelContextProtocol.Protocol.InputRequiredResult> on the wire.
110110

111111
> [!IMPORTANT]
112-
> `RequestRootsAsync` throws `InvalidOperationException("Roots are not supported in stateless mode.")` whenever the server is running stateless — which includes every Streamable HTTP server under `DRAFT-2026-v1` once that revision is forced to stateless-only in a future PR. Stdio servers and current-protocol stateful Streamable HTTP servers continue to work via the legacy server-to-client `roots/list` request flow. For code that needs to run on stateless servers — including all `DRAFT-2026-v1` Streamable HTTP servers going forward — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
112+
> `RequestRootsAsync` throws `InvalidOperationException("Roots are not supported in stateless mode.")` whenever the server is running stateless — which includes every Streamable HTTP server under `2026-07-28` once that revision is forced to stateless-only in a future PR. Stdio servers and current-protocol stateful Streamable HTTP servers continue to work via the legacy server-to-client `roots/list` request flow. For code that needs to run on stateless servers — including all `2026-07-28` Streamable HTTP servers going forward — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
113113
114114
For example:
115115

@@ -128,7 +128,7 @@ public static string ListRootsWithMrtr(
128128

129129
if (!server.IsMrtrSupported)
130130
{
131-
return "This tool requires MRTR support (DRAFT-2026-v1, or a stateful current-protocol session).";
131+
return "This tool requires MRTR support (2026-07-28, or a stateful current-protocol session).";
132132
}
133133

134134
// First call — request the client's root list

docs/concepts/sampling/sampling.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ Sampling requires the client to advertise the `sampling` capability. This is han
123123

124124
### Multi Round-Trip Requests (MRTR)
125125

126-
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `DRAFT-2026-v1`. Under the draft protocol, the server-to-client `sampling/createMessage` request method is removed; the recommended way to ask the client to sample from a server handler is to throw <xref:ModelContextProtocol.Protocol.InputRequiredException> and let the SDK emit an <xref:ModelContextProtocol.Protocol.InputRequiredResult> on the wire.
126+
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `2026-07-28`. Under the draft protocol, the server-to-client `sampling/createMessage` request method is removed; the recommended way to ask the client to sample from a server handler is to throw <xref:ModelContextProtocol.Protocol.InputRequiredException> and let the SDK emit an <xref:ModelContextProtocol.Protocol.InputRequiredResult> on the wire.
127127

128128
> [!IMPORTANT]
129-
> `SampleAsync` and `AsSamplingChatClient` throw `InvalidOperationException("Sampling is not supported in stateless mode.")` whenever the server is running stateless — which includes every Streamable HTTP server under `DRAFT-2026-v1` once that revision is forced to stateless-only in a future PR. Stdio servers and current-protocol stateful Streamable HTTP servers continue to work via the legacy server-to-client `sampling/createMessage` request flow. For code that needs to run on stateless servers — including all `DRAFT-2026-v1` Streamable HTTP servers going forward — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
129+
> `SampleAsync` and `AsSamplingChatClient` throw `InvalidOperationException("Sampling is not supported in stateless mode.")` whenever the server is running stateless — which includes every Streamable HTTP server under `2026-07-28` once that revision is forced to stateless-only in a future PR. Stdio servers and current-protocol stateful Streamable HTTP servers continue to work via the legacy server-to-client `sampling/createMessage` request flow. For code that needs to run on stateless servers — including all `2026-07-28` Streamable HTTP servers going forward — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
130130
131131
For example:
132132

@@ -146,7 +146,7 @@ public static string SampleWithMrtr(
146146

147147
if (!server.IsMrtrSupported)
148148
{
149-
return "This tool requires MRTR support (DRAFT-2026-v1, or a stateful current-protocol session).";
149+
return "This tool requires MRTR support (2026-07-28, or a stateful current-protocol session).";
150150
}
151151

152152
// First call — request LLM completion from the client

docs/concepts/tools/tools.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ Rules and constraints:
339339
- The header name must contain only visible ASCII characters (0x21–0x7E) excluding colon (`:`).
340340
- Values containing non-ASCII characters, control characters, or leading/trailing whitespace are Base64-encoded using the `=?base64?{value}?=` wrapper.
341341
- Header names must be case-insensitively unique within the tool's input schema.
342-
- Header validation is enforced only for protocol versions that support the HTTP Standardization feature (currently `DRAFT-2026-v1` and later).
342+
- Header validation is enforced only for protocol versions that support the HTTP Standardization feature (currently `2026-07-28` and later).
343343

344344
### Pre-loading tool definitions on the client
345345

src/Common/McpHttpHeaders.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ internal static class McpHttpHeaders
3030
/// The associated helpers perform exact ordinal matches against this single value rather
3131
/// than any ordered comparison.
3232
/// </remarks>
33-
public const string DraftProtocolVersion = "DRAFT-2026-v1";
33+
public const string DraftProtocolVersion = "2026-07-28";
3434

3535
/// <summary>The session identifier header.</summary>
3636
public const string SessionId = "Mcp-Session-Id";

0 commit comments

Comments
 (0)