Skip to content

feat(mcp): resume downstream MCP sessions on any replica - #1340

Draft
SantiagoDePolonia wants to merge 2 commits into
mainfrom
feat/mcp-sessions-across-replicas
Draft

SantiagoDePolonia wants to merge 2 commits into
mainfrom
feat/mcp-sessions-across-replicas

Conversation

@SantiagoDePolonia

@SantiagoDePolonia SantiagoDePolonia commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Description

  • An Mcp-Session-Id issued by one replica now works on every replica on the same PostgreSQL or MongoDB database, so MCP clients no longer need sticky sessions.
  • The replica that answers initialize writes the session's binding to the core shared store (mcp.sessions namespace) before the response carries the ID: auth key ID, user path, endpoint, X-MCP-Servers scope, discovery mode, the client's initialize parameters, and the negotiated protocol version.
  • go-sdk v1.8.0 cannot adopt a session it did not create. Its handler keeps sessions in a private map with no store hook, and Stateless drops sessions altogether. It does export StreamableServerTransport and Server.Connect with ServerSessionOptions.State, so a replica that gets an unknown ID rebuilds the session from its record. It then serves that session's GET/POST/DELETE itself, with the SDK handler's request checks and idle timeout. Sessions a replica creates still go through the SDK handler unchanged.
  • Security model: the record is keyed by a SHA-256 digest of the session ID and holds no secrets. Every replica checks auth key, user path, and endpoint against it before resuming or serving, so a leaked ID under another identity gets 404 everywhere. A rejected request does not create a session.
  • DELETE writes a close mark and deletes the record. Deleting a virtual server writes an endpoint close mark with a timestamp, so its sessions end on every replica and a virtual server recreated under the same name does not revive them. A replica serving a session rereads the close marks at most every 2 s, and extends the record's 30-minute expiry at most once a minute. Most requests touch no database.
  • Survives a replica switch: tool calls, listings, prompts, resources, scope and discovery mode, negotiated protocol version, client info and capabilities, and the principal binding.
  • Does not survive: a response stream in flight on a replica that stops (the client sees that request fail), and the open GET stream, which stays on its replica until the client reconnects it. Last-Event-ID replay was never supported. The gateway sends no sampling, elicitation, or roots requests, so none can be stranded.
  • Fallback: with SQLite, or when the shared store cannot be written at initialize, sessions stay local as before. When a store read fails, a session this replica already serves keeps working, and a session it would have to resume answers 404, so the client re-initializes.
  • The core shared store is now also created when the MCP gateway runs on PostgreSQL or MongoDB.
  • Docs: the MCP row of the replica table in production.mdx, and a new "Sessions across replicas" section in the MCP gateway page.

Tests: two Service instances share one store on SQLite, PostgreSQL, and MongoDB. Covered: resume with tools/list and tools/call, foreign key/user path/endpoint rejection, DELETE from either side, and virtual server deletion and recreation. Idle expiry and the bounded touch rate run against a clock-driven store. Plus the no-store fallback and the storage-type switch.

View guided diff Turn on auto-fix

@mintlify

mintlify Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
gomodel 🟢 Ready View Preview Oct 30, 2026, 2:39 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

@coderabbitai

coderabbitai Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the size:XL 500-999 effective changed lines (test files excluded in mixed PRs). label Oct 30, 2026
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 86.94268% with 41 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/mcpgateway/sharedsessions.go 89.09% 24 Missing ⚠️
internal/mcpgateway/resumedsession.go 75.47% 13 Missing ⚠️
internal/mcpgateway/service.go 90.62% 3 Missing ⚠️
internal/app/init_server.go 75.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

This branch was successfully deployed

1 active deployment
staging - docs — d8341262 Deployed Oct 30, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 effective changed lines (test files excluded in mixed PRs).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants