MCP session cold init resilience - #1787
Merged
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | c849005 | Aug 28 2026, 12:04 AM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | c849005 | Commit Preview URL Branch Preview URL |
Aug 28 2026, 12:03 AM |
Contributor
Cloudflare previewTorn down — the PR is closed. |
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/plugin-file-secrets
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
RhysSullivan
force-pushed
the
fix/mcp-session-cold-init
branch
from
August 28, 2026 00:01
0d3fa81 to
c849005
Compare
RhysSullivan
marked this pull request as ready for review
August 28, 2026 00:43
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every cold start of an MCP session Durable Object opened a brand-new Postgres
connection purely to re-read the
organizationsrow the worker had already readmicroseconds earlier on the same request: the authorization check resolved the
full org record and then threw the name away (
organizationName: ""). On a coldrestore the DO also already held that identity in its own storage, and asked the
database first anyway.
When the database was slow to accept that connection, the read hung for the whole
connect budget and then died as an unclassified internal error — so restoring a
session failed with a bare 500 on a database that was, at that same moment,
answering the worker's own queries in milliseconds. The retry the agents SDK then
performs on the whole DO operation turned a short blip into a client-visible hang.
The store error it carried also had an empty field set: no failing operation, no
reason, so the report was undiagnosable on its own.
Fix
McpOrganizationAuth.authorizereturns the resolved organization record ratherthan just its id; the principal and the session props carry its name and slug.
meta this session already persisted (same organization only) → the database.
failures and fails into the same classified, retryable 503 with
Retry-Afterthe auth path already returns, instead of
orDieand a bare 500.UserStoreErrorcarriesoperationand areasonclassified from thedriver cause chain, and those safe fields are promoted onto error-report tags
(the pretty cause is only an
extra, which is scrubbed server-side).Relationship to the Durable-Object error classifier
That work landed on
mainfirst (#1788) and this branch is rebased onto it.Where the two overlapped,
main's shapes are canonical and this branch'ssemantics sit on top of them:
double-report;
main's fix is the one kept. The DO seam still captures andthen claims the cause, and the host's own instrumentation drops its echo of
a claimed cause. This branch originally removed the seam's capture instead —
that removal is dropped, since combined with the claim it would have left an
init failure reported by nobody.
directory is an application failure that merely escapes through the same seam
as a platform reset, so it keeps its own 503 envelope and its own message, and
is checked ahead of
classifyDurableObjectErrorrather than folded into it.The two vocabularies do not currently overlap; the ordering keeps it that way
if either grows.
Testing
Primary is the new e2e scenario
e2e/cloud/mcp-session-cold-init.test.ts(cloudproject), black-box over the MCP wire plus the exported spans:
initializemints a session and the same session id then serves
tools/list, and that oneinit request performs exactly ONE
organizationsread — the worker's ownauthorization check — with no database step inside the Durable Object. The count
is only taken once a worker-plane span for the same trace has landed, so an
unflushed worker batch cannot make a two-read request look like a one-read one.
Verified red against the pre-fix product code (two reads on one
initialize)and green with the fix, and green three consecutive times plus once under load
alongside the sibling MCP scenarios.
Unit tests are kept only for seams the e2e harness cannot observe: the stored-meta
and database fallback sources and the bounded retry (post-fix the props always
name the org on cloud, so no black-box request can reach those branches), the
driver-cause classification of the store error, and the restore ordering on the
base Durable Object.
A frozen-database repro was attempted and does not work here: the harness runs one
single-process PGlite shared by the worker and the DO, and the worker's own
authorization reads that same
organizationsrow on the same request — sofreezing it fails the request before init identically on both sides of the fix,
with no green side. The read-count assertion above is the closest black-box repro
the harness allows.
Post-rebase,
mcp-destroyed-session-envelope.test.ts(the classifier's ownscenario from
main) passes alongside the new one, so the convergence keeps bothbehaviours.
typecheck,lint,format:checkand the affected unit suites pass.