Skip to content

Commit 5db2419

Browse files
halter73Copilot
andcommitted
Add MRTR sections to elicitation, sampling, and roots docs
Add high-level and low-level MRTR examples to each feature doc: - elicitation.md: ElicitAsync (transparent) + IncompleteResultException - sampling.md: SampleAsync (transparent) + IncompleteResultException - roots.md: RequestRootsAsync (transparent) + IncompleteResultException Fix missing entries in docs navigation: - toc.yml: Add Sampling under Client Features - index.md: Add Tasks and MRTR to Base Protocol table Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7ad4702 commit 5db2419

File tree

5 files changed

+205
-0
lines changed

5 files changed

+205
-0
lines changed

docs/concepts/elicitation/elicitation.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,82 @@ Here's an example implementation of how a console application might handle elici
170170

171171
[!code-csharp[](samples/client/Program.cs?name=snippet_ElicitationHandler)]
172172

173+
### Multi Round-Trip Requests (MRTR)
174+
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.
176+
177+
#### High-level API
178+
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+
181+
```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.IncompleteResultException> 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")]
205+
public static string ElicitWithMrtr(
206+
McpServer server,
207+
RequestContext<CallToolRequestParams> context)
208+
{
209+
// On retry, process the client's elicitation response
210+
if (context.Params!.InputResponses?.TryGetValue("user_input", out var response) is true)
211+
{
212+
var elicitResult = response.ElicitationResult;
213+
return elicitResult?.Action == "accept"
214+
? $"User accepted: {elicitResult.Content?.FirstOrDefault().Value}"
215+
: "User declined.";
216+
}
217+
218+
if (!server.IsMrtrSupported)
219+
{
220+
return "This tool requires MRTR support.";
221+
}
222+
223+
// First call — request user input
224+
throw new IncompleteResultException(
225+
inputRequests: new Dictionary<string, InputRequest>
226+
{
227+
["user_input"] = InputRequest.ForElicitation(new ElicitRequestParams
228+
{
229+
Message = "Please confirm the action",
230+
RequestedSchema = new()
231+
{
232+
Properties = new Dictionary<string, ElicitRequestParams.PrimitiveSchemaDefinition>
233+
{
234+
["confirm"] = new ElicitRequestParams.BooleanSchema
235+
{
236+
Description = "Confirm the action"
237+
}
238+
}
239+
}
240+
})
241+
},
242+
requestState: "awaiting-confirmation");
243+
}
244+
```
245+
246+
> [!TIP]
247+
> See [Multi Round-Trip Requests (MRTR)](xref:mrtr) for the full protocol details, including multiple round trips, concurrent input requests, and the compatibility matrix.
248+
173249
### URL Elicitation Required Error
174250

175251
When a tool cannot proceed without first completing a URL-mode elicitation (for example, when third-party OAuth authorization is needed), and calling `ElicitAsync` is not practical (for example in <xref: ModelContextProtocol.AspNetCore.HttpServerTransportOptions.Stateless> is enabled disabling server-to-client requests), the server may throw a <xref:ModelContextProtocol.UrlElicitationRequiredException>. This is a specialized error (JSON-RPC error code `-32042`) that signals to the client that one or more URL-mode elicitations must be completed before the original request can be retried.

docs/concepts/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Install the SDK and build your first MCP client and server.
1818
| [Progress tracking](progress/progress.md) | Learn how to track progress for long-running operations through notification messages. |
1919
| [Cancellation](cancellation/cancellation.md) | Learn how to cancel in-flight MCP requests using cancellation tokens and notifications. |
2020
| [Pagination](pagination/pagination.md) | Learn how to use cursor-based pagination when listing tools, prompts, and resources. |
21+
| [Tasks](tasks/tasks.md) | Learn how to create and manage long-running tool call tasks. |
22+
| [Multi Round-Trip Requests (MRTR)](mrtr/mrtr.md) | Learn how servers request client input during tool execution using incomplete results and retries. |
2123

2224
### Client Features
2325

docs/concepts/roots/roots.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,55 @@ server.RegisterNotificationHandler(
103103
Console.WriteLine($"Roots updated. {result.Roots.Count} roots available.");
104104
});
105105
```
106+
107+
### Multi Round-Trip Requests (MRTR)
108+
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.
110+
111+
#### High-level API
112+
113+
No code changes are needed. `RequestRootsAsync` automatically uses MRTR when both sides have opted in:
114+
115+
```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.IncompleteResultException> 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")]
130+
public static string ListRootsWithMrtr(
131+
McpServer server,
132+
RequestContext<CallToolRequestParams> context)
133+
{
134+
// On retry, process the client's roots response
135+
if (context.Params!.InputResponses?.TryGetValue("get_roots", out var response) is true)
136+
{
137+
var roots = response.RootsResult?.Roots ?? [];
138+
return $"Found {roots.Count} roots: {string.Join(", ", roots.Select(r => r.Uri))}";
139+
}
140+
141+
if (!server.IsMrtrSupported)
142+
{
143+
return "This tool requires MRTR support.";
144+
}
145+
146+
// First call — request the client's root list
147+
throw new IncompleteResultException(
148+
inputRequests: new Dictionary<string, InputRequest>
149+
{
150+
["get_roots"] = InputRequest.ForRootsList(new ListRootsRequestParams())
151+
},
152+
requestState: "awaiting-roots");
153+
}
154+
```
155+
156+
> [!TIP]
157+
> See [Multi Round-Trip Requests (MRTR)](xref:mrtr) for the full protocol details, including load shedding, multiple round trips, and the compatibility matrix.

docs/concepts/sampling/sampling.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,76 @@ McpClientOptions options = new()
117117
### Capability negotiation
118118

119119
Sampling requires the client to advertise the `sampling` capability. This is handled automatically — when a <xref:ModelContextProtocol.Client.McpClientHandlers.SamplingHandler> is set, the client includes the sampling capability during initialization. The server can check whether the client supports sampling before calling <xref:ModelContextProtocol.Server.McpServer.SampleAsync*>; if sampling is not supported, the method throws <xref:System.InvalidOperationException>.
120+
121+
### Multi Round-Trip Requests (MRTR)
122+
123+
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.
124+
125+
#### High-level API
126+
127+
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:
128+
129+
```csharp
130+
// This code works the same with or without MRTR — the SDK handles it transparently.
131+
var result = await server.SampleAsync(
132+
new CreateMessageRequestParams
133+
{
134+
Messages =
135+
[
136+
new SamplingMessage
137+
{
138+
Role = Role.User,
139+
Content = [new TextContentBlock { Text = "Summarize the data" }]
140+
}
141+
],
142+
MaxTokens = 256,
143+
},
144+
cancellationToken);
145+
```
146+
147+
#### Low-level API
148+
149+
For stateless servers or scenarios requiring manual control, throw <xref:ModelContextProtocol.Protocol.IncompleteResultException> with a sampling input request. On retry, read the client's response from <xref:ModelContextProtocol.Protocol.RequestParams.InputResponses>:
150+
151+
```csharp
152+
[McpServerTool, Description("Tool that samples via low-level MRTR")]
153+
public static string SampleWithMrtr(
154+
McpServer server,
155+
RequestContext<CallToolRequestParams> context)
156+
{
157+
// On retry, process the client's sampling response
158+
if (context.Params!.InputResponses?.TryGetValue("llm_call", out var response) is true)
159+
{
160+
var text = response.SamplingResult?.Content
161+
.OfType<TextContentBlock>().FirstOrDefault()?.Text;
162+
return $"LLM said: {text}";
163+
}
164+
165+
if (!server.IsMrtrSupported)
166+
{
167+
return "This tool requires MRTR support.";
168+
}
169+
170+
// First call — request LLM completion from the client
171+
throw new IncompleteResultException(
172+
inputRequests: new Dictionary<string, InputRequest>
173+
{
174+
["llm_call"] = InputRequest.ForSampling(new CreateMessageRequestParams
175+
{
176+
Messages =
177+
[
178+
new SamplingMessage
179+
{
180+
Role = Role.User,
181+
Content = [new TextContentBlock { Text = "Summarize the data" }]
182+
}
183+
],
184+
MaxTokens = 256
185+
})
186+
},
187+
requestState: "awaiting-sample");
188+
}
189+
```
190+
191+
> [!TIP]
192+
> See [Multi Round-Trip Requests (MRTR)](xref:mrtr) for the full protocol details, including load shedding, multiple round trips, and the compatibility matrix.

docs/concepts/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ items:
2323
uid: mrtr
2424
- name: Client Features
2525
items:
26+
- name: Sampling
27+
uid: sampling
2628
- name: Roots
2729
uid: roots
2830
- name: Elicitation

0 commit comments

Comments
 (0)