Table of Contents

Session mode

ThargaMcpOptions.SessionMode decides how the HTTP transport tracks state between requests.

builder.Services.AddThargaMcp(mcp =>
{
    mcp.Options.SessionMode = McpSessionMode.StatefulForInitializeClients;
});

The default is McpSessionMode.Stateless, and most hosts should leave it alone.

Why this option exists

Protocol revision 2026-07-28 removed Mcp-Session-Id (SEP-2567) and the initialize handshake (SEP-2575). ModelContextProtocol 2.0.0 implemented that by defaulting the HTTP transport to stateless, and Tharga.Mcp picked the change up transitively.

For clients that had negotiated a session against an earlier revision, the next call after that upgrade fails:

Bad Request: The Mcp-Session-Id header is not supported in stateless mode

The message is accurate but misleading — it reads as a misconfigured server rather than as the protocol revision changing underneath the client. Until this option existed there was no way to turn it back on through Tharga.Mcp, so a host in that position had no route forward but to pin an older package.

The three modes

Mode Legacy clients 2026-07-28+ clients Needs session affinity
Stateless (default) Rejected Served No
Stateful Full session Forced to downgrade Yes
StatefulForInitializeClients Full session Served statelessly Yes

Stateless

No session id is minted or echoed. The GET, DELETE and /sse endpoints answer 405 Method Not Allowed. The server cannot send unsolicited messages or make requests of the client, so sampling, elicitation and roots are unavailable — use MRTR instead.

In exchange the endpoint needs no session affinity, so it can sit behind more than one instance. That is why it is the right default and worth returning to once your clients have moved.

Stateful

Every client gets a long-lived session, which requires session affinity.

The cost is easy to miss: a client that declares 2026-07-28 or later is refused with -32022 UnsupportedProtocolVersion and has to downgrade to the initialize handshake. A modern client pays for a legacy one. If both kinds call the same endpoint, prefer the hybrid below.

StatefulForInitializeClients

The migration mode. Clients on 2025-11-25 or earlier get a full session with an Mcp-Session-Id and keep using the GET and DELETE endpoints; clients on 2026-07-28 or later are served per request with no session minted, exactly as in Stateless. Neither is forced to downgrade.

This lets an application adopt the new revision progressively instead of waiting for every client to migrate. Session-only features stay unavailable to the stateless half.

When the value is read

SessionMode is read when the transport options are resolved, not when AddThargaMcp returns, so setting it anywhere inside the registration callback works:

builder.Services.AddThargaMcp(mcp =>
{
    mcp.AddTeam();
    mcp.Options.SessionMode = McpSessionMode.Stateful;   // order does not matter
});

Choosing

  • New deployment, or all clients current — leave it at Stateless.
  • Existing clients broke on the upgrade to 2.x — StatefulForInitializeClients.
  • Every client is legacy and you want the simplest thing — Stateful, accepting that it needs session affinity and that any modern client will be downgraded.

Treat anything other than Stateless as temporary. Session affinity is a real constraint on how the endpoint can be hosted, and the protocol has moved.