MCP is stateless: rip out the DO-backed client path#1464
Merged
Conversation
MCP's streamable HTTP transport is fetch with metadata — there is no session state worth a Durable Object: - OutboundMcpFromOurClientCapability DO deleted (class, worker export, alchemy namespace + OUTBOUND_MCP_FROM_OUR_CLIENT_CAPABILITY binding, vitest harness wiring). Nothing dialed it after the codemode rip. - Its core helpers move to src/itx/caps/mcp-client-core.ts with clean names (connectMcp / listMcpTools / executeMcpToolCall, custom-fetch aware, close-on-failed-connect inside connect); McpClient dedupes onto them; the mock-server test moves and adapts. - The "becomes a durable-object ref when handshake latency matters" allusion in McpClient's docs is gone — the doc now states the statelessness as the design, not a tradeoff. Note for deploy: this is the repo's first DO class deletion; alchemy is expected to emit the deleted_classes migration. The preview deploy on this PR is the proof — if it refuses, fallback is a tombstone class. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jonastemplestein
added a commit
that referenced
this pull request
Jun 10, 2026
… legacy define compat, nested workspace.git (#1476) The parked debts from itx-next.md, bandaid pulled to the max per review — **no backcompat anywhere** (prd/preview/dev itx data is erasable). ## CodemodeSession tombstone — deleted The tombstone DO class, its `codemode-session-local` namespace, the `CODEMODE_SESSION` binding, and the vitest wrangler entries are gone. Alchemy emits the `deleted_classes` migration (mechanism proven in #1464). Streams that still carry durable subscriber events dialing the namespace will error on delivery — accepted, the data is being erased. ## executeCodemodeFunctionCall — protocol fully deleted (~2.5k lines) Every capability entrypoint loses its legacy dispatch method (agents, gmail, repos, secrets, slack, streams, workspace, openapi-bridge, AiCapability, OrpcCapability, test entries), along with `legacy-codemode-call.ts` and each wrapper's dead arg-validation helpers. Two callers were still alive and got clean replacements: - the agent chat/debug tool path now dials `AgentDurableObject.callAgentTool({ tool, path, args, callId })` - the ingress test entry upserts secrets via `OrpcCapability.call({ path: ["secrets", "upsert"], … })` `packages/shared/src/codemode/` → `packages/shared/src/type-tree/` (context-proxy deleted — only importer was a deleted legacy test provider); generated typing identifiers de-codemoded (`ItxConsole`, `generateContextTypesFromJsonSchema`, …). ## Registry legacy compat — deleted `caps.define` takes a `target` (SerializableCapTarget) **only**, end to end (registry, ContextDO, Project DO, handle, REPL typings): the legacy `source`/`kind: "worker" | "facet"` inputs, the `codeId` spelling of `cacheKey`, stored `worker`/`facet` kinds, the `source_json` rollback column + sync writes, and all read-side normalization are gone. All callers (browser REPL examples, every e2e suite) spell rpc/source targets directly. ## Nested `itx.workspace.git.*` — deleted Nested RpcTargets returned from entrypoint getters don't survive RPC boundaries; the flat `gitClone`/`gitAdd`/`gitCommit`/`gitPush`/`gitStatus` methods are the surface. The agent preset prompt was actively teaching the broken nested spelling — fixed. ## allowedHosts debt — closed as misdiagnosis The config is `allowedHosts: true`; the 403/502s came from a wedged vite process behind the still-connected cloudflared tunnel. Documented in itx-next.md; e2e through `os.iterate-dev-jonas.com` verified passing. ## Verification `pnpm typecheck` / `lint` / `knip` / `format` green; apps/os unit tests green; workerd suites (`test:project-ingress` 6/6, `test:itx-server-handle` 5/5 pre-#1472, `test:type-tree` 113/113) green; itx e2e (itx, fork, http, subscribe — 20 tests) green against a local dev server on the merged tree, including the post-#1474 capnweb fork. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **High Risk** > Large breaking change to capability registration, MCP/ingress execution paths, and production streams that may still dial removed CodemodeSession subscribers; preview/dev data is intentionally erasable. > > **Overview** > This PR **removes the last codemode-era wiring** and tightens the itx capability model with **no read-side backcompat**. > > **CodemodeSession** is fully removed: the tombstone Durable Object, `CODEMODE_SESSION` binding/namespace in Alchemy and vitest wrangler configs, worker exports, and the dedicated test script. MCP and tests now assume execution goes through the shared itx runner. > > **Legacy `executeCodemodeFunctionCall` dispatch is deleted** across capability entrypoints (~2.5k lines), along with `legacy-codemode-call.ts` and shared `codemode/context-proxy`. Call sites move to itx-native paths (`callAgentTool`, `OrpcCapability.call`, OpenAPI `call({ path, args })`). **`packages/shared` codemode** is renamed to **`type-tree`** with de-codemoded type-generation names. > > **`caps.define` is target-only**: required `SerializableCapTarget`, no `source`/`kind`/`codeId`, no `source_json` column or `normalizeCapTarget` on read—stored rows use `target_json` verbatim. Docs, REPL typings, e2e, and browser REPL examples all use `{ type: "rpc", worker: { type: "source", source: { cacheKey, … } } }`. > > **Workspace git** drops the nested `git` RpcTarget getter; agents, presets, e2e, and preview scripts use flat **`gitClone` / `gitAdd` / `gitCommit` / `gitPush` / `gitStatus`**. **itx-next.md** records resolved debts (legacy define, nested git, allowedHosts misdiagnosis). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 9cf0edd. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- CLOUDFLARE_PREVIEW --> ## Environment Config Lease <!-- CLOUDFLARE_PREVIEW_STATE --> <!-- { "apps": { "os": { "appDisplayName": "OS", "appSlug": "os", "status": "deployed", "updatedAt": "2026-06-10T20:40:22.067Z", "headSha": "9cf0eddaebfbcf1516be75f3e6acffdc31004f08", "message": null, "publicUrl": "https://os.iterate-preview-6.com", "runUrl": "https://github.com/iterate/iterate/actions/runs/27304663825", "shortSha": "9cf0edd" }, "semaphore": { "appDisplayName": "Semaphore", "appSlug": "semaphore", "status": "deployed", "updatedAt": "2026-06-10T20:31:34.680Z", "headSha": "0f50df98f943df63d8133e6be05dcdb33e77305c", "message": null, "publicUrl": "https://semaphore.iterate-preview-6.com", "runUrl": "https://github.com/iterate/iterate/actions/runs/27304258909", "shortSha": "0f50df9" } }, "environmentConfigLease": { "dopplerConfig": "preview_6", "leasedUntil": 1781127403360, "leaseId": "6fe10f72-e7bb-431a-9402-1abae9841129", "slug": "preview-6", "type": "environment-config-lease" } } --> <!-- /CLOUDFLARE_PREVIEW_STATE --> Lease: `preview-6` Doppler config: `preview_6` Type: `environment-config-lease` Leased until: 2026-06-10T21:36:43.360Z ### OS Status: deployed Commit: `9cf0edd` Preview: https://os.iterate-preview-6.com [Workflow run](https://github.com/iterate/iterate/actions/runs/27304663825) Updated: 2026-06-10T20:40:22.067Z ### Semaphore Status: deployed Commit: `0f50df9` Preview: https://semaphore.iterate-preview-6.com [Workflow run](https://github.com/iterate/iterate/actions/runs/27304258909) Updated: 2026-06-10T20:31:34.680Z <!-- /CLOUDFLARE_PREVIEW --> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
Final follow-up to the codemode rip (#1445/#1446/#1447). MCP's streamable HTTP transport is a stateless protocol — fetch with metadata — so nothing about an MCP client belongs in a Durable Object.
What
OutboundMcpFromOurClientCapabilityDO deleted — class, worker export, alchemy namespace +OUTBOUND_MCP_FROM_OUR_CLIENT_CAPABILITYbinding, vitest harness wiring. Nothing has dialed it since the codemode rip (its only caller was the deleted provider registration).src/itx/caps/mcp-client-core.tswith clean names:connectMcp(custom-fetch aware, closes on failed connect),listMcpTools,executeMcpToolCall.McpClientdedupes onto them; the mock-server unit test moved and adapted.McpClient's header now states statelessness as the design ("connect → call → close, per invocation; deliberately no Durable Object anywhere in this path") instead of presenting connection caching as a future optimization.Deploy note
This is the repo's first Durable Object class deletion. The DO had no SQLite (in-memory cache only) and no inbound subscribers, so deletion is data-safe; alchemy is expected to emit the
deleted_classesmigration on deploy — this PR's preview deploy is the proof. If it refuses, the fallback is a tombstone class likeCodemodeSession's.Testing
Repo typecheck / lint / knip / unit suite green locally (incl. the moved mock-server core test). The
McpCliente2e remains gated on a reachable MCP server.🤖 Generated with Claude Code
Environment Config Lease
No active environment config lease.
OS
Status: released
Commit:
5c575edPreview: https://os.iterate-preview-4.com
Summary: Preview app released.
Workflow run
Updated: 2026-06-10T15:50:34.371Z