Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/concepts/completions/completions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Register a completion handler when building the server. The handler receives a r

```csharp
builder.Services.AddMcpServer()
.WithHttpTransport(o => o.Stateless = true)
.WithHttpTransport(o => o.SessionMode = HttpServerSessionMode.Stateless)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we've made the change to default Stateless = true, I wonder if we should update our examples/samples to just call .WithHttpTransport() and not explicitly configure the SessionMode. The reason we originally set this explicitly in all the samples is we new we were going to change the default in 2.0. What do you think @jeffhandley?

.WithPrompts<MyPrompts>()
.WithResources<MyResources>()
.WithCompleteHandler(async (ctx, ct) =>
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/elicitation/elicitation.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ Here's an example implementation of how a console application might handle elici
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `2026-07-28`. In that revision, 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.

> [!IMPORTANT]
> `ElicitAsync` throws `InvalidOperationException("Elicitation is not supported in stateless mode.")` whenever the server is running stateless — including Streamable HTTP requests served under `2026-07-28` with `Stateless = true`. Stdio servers and initialize-handshake stateful Streamable HTTP sessions continue to work via the initialize-era server-to-client `elicitation/create` request flow; an HTTP server set to `Stateless = false` refuses `2026-07-28` so dual-path clients can fall back before using that flow. For code that needs to run on stateless servers — including `2026-07-28` Streamable HTTP — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
> `ElicitAsync` throws `InvalidOperationException("Elicitation is not supported in stateless mode.")` whenever the server is running stateless — including every Streamable HTTP request served under `2026-07-28`. Stdio servers and initialize-handshake stateful Streamable HTTP sessions continue to work via the initialize-era server-to-client `elicitation/create` request flow; an HTTP server set to `SessionMode = HttpServerSessionMode.Stateful` refuses `2026-07-28` so dual-path clients can fall back before using that flow, while `HttpServerSessionMode.StatefulForInitializeClients` instead serves `2026-07-28` statelessly on the same endpoint (see [hybrid mode](xref:stateless#hybrid-mode-sessions-for-initialize-clients-only)), so those requests use MRTR while `initialize`-handshake sessions keep this flow. For code that needs to run on stateless servers — including `2026-07-28` Streamable HTTP — throw `InputRequiredException` from your handler instead. It works across both protocol eras and all three HTTP `SessionMode` configurations.

For example:

Expand Down
5 changes: 3 additions & 2 deletions docs/concepts/elicitation/samples/server/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Elicitation.Tools;
using ModelContextProtocol.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -8,8 +9,8 @@
.WithHttpTransport(options =>
{
// Elicitation requires stateful mode because it sends server-to-client requests.
// Set Stateless = false explicitly for forward compatibility in case the default changes.
options.Stateless = false;
// Set SessionMode = HttpServerSessionMode.Stateful explicitly for forward compatibility in case the default changes.
options.SessionMode = HttpServerSessionMode.Stateful;
})
.WithTools<InteractiveTools>();

Expand Down
8 changes: 5 additions & 3 deletions docs/concepts/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ To enable authorization support, call `AddAuthorizationFilters()` when configuri

```csharp
services.AddMcpServer()
.WithHttpTransport(o => o.Stateless = true)
.WithHttpTransport(o => o.SessionMode = HttpServerSessionMode.Stateless)
.AddAuthorizationFilters() // Enable authorization filter support
.WithTools<WeatherTools>();
```
Expand Down Expand Up @@ -511,7 +511,7 @@ This allows you to implement logging, metrics, or other cross-cutting concerns t

```csharp
services.AddMcpServer()
.WithHttpTransport(o => o.Stateless = true)
.WithHttpTransport(o => o.SessionMode = HttpServerSessionMode.Stateless)
.WithRequestFilters(requestFilters =>
{
requestFilters.AddListToolsFilter(next => async (context, cancellationToken) =>
Expand Down Expand Up @@ -546,6 +546,8 @@ services.AddMcpServer()
To use authorization features, you must configure authentication and authorization in your ASP.NET Core application and call `AddAuthorizationFilters()`:

```csharp
using ModelContextProtocol.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication("Bearer")
Expand All @@ -556,7 +558,7 @@ builder.Services.AddAuthorization();
builder.Services.AddMcpServer()
.WithHttpTransport(options =>
{
options.Stateless = true;
options.SessionMode = HttpServerSessionMode.Stateless;
})
.AddAuthorizationFilters() // Required for authorization support
.WithTools<WeatherTools>()
Expand Down
3 changes: 2 additions & 1 deletion docs/concepts/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ dotnet add package ModelContextProtocol.AspNetCore
And add the following code:

```csharp
using ModelContextProtocol.AspNetCore;
using ModelContextProtocol.Server;
using System.ComponentModel;

Expand All @@ -88,7 +89,7 @@ builder.Services.AddMcpServer()
// Stateless mode is recommended for servers that don't need
// server-to-client requests like sampling or elicitation.
// See the Stateless and Stateful documentation for details.
options.Stateless = true;
options.SessionMode = HttpServerSessionMode.Stateless;
})
.WithToolsFromAssembly();
var app = builder.Build();
Expand Down
3 changes: 2 additions & 1 deletion docs/concepts/httpcontext/samples/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using HttpContext.Tools;
using ModelContextProtocol.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -7,7 +8,7 @@
builder.Services.AddMcpServer()
.WithHttpTransport(options =>
{
options.Stateless = true;
options.SessionMode = HttpServerSessionMode.Stateless;
})
.WithTools<ContextTools>();

Expand Down
5 changes: 3 additions & 2 deletions docs/concepts/logging/samples/server/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Logging.Tools;
using ModelContextProtocol.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -8,8 +9,8 @@
.WithHttpTransport(options =>
{
// Log streaming requires stateful mode because the server pushes log notifications
// to clients. Set Stateless = false explicitly for forward compatibility.
options.Stateless = false;
// to clients. Set SessionMode = HttpServerSessionMode.Stateful explicitly for forward compatibility.
options.SessionMode = HttpServerSessionMode.Stateful;
})
.WithTools<LoggingTools>();
// .WithSetLoggingLevelHandler(async (ctx, ct) => new EmptyResult());
Expand Down
6 changes: 3 additions & 3 deletions docs/concepts/mrtr/mrtr.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ MRTR is useful when:

## Opting in

MRTR activates when both peers negotiate protocol revision **`2026-07-28`**. The C# SDK client prefers `2026-07-28` by default — it probes with `server/discover` and falls back to an `initialize` handshake only when the server doesn't support it. Stateless HTTP servers accept `2026-07-28` automatically when a client offers it; HTTP servers configured with `Stateless = false` refuse that revision with `UnsupportedProtocolVersion` so dual-path clients can fall back to a session-capable revision. No experimental flags are required; pinning `ProtocolVersion` to an initialize-capable revision opts back out.
MRTR activates when both peers negotiate protocol revision **`2026-07-28`**. The C# SDK client prefers `2026-07-28` by default — it probes with `server/discover` and falls back to an `initialize` handshake only when the server doesn't support it. Stateless HTTP servers accept `2026-07-28` automatically when a client offers it; HTTP servers configured with `SessionMode = HttpServerSessionMode.Stateful` refuse that revision with `UnsupportedProtocolVersion` so dual-path clients can fall back to a session-capable revision. `HttpServerSessionMode.StatefulForInitializeClients` ([hybrid mode](xref:stateless#hybrid-mode-sessions-for-initialize-clients-only)) accepts `2026-07-28` statelessly — and therefore enables MRTR — while still issuing sessions to `initialize`-handshake clients on the same endpoint. No experimental flags are required; pinning `ProtocolVersion` to an initialize-capable revision opts back out.

```csharp
// Client — the SDK prefers 2026-07-28 (and therefore MRTR) by default.
Expand Down Expand Up @@ -373,7 +373,7 @@ public static string CloseSupportTicket(

## Compatibility

The SDK supports `InputRequiredException` across two protocol revisions and two session modes:
The SDK supports `InputRequiredException` across both protocol eras and both effective request modes:

| Negotiated protocol | Session mode | Behavior |
|----------------------------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
Expand All @@ -391,4 +391,4 @@ The SDK supports `InputRequiredException` across two protocol revisions and two

Under `2025-11-25` 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 `2026-07-28` 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.

Because `2026-07-28` removes `Mcp-Session-Id` (SEP-2567) and the `initialize` handshake (SEP-2575), Streamable HTTP can serve that revision only through the stateless path. The `Stateful` row for `2026-07-28` in the compatibility matrix above therefore applies to stdio and other non-HTTP stateful sessions; an HTTP server explicitly set to `Stateless = false` refuses `2026-07-28` with `UnsupportedProtocolVersion` and creates a session only when an older client falls back to `initialize`.
Because `2026-07-28` removes `Mcp-Session-Id` (SEP-2567) and the `initialize` handshake (SEP-2575), Streamable HTTP can serve that revision only through the stateless path. The `Stateful` row for `2026-07-28` in the compatibility matrix above therefore applies to stdio and other non-HTTP stateful sessions; an HTTP server explicitly set to `SessionMode = HttpServerSessionMode.Stateful` refuses `2026-07-28` with `UnsupportedProtocolVersion` and creates a session only when an older client falls back to `initialize`. `HttpServerSessionMode.StatefulForInitializeClients` ([hybrid mode](xref:stateless#hybrid-mode-sessions-for-initialize-clients-only)) serves `2026-07-28` requests through the stateless path — the `2026-07-28` / `Stateless` row — while `initialize`-handshake clients on the same endpoint follow the `2025-11-25` / `Stateful` row.
2 changes: 1 addition & 1 deletion docs/concepts/pagination/pagination.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ When implementing custom list handlers on the server, pagination is supported by

```csharp
builder.Services.AddMcpServer()
.WithHttpTransport(o => o.Stateless = true)
.WithHttpTransport(o => o.SessionMode = HttpServerSessionMode.Stateless)
.WithListResourcesHandler(async (ctx, ct) =>
{
const int pageSize = 10;
Expand Down
3 changes: 2 additions & 1 deletion docs/concepts/progress/samples/server/Program.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using ModelContextProtocol.AspNetCore;
using Progress.Tools;

var builder = WebApplication.CreateBuilder(args);
Expand All @@ -7,7 +8,7 @@
builder.Services.AddMcpServer()
.WithHttpTransport(options =>
{
options.Stateless = true;
options.SessionMode = HttpServerSessionMode.Stateless;
})
.WithTools<LongRunningTools>();

Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/prompts/prompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Register prompt types when building the server:

```csharp
builder.Services.AddMcpServer()
.WithHttpTransport(o => o.Stateless = true)
.WithHttpTransport(o => o.SessionMode = HttpServerSessionMode.Stateless)
.WithPrompts<MyPrompts>()
.WithPrompts<CodePrompts>();
```
Expand Down
6 changes: 3 additions & 3 deletions docs/concepts/resources/resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Register resource types when building the server:

```csharp
builder.Services.AddMcpServer()
.WithHttpTransport(o => o.Stateless = true)
.WithHttpTransport(o => o.SessionMode = HttpServerSessionMode.Stateless)
.WithResources<MyResources>()
.WithResources<DocumentResources>();
```
Expand Down Expand Up @@ -209,8 +209,8 @@ Register subscription handlers when building the server:
```csharp
builder.Services.AddMcpServer()
// Subscriptions require stateful mode because the server pushes change notifications
// to clients. Set Stateless = false explicitly for forward compatibility.
.WithHttpTransport(o => o.Stateless = false)
// to clients. Set SessionMode = HttpServerSessionMode.Stateful explicitly for forward compatibility.
.WithHttpTransport(o => o.SessionMode = HttpServerSessionMode.Stateful)
.WithResources<MyResources>()
.WithSubscribeToResourcesHandler(async (ctx, ct) =>
{
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/roots/roots.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ server.RegisterNotificationHandler(
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `2026-07-28`. In that revision, 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.

> [!IMPORTANT]
> `RequestRootsAsync` throws `InvalidOperationException("Roots are not supported in stateless mode.")` whenever the server is running stateless — including Streamable HTTP requests served under `2026-07-28` with `Stateless = true`. Stdio servers and initialize-handshake stateful Streamable HTTP sessions continue to work via the initialize-era server-to-client `roots/list` request flow; an HTTP server set to `Stateless = false` refuses `2026-07-28` so dual-path clients can fall back before using that flow. For code that needs to run on stateless servers — including `2026-07-28` Streamable HTTP — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
> `RequestRootsAsync` throws `InvalidOperationException("Roots are not supported in stateless mode.")` whenever the server is running stateless — including every Streamable HTTP request served under `2026-07-28`. Stdio servers and initialize-handshake stateful Streamable HTTP sessions continue to work via the initialize-era server-to-client `roots/list` request flow; an HTTP server set to `SessionMode = HttpServerSessionMode.Stateful` refuses `2026-07-28` so dual-path clients can fall back before using that flow, while `HttpServerSessionMode.StatefulForInitializeClients` instead serves `2026-07-28` statelessly on the same endpoint (see [hybrid mode](xref:stateless#hybrid-mode-sessions-for-initialize-clients-only)), so those requests use MRTR while `initialize`-handshake sessions keep this flow. For code that needs to run on stateless servers — including `2026-07-28` Streamable HTTP — throw `InputRequiredException` from your handler instead. It works across both protocol eras and all three HTTP `SessionMode` configurations.

For example:

Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/sampling/sampling.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ Sampling requires the client to advertise the `sampling` capability. This is han
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `2026-07-28`. In that revision, 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.

> [!IMPORTANT]
> `SampleAsync` and `AsSamplingChatClient` throw `InvalidOperationException("Sampling is not supported in stateless mode.")` whenever the server is running stateless — including Streamable HTTP requests served under `2026-07-28` with `Stateless = true`. Stdio servers and initialize-handshake stateful Streamable HTTP sessions continue to work via the initialize-era server-to-client `sampling/createMessage` request flow; an HTTP server set to `Stateless = false` refuses `2026-07-28` so dual-path clients can fall back before using that flow. For code that needs to run on stateless servers — including `2026-07-28` Streamable HTTP — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
> `SampleAsync` and `AsSamplingChatClient` throw `InvalidOperationException("Sampling is not supported in stateless mode.")` whenever the server is running stateless — including every Streamable HTTP request served under `2026-07-28`. Stdio servers and initialize-handshake stateful Streamable HTTP sessions continue to work via the initialize-era server-to-client `sampling/createMessage` request flow; an HTTP server set to `SessionMode = HttpServerSessionMode.Stateful` refuses `2026-07-28` so dual-path clients can fall back before using that flow, while `HttpServerSessionMode.StatefulForInitializeClients` instead serves `2026-07-28` statelessly on the same endpoint (see [hybrid mode](xref:stateless#hybrid-mode-sessions-for-initialize-clients-only)), so those requests use MRTR while `initialize`-handshake sessions keep this flow. For code that needs to run on stateless servers — including `2026-07-28` Streamable HTTP — throw `InputRequiredException` from your handler instead. It works across both protocol eras and all three HTTP `SessionMode` configurations.

For example:

Expand Down
Loading