Skip to content

Commit b7e68dc

Browse files
halter73Copilot
andcommitted
Improve session docs, client behavior, and observability guidance
Add client-side session behavior documentation covering session lifecycle, expiry detection, reconnection patterns, and transport options. Move Sessions to Base Protocol in toc.yml. Add session cross-references to sampling, roots, tools, prompts, progress, and cancellation docs. Restructure sessions.md: merge redundant stateless sections, promote Tasks, Request backpressure, and Observability to top-level sections, move client section before Advanced features, and fold stream reconnection into lifecycle. Add reconnection integration test (Client_CanReconnect_AfterSessionExpiry) using MapMcp with middleware to simulate 404 session expiry. Clarify the two session ID concepts: transport session ID (McpSession.SessionId, shared between client and server) vs telemetry session ID (mcp.session.id tag, per-instance). Document that middleware should read Mcp-Session-Id from the response header after await next() to capture it on the initialize request. Initialize EnableLegacySse from AppContext switch in property initializer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4062b23 commit b7e68dc

File tree

13 files changed

+326
-48
lines changed

13 files changed

+326
-48
lines changed

docs/concepts/cancellation/cancellation.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ MCP supports [cancellation] of in-flight requests. Either side can cancel a prev
1212
[cancellation]: https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/cancellation
1313
[task cancellation]: https://learn.microsoft.com/dotnet/standard/parallel-programming/task-cancellation
1414

15+
> [!NOTE]
16+
> The source and lifetime of the `CancellationToken` provided to server handlers depends on the transport and session mode. In [stateless mode](xref:sessions#stateless-mode-recommended), the token is tied to the HTTP request — if the client disconnects, the handler is cancelled. In [stateful mode](xref:sessions#stateful-mode-sessions), the token is tied to the session lifetime. See [Cancellation and disposal](xref:sessions#cancellation-and-disposal) for details.
17+
1518
### How cancellation maps to MCP notifications
1619

1720
When a `CancellationToken` passed to a client method (such as <xref:ModelContextProtocol.Client.McpClient.CallToolAsync*>) is cancelled, a `notifications/cancelled` notification is sent to the server with the request ID. On the server side, the `CancellationToken` provided to the tool method is then triggered, allowing the handler to stop work gracefully. This same mechanism works in reverse for server-to-client requests.

docs/concepts/progress/progress.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Typically progress tracking is supported by server tools that perform operations
1515
However, progress tracking is defined in the MCP specification as a general feature that can be implemented for any request that's handled by either a server or a client.
1616
This project illustrates the common case of a server tool that performs a long-running operation and sends progress updates to the client.
1717

18+
> [!NOTE]
19+
> Progress notifications are sent inline as part of the response to a request — they are not unsolicited. Progress tracking works in both [stateless and stateful](xref:sessions) modes as well as stdio.
20+
1821
### Server Implementation
1922

2023
When processing a request, the server can use the <xref:ModelContextProtocol.McpSession.SendNotificationAsync*> extension method of <xref:ModelContextProtocol.Server.McpServer> to send progress updates,

docs/concepts/prompts/prompts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ foreach (var message in result.Messages)
197197

198198
### Prompt list change notifications
199199

200-
Servers can dynamically add, remove, or modify prompts at runtime and notify connected clients.
200+
Servers can dynamically add, remove, or modify prompts at runtime and notify connected clients. These are unsolicited notifications, so they require [stateful mode or stdio](xref:sessions)[stateless](xref:sessions#stateless-mode-recommended) servers cannot send unsolicited notifications.
201201

202202
#### Sending notifications from the server
203203

docs/concepts/roots/roots.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ await using var client = await McpClient.CreateAsync(transport, options);
5757

5858
### Requesting roots from the server
5959

60-
Servers can request the client's root list using <xref:ModelContextProtocol.Server.McpServer.RequestRootsAsync*>:
60+
Servers can request the client's root list using <xref:ModelContextProtocol.Server.McpServer.RequestRootsAsync*>. This is a server-to-client request, so it requires [stateful mode or stdio](xref:sessions) — it is not available in [stateless mode](xref:sessions#stateless-mode-recommended).
6161

6262
```csharp
6363
[McpServerTool, Description("Lists the user's project roots")]

docs/concepts/sampling/sampling.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ MCP [sampling] allows servers to request LLM completions from the client. This e
1111

1212
[sampling]: https://modelcontextprotocol.io/specification/2025-11-25/client/sampling
1313

14+
> [!NOTE]
15+
> Sampling is a **server-to-client request** — the server sends a request back to the client over an open connection. This requires [stateful mode or stdio](xref:sessions). Sampling is not available in [stateless mode](xref:sessions#stateless-mode-recommended) because stateless servers cannot send requests to clients.
16+
1417
### How sampling works
1518

1619
1. The server calls <xref:ModelContextProtocol.Server.McpServer.SampleAsync*> (or uses the <xref:ModelContextProtocol.Server.McpServer.AsSamplingChatClient*> adapter) during tool execution.

docs/concepts/sessions/sessions.md

Lines changed: 174 additions & 36 deletions
Large diffs are not rendered by default.

docs/concepts/toc.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ items:
99
uid: capabilities
1010
- name: Transports
1111
uid: transports
12+
- name: Sessions
13+
uid: sessions
1214
- name: Ping
1315
uid: ping
1416
- name: Progress
@@ -39,8 +41,6 @@ items:
3941
uid: completions
4042
- name: Logging
4143
uid: logging
42-
- name: Sessions
43-
uid: sessions
4444
- name: HTTP Context
4545
uid: httpcontext
4646
- name: Filters

docs/concepts/tools/tools.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ if (result.IsError is true)
262262

263263
### Tool list change notifications
264264

265-
Servers can dynamically add, remove, or modify tools at runtime. When the tool list changes, the server notifies connected clients so they can refresh their tool list.
265+
Servers can dynamically add, remove, or modify tools at runtime. When the tool list changes, the server notifies connected clients so they can refresh their tool list. These are unsolicited notifications, so they require [stateful mode or stdio](xref:sessions)[stateless](xref:sessions#stateless-mode-recommended) servers cannot send unsolicited notifications.
266266

267267
#### Sending notifications from the server
268268

docs/concepts/transports/transports.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ SSE-specific configuration options:
178178

179179
#### SSE server (ASP.NET Core)
180180

181-
The ASP.NET Core integration supports SSE transport alongside Streamable HTTP. Legacy SSE endpoints (`/sse` and `/message`) are **disabled by default** due to [backpressure concerns](xref:sessions#sse-legacy-1). To enable them, set <xref:ModelContextProtocol.AspNetCore.HttpServerTransportOptions.EnableLegacySse> to `true`. SSE always requires stateful mode; legacy SSE endpoints are never mapped when `Stateless = true`.
181+
The ASP.NET Core integration supports SSE transport alongside Streamable HTTP. Legacy SSE endpoints (`/sse` and `/message`) are **disabled by default** due to [backpressure concerns](xref:sessions#request-backpressure). To enable them, set <xref:ModelContextProtocol.AspNetCore.HttpServerTransportOptions.EnableLegacySse> to `true`. SSE always requires stateful mode; legacy SSE endpoints are never mapped when `Stateless = true`.
182182

183183
```csharp
184184
var builder = WebApplication.CreateBuilder(args);
@@ -255,3 +255,5 @@ var tools = await client.ListToolsAsync();
255255
var echo = tools.First(t => t.Name == "echo");
256256
Console.WriteLine(await echo.InvokeAsync(new() { ["arg"] = "Hello World" }));
257257
```
258+
259+
Like [stdio](#stdio-transport), the in-memory transport is inherently single-session — there is no `Mcp-Session-Id` header, and server-to-client requests (sampling, elicitation, roots) work naturally over the bidirectional pipe. This makes it ideal for testing servers that depend on these features. See [Sessions](xref:sessions) for how session behavior varies across transports.

src/ModelContextProtocol.AspNetCore/HttpServerTransportOptions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ public class HttpServerTransportOptions
9292
/// </para>
9393
/// </remarks>
9494
[Obsolete(Obsoletions.EnableLegacySse_Message, DiagnosticId = Obsoletions.EnableLegacySse_DiagnosticId, UrlFormat = Obsoletions.EnableLegacySse_Url)]
95-
public bool EnableLegacySse { get; set; }
95+
public bool EnableLegacySse { get; set; } =
96+
AppContext.TryGetSwitch("ModelContextProtocol.AspNetCore.EnableLegacySse", out var enabled) && enabled;
9697

9798
/// <summary>
9899
/// Gets or sets the event store for resumability support.

0 commit comments

Comments
 (0)