Skip to content

fix(aspnetcore): explain why a stateful session lookup failed - #1876

Open
ump45nose wants to merge 1 commit into
modelcontextprotocol:mainfrom
ump45nose:contrib/e4e4cded3f40
Open

fix(aspnetcore): explain why a stateful session lookup failed#1876
ump45nose wants to merge 1 commit into
modelcontextprotocol:mainfrom
ump45nose:contrib/e4e4cded3f40

Conversation

@ump45nose

Copy link
Copy Markdown

Summary

Related to #1861. A stateful server answers a request for a session it does not have with 404 and the bare message Session not found. That is exactly what a multi-instance deployment without session affinity produces — or a restart that drops in-memory sessions — and the report shows the result: intermittent connection failures with nothing in the response pointing at load balancing or at stateful mode.

Three changes:

1. The 404 explains itself. The message now names the likely cause and both remedies, in the same shape as the sibling session errors, which already point at stateless mode and the docs:

Session not found: The server has no session for this Mcp-Session-Id. Sessions are held in memory by the
instance that created them, so a request for an existing session must reach that same instance; configure
session affinity (sticky sessions) when running more than one instance behind a load balancer. If your
server doesn't need sessions, enable stateless mode by setting HttpServerTransportOptions.SessionMode =
HttpServerSessionMode.Stateless. See https://csharp.sdk.modelcontextprotocol.io/concepts/stateless/stateless.html
for more details.

The -32001 code, the 404 status, and the Session not found prefix are unchanged, so clients that match on either keep working. Legacy Streamable HTTP clients and raw HTTP tooling (the Postman MCP client and the inspector used in the report) see this text directly.

2. The unknown-session path is now covered. Stateful_UnknownSessionId_Returns404WithSessionAffinityGuidance replays the load-balanced case against a real ASP.NET Core server: no initialize is performed, the request carries a session id minted by "another instance", and the test asserts the status, the -32001 code and the guidance. Nothing in the repository referenced -32001 or this message before, so the path was entirely uncovered.

3. The affinity requirement is visible where SessionMode is configured. transports.md already told readers to set Stateful explicitly, and its comparison table already said "Requires session affinity", but the consequence — and the reason a multi-instance deployment fails intermittently — only appeared in the stateless guide. The sentence that tells readers to configure stateful mode now carries it too.

Not changed: stateful sessions still require session affinity. This PR does not add cross-instance session storage, and it does not change session semantics — it makes an existing failure mode diagnosable. If you would rather keep the wire message minimal and put this in a server log instead, I'm happy to move it.

Verification

  • The new test fails before the message change, at Assert.Contains("session affinity", message), and passes after. The 404 and -32001 assertions passed both before and after, which is how I confirmed the scenario reaches the intended path rather than a protocol-version rejection.
  • dotnet test tests/ModelContextProtocol.AspNetCore.Tests -f net10.0 → 621 passed, 0 failed, 46 skipped.
  • Targeted: --filter "FullyQualifiedName~Stateful_UnknownSessionId|FullyQualifiedName~Client_CanReconnect_AfterSessionExpiry" → 2 passed, 2 skipped (the skipped pair are the stateless-mode variants, which have no sessions).

Related to #1861.

AI assistance disclosure: AI was used to discover this opportunity and draft the change or text. The submission was checked against the prepared artifact and recorded verification evidence.

A request for an Mcp-Session-Id this instance does not know is answered with
`404 Session not found` and nothing else. That is what an operator sees when a
stateful server runs more than one instance without session affinity, or after
a restart drops in-memory sessions, and the bare message made a deployment
misconfiguration look like a client bug.

Report the likely cause and both remedies (session affinity, or stateless mode)
in the error, matching the guidance the sibling session errors already carry,
and cover the unknown-session path with a test that replays the load-balanced
case. Also state the affinity requirement in the sentence that tells readers to
configure SessionMode, not only in the stateless guide.

The -32001 code, the 404 status, and the "Session not found" prefix are
unchanged.

Related to modelcontextprotocol#1861
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant