diff --git a/apps/cloud/src/app.ts b/apps/cloud/src/app.ts index ac1dc26c0..77afa9c7f 100644 --- a/apps/cloud/src/app.ts +++ b/apps/cloud/src/app.ts @@ -13,7 +13,7 @@ import { ApiKeyService } from "./auth/api-keys"; import { cloudIdentityFailureStrategy, workosIdentityLayer } from "./auth/workos-auth-provider"; import { DbService } from "./db/db"; import { cloudMcpAuth } from "./mcp"; -import { McpSessionDO } from "./mcp/session-durable-object"; +import { McpSessionDOSqlite } from "./mcp/session-durable-object"; import { ErrorCaptureLive } from "./observability"; import { AutumnService } from "./extensions/billing/service"; import { @@ -112,7 +112,7 @@ const { appLayer, toWebHandler, mcpExport } = ExecutorApp.make({ failure: cloudIdentityFailureStrategy, // The MCP session Durable Object class — a top-level Workers export a Layer // can't return; surfaced so `server.ts` can re-export it. - mcpExport: McpSessionDO, + mcpExport: McpSessionDOSqlite, }, // The long-lived (boot-scoped) context provideMerge'd under everything: the // WorkOS control plane (the raw `WorkOSClient` + `ApiKeyService` the per-request @@ -135,7 +135,7 @@ const { appLayer, toWebHandler, mcpExport } = ExecutorApp.make({ requestScoped: RequestScopedServicesLive, }); -export { McpSessionDO }; +export { McpSessionDOSqlite }; export const CloudAppLayer = appLayer; export const cloudMcpExport = mcpExport; diff --git a/apps/cloud/src/mcp/agent-handler.ts b/apps/cloud/src/mcp/agent-handler.ts index 37c4ea64a..239215920 100644 --- a/apps/cloud/src/mcp/agent-handler.ts +++ b/apps/cloud/src/mcp/agent-handler.ts @@ -15,7 +15,7 @@ import { import type { McpSessionProps } from "@executor-js/cloudflare/mcp/agent-durable-object"; import { cloudMcpAuth } from "./auth-provider"; -import { McpSessionDO } from "./session-durable-object"; +import { McpSessionDOSqlite } from "./session-durable-object"; interface McpAgentSessionStub { readonly validateMcpSessionOwner: (identity: { @@ -111,7 +111,7 @@ const propsForPrincipal = ( }); export const makeCloudMcpAgentHandler = () => { - const serve = McpSessionDO.serve("/mcp", { + const serve = McpSessionDOSqlite.serve("/mcp", { binding: "MCP_SESSION", transport: "streamable-http", }); diff --git a/apps/cloud/src/mcp/session-durable-object.ts b/apps/cloud/src/mcp/session-durable-object.ts index bca5275da..8b0936b59 100644 --- a/apps/cloud/src/mcp/session-durable-object.ts +++ b/apps/cloud/src/mcp/session-durable-object.ts @@ -157,7 +157,7 @@ const makeSessionServices = (dbHandle: CloudSessionDbHandle) => { // Durable Object // --------------------------------------------------------------------------- -export class McpSessionDO extends McpAgentSessionDOBase { +export class McpSessionDOSqlite extends McpAgentSessionDOBase { protected override openSessionDb(): CloudSessionDbHandle { return makeDbHandle({ idleTimeout: LONG_LIVED_DB_IDLE_TIMEOUT_SECONDS, @@ -181,7 +181,7 @@ export class McpSessionDO extends McpAgentSessionDOBase dbHandle.end())), // oxlint-disable-next-line executor/no-effect-escape-hatch -- boundary: a vanished org is a defect; the worker already verified the bearer @@ -208,7 +208,7 @@ export class McpSessionDO extends McpAgentSessionDOBase ({ // not a global fetch wrapper. // --------------------------------------------------------------------------- -export const McpSessionDO = Sentry.instrumentDurableObjectWithSentry( +export const McpSessionDOSqlite = Sentry.instrumentDurableObjectWithSentry( sentryOptions, McpSessionDOBase, ); diff --git a/apps/cloud/wrangler.jsonc b/apps/cloud/wrangler.jsonc index 19a81e71f..f2cc4a143 100644 --- a/apps/cloud/wrangler.jsonc +++ b/apps/cloud/wrangler.jsonc @@ -20,16 +20,17 @@ "bindings": [ { "name": "MCP_SESSION", - "class_name": "McpSessionDO", + "class_name": "McpSessionDOSqlite", }, ], }, // The MCP session DO moved to the Cloudflare Agents (`McpAgent`) base, which - // stores state in SQLite. `McpSessionDO` was originally created with the + // stores state in SQLite. The original `McpSessionDO` was created with the // key-value backend (`new_classes`), and Cloudflare cannot convert a live class - // to SQLite in place. Session state is ephemeral, so v2 deletes the KV class and - // v3 recreates the same name on the SQLite backend. Keeping the name avoids any - // binding/export rename. + // to SQLite in place, nor delete a class while a binding still references it. + // Session state is ephemeral, so v2 repoints the `MCP_SESSION` binding to a new + // SQLite-backed class (`McpSessionDOSqlite`) and deletes the old KV `McpSessionDO` + // (now unreferenced). The worker exports `McpSessionDOSqlite`, not `McpSessionDO`. "migrations": [ { "tag": "v1", @@ -38,10 +39,7 @@ { "tag": "v2", "deleted_classes": ["McpSessionDO"], - }, - { - "tag": "v3", - "new_sqlite_classes": ["McpSessionDO"], + "new_sqlite_classes": ["McpSessionDOSqlite"], }, ], "services": [