Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/cloud/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -135,7 +135,7 @@ const { appLayer, toWebHandler, mcpExport } = ExecutorApp.make({
requestScoped: RequestScopedServicesLive,
});

export { McpSessionDO };
export { McpSessionDOSqlite };

export const CloudAppLayer = appLayer;
export const cloudMcpExport = mcpExport;
Expand Down
4 changes: 2 additions & 2 deletions apps/cloud/src/mcp/agent-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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",
});
Expand Down
10 changes: 5 additions & 5 deletions apps/cloud/src/mcp/session-durable-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ const makeSessionServices = (dbHandle: CloudSessionDbHandle) => {
// Durable Object
// ---------------------------------------------------------------------------

export class McpSessionDO extends McpAgentSessionDOBase<Env, CloudSessionDbHandle> {
export class McpSessionDOSqlite extends McpAgentSessionDOBase<Env, CloudSessionDbHandle> {
protected override openSessionDb(): CloudSessionDbHandle {
return makeDbHandle({
idleTimeout: LONG_LIVED_DB_IDLE_TIMEOUT_SECONDS,
Expand All @@ -181,7 +181,7 @@ export class McpSessionDO extends McpAgentSessionDOBase<Env, CloudSessionDbHandl
elicitationMode: token.elicitationMode,
} satisfies SessionMeta;
}).pipe(
Effect.withSpan("McpSessionDO.resolveSessionMeta"),
Effect.withSpan("McpSessionDOSqlite.resolveSessionMeta"),
Effect.provide(makeSessionServices(dbHandle)),
Effect.ensuring(Effect.promise(() => dbHandle.end())),
// oxlint-disable-next-line executor/no-effect-escape-hatch -- boundary: a vanished org is a defect; the worker already verified the bearer
Expand All @@ -208,7 +208,7 @@ export class McpSessionDO extends McpAgentSessionDOBase<Env, CloudSessionDbHandl
// billing service degrades to a no-op tracker, so this stays inert in
// cloud dev/preview environments that run without a billing backend.
Effect.provide(CloudMeteredExecutionStackLayer.pipe(Layer.provide(AutumnService.Default))),
Effect.withSpan("McpSessionDO.makeExecutionStack"),
Effect.withSpan("McpSessionDOSqlite.makeExecutionStack"),
);
// Build the description here so `executor.connections.list()` stays under
// the DO startup span and the MCP SDK receives a concrete string instead
Expand All @@ -235,10 +235,10 @@ export class McpSessionDO extends McpAgentSessionDOBase<Env, CloudSessionDbHandl
}),
}
: { mode: sessionElicitationMode },
}).pipe(Effect.withSpan("McpSessionDO.createExecutorMcpServer"));
}).pipe(Effect.withSpan("McpSessionDOSqlite.createExecutorMcpServer"));
return { mcpServer, engine } satisfies BuiltMcpServer;
}).pipe(
Effect.withSpan("McpSessionDO.buildMcpServer"),
Effect.withSpan("McpSessionDOSqlite.buildMcpServer"),
Effect.provide(makeSessionServices(dbHandle)),
// oxlint-disable-next-line executor/no-effect-escape-hatch -- boundary: runtime-build failures surface as the base's tapCause/cleanup defect
Effect.orDie,
Expand Down
4 changes: 2 additions & 2 deletions apps/cloud/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import handler from "@tanstack/react-start/server-entry";
import { isAppOwnedPath } from "./app-paths";
import { makeCloudMcpAgentHandler } from "./mcp/agent-handler";
import { classifyMcpPath, prepareMcpOrgScope } from "./mcp/mount";
import { McpSessionDO as McpSessionDOBase } from "./mcp/session-durable-object";
import { McpSessionDOSqlite as McpSessionDOBase } from "./mcp/session-durable-object";
import { browserTracesResponse } from "./observability/browser-traces";
import { flushTracerProvider, installTracerProvider } from "./observability/telemetry";

Expand Down Expand Up @@ -41,7 +41,7 @@ const sentryOptions = (env: Env) => ({
// not a global fetch wrapper.
// ---------------------------------------------------------------------------

export const McpSessionDO = Sentry.instrumentDurableObjectWithSentry(
export const McpSessionDOSqlite = Sentry.instrumentDurableObjectWithSentry(
sentryOptions,
McpSessionDOBase,
);
Expand Down
16 changes: 7 additions & 9 deletions apps/cloud/wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -38,10 +39,7 @@
{
"tag": "v2",
"deleted_classes": ["McpSessionDO"],
},
{
"tag": "v3",
"new_sqlite_classes": ["McpSessionDO"],
"new_sqlite_classes": ["McpSessionDOSqlite"],
},
],
"services": [
Expand Down
Loading