Skip to content

feat(mcp): durable Tasks-extension records across server restarts - #745

Merged
ecto merged 2 commits into
claude/mcp-2026-07-28-support-6376a9from
claude/cranky-jones-4caa82
Jul 29, 2026
Merged

ecto merged 2 commits into
claude/mcp-2026-07-28-support-6376a9from
claude/cranky-jones-4caa82

Conversation

@ecto

@ecto ecto commented Jul 29, 2026

Copy link
Copy Markdown
Owner

What

Stacked on #743 (retarget to main after it merges). Completes the first follow-up from that PR: Tasks-extension records now survive server restarts — without pretending a half-run background tool can resume (it can't; the in-process bridge dies with the process).

Three guarantees:

  1. Terminal tasks survive. When a task reaches completed/failed/cancelled, the serializable record (taskId, status, statusMessage, timestamps, toolName, result, error) persists to a durable task store (packages/mcp/src/task-store.ts, mirroring the session-store pattern exactly): file store under <sessionDir>/tasks locally, Supabase mcp_tasks (migration 037, capability-keyed + service-role-only like mcp_artifacts) when the env is present, in-memory no-op otherwise. tasks/get hydrates from the store on a cache miss before reporting unknown, and re-caches.
  2. Orphaned in-flight tasks report honestly. taskIds now embed the minting process's boot token (task_<tok>_<random>, same scheme as session ids). A prior-boot taskId with no durable terminal record gets a status:"failed" task result explaining the server restarted mid-run and the call should be re-issued — not an unknown-id error. A same-boot unknown id still errors as a typo.
  3. Durability honesty. When isSessionStoreDurable() is false, the CreateTaskResult statusMessage notes the handle will not survive a restart (the session-minting tools' pattern).

Not included

Verification

  • 7 new tests in protocol-2026.test.ts (env-isolated temp dir, per the durability-smoke pattern): terminal round-trip through a simulated restart, failed-by-restart orphan reporting on get and cancel, typo-vs-restart distinction, TTL expiry through the store, and both durability-note branches
  • Full suite: 1081 passed / 97 files; tsc --noEmit clean; deprecated-surface tripwire green

🤖 Generated with Claude Code

Terminal task records (completed/failed/cancelled) now persist to a durable
task store mirroring the session-store pattern: file store under
<sessionDir>/tasks locally, Supabase mcp_tasks (migration 037) when the
service-role env is present, in-memory no-op otherwise. tasks/get hydrates
from the store on a cache miss before reporting unknown.

taskIds now embed the minting process's boot token (same scheme as session
ids), so a taskId orphaned by a restart — in-flight tasks cannot resume, the
bridge dies with the process — reports an honest failed-by-restart status
with a re-issue remediation instead of an unknown-id error. When the store is
not durable, the CreateTaskResult statusMessage says the handle will not
survive a restart.

Migration 037 is NOT yet pushed to prod (supabase db push deploys it).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vcad-mcp Building Building Preview, Comment Jul 29, 2026 5:23pm
3 Skipped Deployments
Project Deployment Actions Updated (UTC)
mecheval Ignored Ignored Jul 29, 2026 5:23pm
vcad Ignored Ignored Jul 29, 2026 5:23pm
vcad-docs Ignored Ignored Jul 29, 2026 5:23pm

Request Review

@chojiai

chojiai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Choji live review — Looks good — no findings

Choji review — Looks good

The prior findings (P1 fire-and-forget race, P2 timing-dependent sleep) are both resolved: pendingPersists tracking + flushTaskPersists() replaces the 100 ms sleep, and the persist promise is correctly removed from the set in its own finally handler. The new logic is sound — boot-token discrimination, store hydration on cache miss, and orphan reporting all look correct.

No findings — looks good.


Verified by Choji

Choji ran your change live — checks failed.

2 checks.

Claim Result Evidence
npm run test Unverified — environment sandbox failure, not your PR
npm run typecheck Unverified — environment sandbox failure, not your PR

Checks marked environment failed in Choji's sandbox, not against your PR. They never block.

No live preview was run for this backend/MCP change. The npm run test and npm run typecheck checks both failed, but the failure is entirely caused by wasm-pack being an invalid shim in Choji's environment (mise ERROR wasm-pack is not a valid shim) — the vcad-kernel-wasm#build step aborted before any MCP tests ran. This is an infra-environment failure unrelated to the PR's code. The PR description states 1081 tests passed including 7 new durability tests in protocol-2026.test.ts, which could not be independently confirmed here due to the environment issue. The diff itself is internally consistent: task-store.ts mirrors session-store.ts's pattern, the new handleTaskMethod is now async and properly awaits the store, boot-token extraction and orphan detection logic are wired correctly, and the SQL migration follows the same RLS/service-role model as migration 033. No visual or behavioral regressions are observable.

No issues found in the running app.


Rate findings

Reviewed e8446dd · Choji updates this comment as you push · Mention @chojiai in a comment to discuss, re-review, or request a fix

chojiai[bot]
chojiai Bot previously approved these changes Jul 29, 2026
… round-trip test

Track in-flight terminal-record writes in a module-level set and expose
flushTaskPersists(); the durability test awaits it instead of sleeping 100ms
and hoping the fire-and-forget save landed. (Choji review on #745.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ecto

ecto commented Jul 29, 2026

Copy link
Copy Markdown
Owner Author

Addressed the Choji findings in e8446dd: terminal-record persists are now tracked in a module-level set with an exported flushTaskPersists(), and the restart round-trip test awaits it instead of a 100 ms sleep — no timing dependence, and shutdown/test callers can drain pending writes. (An in-memory prune racing a persist was already safe: prune only drops the warm cache; the store write completes independently, and the file store's write-then-rename can't leave a torn record.)

🤖 Addressed by Claude Code

@chojiai
chojiai Bot dismissed their stale review July 29, 2026 17:24

Dismissing prior approval to re-evaluate e8446dd.

@ecto
ecto merged commit 580cb54 into claude/mcp-2026-07-28-support-6376a9 Jul 29, 2026
17 checks passed

This branch was successfully deployed

1 active deployment
Preview – vcad-mcp — e8446dde Deployed Jul 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant