MCP tasks/cancel vs Sume jobs_cancel: cancel works only before start

TypeScript SDK 2.3.0 adds tasks/get and tasks/cancel. Sume's jobs_cancel is narrower: it succeeds only before generation starts, then returns 409.

4 min readSume
All posts

An MCP task cancel and a Sume job cancel are not the same promise. Sume's jobs_cancel works only while a job is still waiting; once generation has started the API answers 409 job_generation_already_started and the job runs to completion and bills.

The TypeScript SDK 2.3.0 release added tasks/get and tasks/cancel, so it is worth being clear about what a cancel button can honestly do for a paid render.

The task side

In the 2026-07-28 specification, the experimental tasks feature moved to the official extension io.modelcontextprotocol/tasks. The blocking tasks/result call was replaced by polling tasks/get plus tasks/update, tasks/list was removed, and servers may return task handles unsolicited.

Task calls and their Sume counterparts (read 2026-10-03)
MCP task callClosest Sume hosted toolNotes
tasks/getjobs_statusRead-only status for one job.
tasks/canceljobs_cancelNeeds a write session and an idempotency_key.
tasks/list (removed)jobs_listLists jobs visible to the credential.

What jobs_cancel guarantees

The Sume docs state the rule plainly. Cancellation succeeds only before generation work starts. After that the API returns 409 job_generation_already_started with details.cancelable: false, and the job completes or fails normally.

Two related cases matter for a retry loop. Cancelling a job that is already canceled is idempotent and returns the same canceled job. A job that is already completed is a different 409, job_not_cancelable.

  • queued: cancel is possible while the job waits for a concurrency slot.
  • processing: cancel may already be too late; expect the 409.
  • completed, failed: nothing to cancel.

Why queued time is the cancel window

Sume admits paid jobs queue-first. Concurrency is a dispatch limit, so a valid submit can be accepted as queued and wait for a slot. That wait is where cancel is useful: if a user changes their mind, or a batch is no longer needed, the queued jobs can be cancelled before they cost anything.

The admission docs recommend exactly this when you hit queue_full: poll existing jobs, cancel queued jobs that are no longer needed, and retry with the same idempotency key once capacity opens.

Design a cancel button honestly

If you wrap Sume generation in your own task-style interface, map the 409 to a clear state instead of pretending the cancel worked.

  • Call jobs_cancel with its own idempotency_key and read the result.
  • On job_generation_already_started, show the job as still running and keep waiting with jobs_wait slices.
  • Do not resubmit the original paid request just because the user pressed cancel and the cancel failed.
  • Treat a client-side timeout as different from a cancel: stopping to watch a job does not stop it.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume