Skip to content

Commit 18c0df7

Browse files
halter73Copilot
andcommitted
Remove implicit MRTR machinery and require InputRequiredException under draft
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8f87ad4 commit 18c0df7

28 files changed

Lines changed: 232 additions & 3349 deletions

docs/concepts/elicitation/elicitation.md

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

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

175-
When both the client and server opt in to the experimental [MRTR](xref:mrtr) protocol, elicitation requests are handled via incomplete result / retry instead of a direct JSON-RPC request. This is transparent — the existing `ElicitAsync` API works identically regardless of whether MRTR is active.
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 only supported 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

177-
#### High-level API
177+
> [!IMPORTANT]
178+
> Calling `ElicitAsync` after negotiating `DRAFT-2026-v1` throws `InvalidOperationException`. Use `InputRequiredException` from your tool/prompt handler instead — it works under both the current protocol (resolved via legacy JSON-RPC + retry on stateful sessions) and the draft protocol (wire-format `InputRequiredResult`, no server-side handler state required).
178179
179-
No code changes are needed. `ElicitAsync` automatically uses MRTR when both sides have opted in, and falls back to legacy JSON-RPC requests otherwise:
180+
For example:
180181

181182
```csharp
182-
// This code works the same with or without MRTR — the SDK handles it transparently.
183-
var result = await server.ElicitAsync(new ElicitRequestParams
184-
{
185-
Message = "Please confirm the action",
186-
RequestedSchema = new()
187-
{
188-
Properties = new Dictionary<string, ElicitRequestParams.PrimitiveSchemaDefinition>
189-
{
190-
["confirm"] = new ElicitRequestParams.BooleanSchema
191-
{
192-
Description = "Confirm the action"
193-
}
194-
}
195-
}
196-
}, cancellationToken);
197-
```
198-
199-
#### Low-level API
200-
201-
For stateless servers or scenarios requiring manual control, throw <xref:ModelContextProtocol.Protocol.InputRequiredException> with an elicitation input request. On retry, read the client's response from <xref:ModelContextProtocol.Protocol.RequestParams.InputResponses>:
202-
203-
```csharp
204-
[McpServerTool, Description("Tool that elicits via low-level MRTR")]
183+
[McpServerTool, Description("Tool that elicits via MRTR")]
205184
public static string ElicitWithMrtr(
206185
McpServer server,
207186
RequestContext<CallToolRequestParams> context)
@@ -217,7 +196,7 @@ public static string ElicitWithMrtr(
217196

218197
if (!server.IsMrtrSupported)
219198
{
220-
return "This tool requires MRTR support.";
199+
return "This tool requires MRTR support (DRAFT-2026-v1, or a stateful current-protocol session).";
221200
}
222201

223202
// First call — request user input

docs/concepts/mrtr/mrtr.md

Lines changed: 48 additions & 221 deletions
Large diffs are not rendered by default.

docs/concepts/roots/roots.md

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -106,27 +106,15 @@ server.RegisterNotificationHandler(
106106

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

109-
When both the client and server opt in to the experimental [MRTR](xref:mrtr) protocol, root list requests are handled via incomplete result / retry instead of a direct JSON-RPC request. This is transparent — the existing `RequestRootsAsync` API works identically regardless of whether MRTR is active.
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 only supported 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

111-
#### High-level API
111+
> [!IMPORTANT]
112+
> Calling `RequestRootsAsync` after negotiating `DRAFT-2026-v1` throws `InvalidOperationException`. Use `InputRequiredException` from your tool/prompt handler instead — it works under both the current protocol (resolved via legacy JSON-RPC + retry on stateful sessions) and the draft protocol (wire-format `InputRequiredResult`, no server-side handler state required).
112113
113-
No code changes are needed. `RequestRootsAsync` automatically uses MRTR when both sides have opted in:
114+
For example:
114115

115116
```csharp
116-
// This code works the same with or without MRTR — the SDK handles it transparently.
117-
var result = await server.RequestRootsAsync(new ListRootsRequestParams(), cancellationToken);
118-
foreach (var root in result.Roots)
119-
{
120-
Console.WriteLine($"Root: {root.Name ?? root.Uri}");
121-
}
122-
```
123-
124-
#### Low-level API
125-
126-
For stateless servers or scenarios requiring manual control, throw <xref:ModelContextProtocol.Protocol.InputRequiredException> with a roots input request. On retry, read the client's response from <xref:ModelContextProtocol.Protocol.RequestParams.InputResponses>:
127-
128-
```csharp
129-
[McpServerTool, Description("Tool that requests roots via low-level MRTR")]
117+
[McpServerTool, Description("Tool that requests roots via MRTR")]
130118
public static string ListRootsWithMrtr(
131119
McpServer server,
132120
RequestContext<CallToolRequestParams> context)
@@ -140,7 +128,7 @@ public static string ListRootsWithMrtr(
140128

141129
if (!server.IsMrtrSupported)
142130
{
143-
return "This tool requires MRTR support.";
131+
return "This tool requires MRTR support (DRAFT-2026-v1, or a stateful current-protocol session).";
144132
}
145133

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

docs/concepts/sampling/sampling.md

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

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

126-
When both the client and server opt in to the experimental [MRTR](xref:mrtr) protocol, sampling requests are handled via incomplete result / retry instead of a direct JSON-RPC request. This is transparent — the existing `SampleAsync` and `AsSamplingChatClient` APIs work identically regardless of whether MRTR is active.
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 only supported 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

128-
#### High-level API
128+
> [!IMPORTANT]
129+
> Calling `SampleAsync` or `AsSamplingChatClient` after negotiating `DRAFT-2026-v1` throws `InvalidOperationException`. Use `InputRequiredException` from your tool/prompt handler instead — it works under both the current protocol (resolved via legacy JSON-RPC + retry on stateful sessions) and the draft protocol (wire-format `InputRequiredResult`, no server-side handler state required).
129130
130-
No code changes are needed. `SampleAsync` and `AsSamplingChatClient` automatically use MRTR when both sides have opted in, and fall back to legacy JSON-RPC requests otherwise:
131+
For example:
131132

132133
```csharp
133-
// This code works the same with or without MRTR — the SDK handles it transparently.
134-
var result = await server.SampleAsync(
135-
new CreateMessageRequestParams
136-
{
137-
Messages =
138-
[
139-
new SamplingMessage
140-
{
141-
Role = Role.User,
142-
Content = [new TextContentBlock { Text = "Summarize the data" }]
143-
}
144-
],
145-
MaxTokens = 256,
146-
},
147-
cancellationToken);
148-
```
149-
150-
#### Low-level API
151-
152-
For stateless servers or scenarios requiring manual control, throw <xref:ModelContextProtocol.Protocol.InputRequiredException> with a sampling input request. On retry, read the client's response from <xref:ModelContextProtocol.Protocol.RequestParams.InputResponses>:
153-
154-
```csharp
155-
[McpServerTool, Description("Tool that samples via low-level MRTR")]
134+
[McpServerTool, Description("Tool that samples via MRTR")]
156135
public static string SampleWithMrtr(
157136
McpServer server,
158137
RequestContext<CallToolRequestParams> context)
@@ -167,7 +146,7 @@ public static string SampleWithMrtr(
167146

168147
if (!server.IsMrtrSupported)
169148
{
170-
return "This tool requires MRTR support.";
149+
return "This tool requires MRTR support (DRAFT-2026-v1, or a stateful current-protocol session).";
171150
}
172151

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

src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Microsoft.Extensions.AI;
1+
using Microsoft.Extensions.AI;
22
using Microsoft.Extensions.DependencyInjection;
33
using ModelContextProtocol.Protocol;
44
using System.ComponentModel;
@@ -15,7 +15,6 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
1515
{
1616
private readonly bool _structuredOutputRequiresWrapping;
1717
private readonly IReadOnlyList<object> _metadata;
18-
private readonly bool _deferTaskCreation;
1918

2019
/// <summary>
2120
/// Creates an <see cref="McpServerTool"/> instance for a method, specified via a <see cref="Delegate"/> instance.
@@ -174,7 +173,7 @@ options.OpenWorld is not null ||
174173
tool.Execution.TaskSupport = ToolTaskSupport.Optional;
175174
}
176175

177-
return new AIFunctionMcpServerTool(function, tool, options?.Services, structuredOutputRequiresWrapping, options?.Metadata ?? [], options?.DeferTaskCreation ?? false);
176+
return new AIFunctionMcpServerTool(function, tool, options?.Services, structuredOutputRequiresWrapping, options?.Metadata ?? []);
178177
}
179178

180179
private static McpServerToolCreateOptions DeriveOptions(MethodInfo method, McpServerToolCreateOptions? options)
@@ -225,11 +224,6 @@ private static McpServerToolCreateOptions DeriveOptions(MethodInfo method, McpSe
225224
newOptions.Execution ??= new ToolExecution();
226225
newOptions.Execution.TaskSupport ??= taskSupport;
227226
}
228-
229-
if (toolAttr._deferTaskCreation is bool deferTaskCreation)
230-
{
231-
newOptions.DeferTaskCreation = deferTaskCreation;
232-
}
233227
}
234228

235229
if (method.GetCustomAttribute<DescriptionAttribute>() is { } descAttr)
@@ -247,7 +241,7 @@ private static McpServerToolCreateOptions DeriveOptions(MethodInfo method, McpSe
247241
internal AIFunction AIFunction { get; }
248242

249243
/// <summary>Initializes a new instance of the <see cref="McpServerTool"/> class.</summary>
250-
private AIFunctionMcpServerTool(AIFunction function, Tool tool, IServiceProvider? serviceProvider, bool structuredOutputRequiresWrapping, IReadOnlyList<object> metadata, bool deferTaskCreation)
244+
private AIFunctionMcpServerTool(AIFunction function, Tool tool, IServiceProvider? serviceProvider, bool structuredOutputRequiresWrapping, IReadOnlyList<object> metadata)
251245
{
252246
ValidateToolName(tool.Name);
253247

@@ -256,15 +250,11 @@ private AIFunctionMcpServerTool(AIFunction function, Tool tool, IServiceProvider
256250

257251
_structuredOutputRequiresWrapping = structuredOutputRequiresWrapping;
258252
_metadata = metadata;
259-
_deferTaskCreation = deferTaskCreation;
260253
}
261254

262255
/// <inheritdoc />
263256
public override Tool ProtocolTool { get; }
264257

265-
/// <inheritdoc />
266-
public override bool DeferTaskCreation => _deferTaskCreation;
267-
268258
/// <inheritdoc />
269259
public override IReadOnlyList<object> Metadata => _metadata;
270260

src/ModelContextProtocol.Core/Server/DeferredTaskCreationResult.cs

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/ModelContextProtocol.Core/Server/DeferredTaskInfo.cs

Lines changed: 0 additions & 78 deletions
This file was deleted.

src/ModelContextProtocol.Core/Server/DelegatingMcpServerTool.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using ModelContextProtocol.Protocol;
1+
using ModelContextProtocol.Protocol;
22

33
namespace ModelContextProtocol.Server;
44

@@ -23,9 +23,6 @@ protected DelegatingMcpServerTool(McpServerTool innerTool)
2323
/// <inheritdoc />
2424
public override Tool ProtocolTool => _innerTool.ProtocolTool;
2525

26-
/// <inheritdoc />
27-
public override bool DeferTaskCreation => _innerTool.DeferTaskCreation;
28-
2926
/// <inheritdoc />
3027
public override IReadOnlyList<object> Metadata => _innerTool.Metadata;
3128

0 commit comments

Comments
 (0)