Is there an existing issue for this?
Description
On Appsmith Cloud, the embedded MCP server (appsmith-mcp 0.0.1) accepts initialize and returns an Mcp-Session-Id, but then rejects that same session id on nearly every follow-up request:
HTTP 404
{"error":"session not found; initialize a new MCP session"}
Result: every standard MCP client (Claude Code, etc.) connects, initializes successfully, fails on its first real call (tools/list), and drops the server. The MCP feature is effectively unusable on Cloud.
Cause (in source): sessions are stored in a per-process Map —
app/client/packages/mcp/src/app.ts:7011
const sessions = new Map<string, McpSession>();
registered in onsessioninitialized (app.ts:7282, sessionIdGenerator: randomUUID) and removed in transport.onclose. With more than one replica behind a load balancer that has no session affinity, initialize lands on replica A and registers the session there, while subsequent POSTs are balanced across the other replicas, none of which know the id.
Note that #42210 ("Now Mcp also accepts redis cluster", merged 2026-09-08) moved governance state into Redis (governance/store.ts) but did not touch the transport session map, so that path is still per-process.
Stateless mode is not available as a workaround: tools/list without a session id returns 400 {"error":"initialize the MCP session first"}.
What I expect: a session issued at initialize is honored by all subsequent requests carrying its Mcp-Session-Id, regardless of which replica serves them.
Steps To Reproduce
Against a Cloud tenant, with a valid MCP key as bearer token (from the "Connect an MCP client" page):
POST /mcp with an initialize request → 200 OK, Mcp-Session-Id header present, correct handshake body (serverInfo: appsmith-mcp 0.0.1, protocol 2025-06-18).
POST /mcp with that Mcp-Session-Id header and {"jsonrpc":"2.0","id":2,"method":"tools/list"}.
- Repeat step 2 against the same session id.
Twelve consecutive attempts on one session id:
Oxxxxxxxxxxx → 1 success, 11 × "session not found"
Roughly 1 in 12 requests succeeds, consistent with a dozen or so replicas behind a non-sticky balancer. No Set-Cookie is issued on initialize, so a client has nothing to echo back for affinity.
Initialize response headers:
HTTP/1.1 200 OK
Mcp-Session-Id: 805e04fd-964f-47ea-a0d7-c12c314fb2a2
Via: 1.1 Caddy, 1.1 <redacted>.cloudfront.net (CloudFront)
X-Appsmith-Request-Id: 74a64b33-167c-4ceb-ac8e-2e6711108b51
Auth is not the problem: without a token the endpoint returns a clean 401 + WWW-Authenticate: Bearer, and with the token initialize succeeds every time.
Suggested fixes
- Short term (ops): session affinity at the Caddy/CDN layer keyed on the
Mcp-Session-Id header.
- Medium term: back the session map with the shared Redis already used by the governance store, so any replica can serve any session.
- Alternative: run the transport stateless (
sessionIdGenerator: undefined) where per-session server state isn't required.
Public Sample App
No response — not app-specific; reproduces at the transport layer with any tenant and any MCP key.
Environment
Production
Severity
High (Blocker to building or releasing)
Issue video log
No response
Version
Cloud — appsmith-mcp 0.0.1 (per initialize handshake), tested 2026-09-16
Is there an existing issue for this?
Description
On Appsmith Cloud, the embedded MCP server (
appsmith-mcp 0.0.1) acceptsinitializeand returns anMcp-Session-Id, but then rejects that same session id on nearly every follow-up request:Result: every standard MCP client (Claude Code, etc.) connects, initializes successfully, fails on its first real call (
tools/list), and drops the server. The MCP feature is effectively unusable on Cloud.Cause (in source): sessions are stored in a per-process Map —
app/client/packages/mcp/src/app.ts:7011registered in
onsessioninitialized(app.ts:7282,sessionIdGenerator: randomUUID) and removed intransport.onclose. With more than one replica behind a load balancer that has no session affinity,initializelands on replica A and registers the session there, while subsequent POSTs are balanced across the other replicas, none of which know the id.Note that #42210 ("Now Mcp also accepts redis cluster", merged 2026-09-08) moved governance state into Redis (
governance/store.ts) but did not touch the transport session map, so that path is still per-process.Stateless mode is not available as a workaround:
tools/listwithout a session id returns400 {"error":"initialize the MCP session first"}.What I expect: a session issued at
initializeis honored by all subsequent requests carrying itsMcp-Session-Id, regardless of which replica serves them.Steps To Reproduce
Against a Cloud tenant, with a valid MCP key as bearer token (from the "Connect an MCP client" page):
POST /mcpwith aninitializerequest →200 OK,Mcp-Session-Idheader present, correct handshake body (serverInfo: appsmith-mcp 0.0.1, protocol2025-06-18).POST /mcpwith thatMcp-Session-Idheader and{"jsonrpc":"2.0","id":2,"method":"tools/list"}.Twelve consecutive attempts on one session id:
Roughly 1 in 12 requests succeeds, consistent with a dozen or so replicas behind a non-sticky balancer. No
Set-Cookieis issued oninitialize, so a client has nothing to echo back for affinity.Initialize response headers:
Auth is not the problem: without a token the endpoint returns a clean
401+WWW-Authenticate: Bearer, and with the tokeninitializesucceeds every time.Suggested fixes
Mcp-Session-Idheader.sessionIdGenerator: undefined) where per-session server state isn't required.Public Sample App
No response — not app-specific; reproduces at the transport layer with any tenant and any MCP key.
Environment
Production
Severity
High (Blocker to building or releasing)
Issue video log
No response
Version
Cloud —
appsmith-mcp 0.0.1(perinitializehandshake), tested 2026-09-16