Add stateless doc, prefer stateless mode and disable legacy SSE by default (#1468)

This commit is contained in:
Stephen Halter 2026-03-27 13:56:16 -07:00 • committed by GitHub
commit 8eb4023c20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 1440 additions and 73 deletions

View file

@ -29,3 +29,16 @@ The following code snippet shows the `ContextTools` class accepting an [IHttpCon
and the `GetHttpHeaders` method accessing the current [HttpContext] to retrieve the HTTP headers from the current request.
[!code-csharp[](samples/Tools/ContextTools.cs?name=snippet_AccessHttpContext)]
### SSE transport and stale HttpContext
When using the legacy SSE transport, be aware that the `HttpContext` returned by `IHttpContextAccessor` references the long-lived SSE connection request — not the individual `POST` request that triggered the tool call. This means:
- The `HttpContext.User` may contain stale claims if the client's token was refreshed after the SSE connection was established.
- Request headers, query strings, and other per-request metadata will reflect the initial SSE connection, not the current operation.
The Streamable HTTP transport does not have this issue because each tool call is its own HTTP request, so `IHttpContextAccessor.HttpContext` always reflects the current request. In [stateless](xref:stateless) mode, this is guaranteed since every request creates a fresh server context.
<!-- mlc-disable-next-line -->
> [!NOTE]
> The server validates that the user identity has not changed between the session-initiating request and subsequent requests (using the `sub`, `NameIdentifier`, or `UPN` claim). If the user identity changes, the request is rejected with `403 Forbidden`. However, other claims (roles, permissions, custom claims) are not re-validated and may become stale over the lifetime of a session.

View file

@ -5,7 +5,10 @@ var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithHttpTransport(options =>
{
options.Stateless = true;
})
.WithTools<ContextTools>();
// <snippet_AddHttpContextAccessor>