MCP Tasks for Long-Running Video Renders
How the MCP Tasks extension handles a tool call that runs for minutes, how it maps onto a render job ID, and what to build before your client supports it.
Founder

A video render takes longer than an MCP tool call should wait. The
2026-07-28 MCP specification answers this with the Tasks extension: the
server returns a durable taskId at once, and the client polls tasks/get
until the work is done. Renderly's MCP connector does not use the extension
yet. It uses the older pattern that Tasks formalizes: renderly_create_render
returns a jobId, and the agent polls renderly_get_render_status or waits
for a webhook. This post explains both, maps one onto the other, and says what
to build now.
Key Takeaways
- In the 2026-07-28 MCP spec, Tasks moved out of the experimental core into an official extension,
io.modelcontextprotocol/tasks.- A task handle carries
taskId,status,ttlMsandpollIntervalMs. The client pollstasks/get, answers questions withtasks/updateand can ask fortasks/cancel.- The spec names "external job systems" as a use case. A render queue with job IDs is exactly that.
- Renderly's connector returns a
jobIdas a normal tool result today. It works in every client, with or without extension support.- A server must never return a task to a client that did not declare support, so you need the job-ID path anyway. Build on it now and add Tasks as a layer.
Why does a video render not fit in one tool call?
The MCP Tasks documentation states the problem directly: blocking ties up a connection, and "Many clients and transport intermediaries impose timeouts that make this impractical beyond a few seconds" (Model Context Protocol, Tasks, 2026). A render is queued work. It waits for a worker, renders frame by frame, encodes and uploads the MP4.
The Renderly MCP endpoint caps each request at 60 seconds. So the render tool
does not wait. It checks the arguments, charges the credits, puts the job on
the queue and returns. The job then moves through four states: PENDING,
PROCESSING, COMPLETED and FAILED. The agent needs a way to follow that
job after the tool call has ended. That is the whole problem Tasks solves.
What does the Tasks extension change?
The 2026-07-28 changelog lists this change: "Move experimental tasks out of
the core protocol and into an official extension
(io.modelcontextprotocol/tasks)". The redesign "replaces the blocking
tasks/result method with polling via tasks/get and a new tasks/update
for client-to-server input, removes tasks/list, and allows servers to return
task handles unsolicited without per-request opt-in"
(MCP Key Changes, 2026-07-28).
"Without per-request opt-in" does not mean without opt-in. The client
declares the extension once in its capabilities, and the server then decides
per request whether to return a task, with no per-call flag.
The extension's own repository lists its 2026-07-28 schema as Stable (modelcontextprotocol/ext-tasks).
The flow has six parts:
- Opt in. The client puts
io.modelcontextprotocol/tasksin the client capabilities that it sends in each request's_meta. The server lists the same extension in itsserver/discoverresponse. - Get a handle. For a long request such as
tools/call, the server can return aCreateTaskResultwithresultType: "task"in place of the normal result. The spec says the task must be stored durably before the server sends that response. - Poll. The client calls
tasks/getwith thetaskIdand honorspollIntervalMs. - Answer questions. If the status is
input_required, the response holds aninputRequestsmap. The client answers withtasks/update. - Read the result. On
completed, theresultfield holds what the tool call would have returned. Onfailed, theerrorfield holds a JSON-RPC error. - Cancel, maybe. The client can send
tasks/cancel. Cancellation is cooperative, so the task can still end ascompletedorfailed.
This is the shape of a task handle in the 2026-07-28 schema. The values are an example from a hypothetical server, not a Renderly response:
{
"resultType": "task",
"taskId": "render-7f3a",
"status": "working",
"statusMessage": "Rendering frame 312 of 900",
"createdAt": "2026-10-12T03:14:07Z",
"lastUpdatedAt": "2026-10-12T03:14:07Z",
"ttlMs": 86400000,
"pollIntervalMs": 5000
}| Status | Meaning | Terminal |
|---|---|---|
working | The work is in progress | No |
input_required | The server needs an answer, listed in inputRequests | No |
completed | result holds the tool result | Yes |
failed | error holds the JSON-RPC error | Yes |
cancelled | The work stopped after tasks/cancel | Yes |
Polling is the default. A server can also push the full task state as
notifications/tasks to clients that opt in through subscriptions/listen,
which saves the extra tasks/get round trip.
How does Renderly handle a long render today?
The same changelog removes protocol-level sessions and says that "Servers
that need cross-call state use explicit, server-minted handles passed as
ordinary tool arguments"
(MCP Key Changes, 2026-07-28).
That sentence describes the Renderly connector. The handle is a jobId, and
it moves between two tools.
First the agent calls renderly_create_render with a project or template and
its replacements:
{
"templateId": "<template id>",
"replacements": { "headline": "Spring sale ends Friday" },
"webhookUrl": "https://example.com/hooks/renderly"
}The tool returns at once with the handle and the charge:
{
"jobId": "<job id>",
"projectId": "<project id>",
"status": "PROCESSING",
"creditsUsed": 0.5,
"estimatedDurationMinutes": 0.5,
"mode": "template"
}estimatedDurationMinutes is the length of the video, which sets the price.
It is not a forecast of the render time. Here a 30-second 1080p video costs
0.5 credits at the default rate of 1 credit per 1080p minute, rounded up to the
nearest half credit. Some templates set a higher per-minute rate.
Then the agent calls renderly_get_render_status with the jobId. The result
carries status, progressPercentage, estimatedTimeRemaining in seconds,
and, once the status is COMPLETED, the outputUrl of the MP4. A FAILED
job carries an errorMessage.
The webhookUrl is the push path. When the render ends, Renderly POSTs a
render.completed or render.failed event to that URL, so a backend agent
does not have to poll at all. The
webhook guide shows how to
receive and verify the event.
How do render job fields map to Task fields?
The Tasks documentation lists this exact case as a fit: "If your server wraps an API that already uses job IDs (cloud deployments, async APIs, queued work), return a task when you create the job and resolve it when the job completes" (Model Context Protocol, Tasks, 2026). Most of the mapping is direct. Two rows have no Renderly equivalent today, and the table says so.
| Task field or method | Renderly today |
|---|---|
taskId | jobId from renderly_create_render |
status: working | PENDING or PROCESSING |
status: completed + result | COMPLETED + outputUrl |
status: failed + error | FAILED + errorMessage |
statusMessage | progressPercentage and estimatedTimeRemaining |
createdAt / lastUpdatedAt | createdAt / updatedAt |
tasks/get | renderly_get_render_status |
notifications/tasks | webhookUrl, with render.completed and render.failed |
tasks/cancel | None. A render runs to the end once it starts |
input_required | None inside a job. The tool description tells the agent to confirm values with the user before it calls the render |
The input_required row matters more than it looks. A render costs credits,
and the credits are charged when the job is created. The useful question to
ask a person is "are these the right values?", and the answer has to come
before the charge, not halfway through the render. That is why the connector
has a free preview tool
that takes the same arguments as the render and reports wrong variable names
and clipped text. A render that fails gets its credits back.
Should you wait for client support before you build?
No. The spec tells servers to "verify that the client included the extension in its per-request capabilities. Never return a task to a client that did not declare support" (Model Context Protocol, Tasks, 2026). So every server that adopts Tasks still needs a plain-result path for the clients that have not. For a render, that plain path is the job handle.
Client support is still thin. On 12 October 2026, the extension support matrix listed four extensions - MCP Apps, OAuth Client Credentials, Enterprise-Managed Authorization and Skills - and did not list Tasks. The matrix is maintained by the community, so check it again before you plan around it.
The protocol is also not finished with long-running work. The roadmap, last updated 2026-08-22, makes server-initiated events a priority because "we need extensions that let servers tell clients when work has finished, without relying purely on expensive client-side polling", and it expects work on Tasks to continue "toward eventual inclusion of the extension in the core protocol" (MCP Roadmap, 2026). Push delivery for MCP is being designed now. A webhook works today.
So the order is clear. Build on job handles and webhooks, which every client
and every backend can use. When the clients you care about declare the Tasks
extension, a server can return a task to them and keep the job handle for
everyone else. The jobId becomes the taskId, and nothing on the render
side changes.
How should an agent follow a render today?
The Tasks client guide gives the rules for any polled job: "Continue polling
until the task reaches a terminal status" and "Store task IDs durably so
polling can resume after a client crash or restart"
(Model Context Protocol, Tasks, 2026).
They apply to a jobId just as well:
- Preview first. Call
renderly_preview_renderwith the same arguments. It costs nothing and catches the mistakes that would waste a paid render. - Keep the
jobId. Write it to your database or the conversation before you poll. A job does not depend on the MCP connection, so a new session can pick it up withrenderly_get_render_status. - Stop at a terminal status.
COMPLETEDandFAILEDdo not change.PENDINGandPROCESSINGmean poll again later. - Space the polls. Use
estimatedTimeRemainingto choose the next check instead of calling in a tight loop. Each poll is a tool call, and in a chat client each one uses the model's context. - Use the webhook for batches. If an agent starts fifty renders, one
webhookUrlis better than fifty polling loops. The batch rendering guide shows the pattern at scale.
The full tool list, setup for Claude, Cursor and Claude Code, and the connector's current limits are in the Claude MCP connector guide and the MCP docs.
The short version
MCP Tasks let a server answer a long tool call with a durable taskId that
the client polls with tasks/get. In the 2026-07-28 spec, Tasks became an
official extension, and the spec names job-ID systems as a use case. Renderly's
connector uses the same idea without the extension: renderly_create_render
returns a jobId, and renderly_get_render_status or a webhook reports the
finished MP4.
Build on the job handle now. It works in every MCP client, and it is the path
a Tasks server must keep for clients that do not declare the extension.
Add the connector at https://renderly.video/api/mcp, pick a template from
the template gallery, and preview it for free before the first
paid render.
Frequently asked
What are MCP Tasks?
Does the Renderly MCP connector use Tasks?
Why can't an MCP tool just wait until the video is rendered?
Which MCP clients support the Tasks extension?
Can I cancel a Renderly render from an agent?
Related Articles

How to Create Videos with Claude Using Renderly's MCP Connector
Renderly is an MCP connector for Claude. Connect it and render personalized videos by typing a sentence. Setup steps, all ten tools, and current limits.
June 4, 2026

How to Let Your AI Agent Preview Videos Before Rendering (Free, No Credits)
66% of developers say their top AI frustration is output that's almost right but not quite. Renderly's free preview endpoint lets your agent see the video first.
August 11, 2026

How to Set Up Video Rendering Webhooks (Production Guide)
Video rendering is asynchronous — polling wastes 90%+ of requests. This guide covers HMAC SHA-256 signature verification, retry semantics, idempotency, and the raw-body pitfall that breaks most webhook handlers.
May 28, 2026

How to Generate 1,000+ Personalized Videos with API Automation (2026 Update)
A 30-second 1080p render costs $0.10 on a template API and $1.50+ on a generative one. Build the bulk pipeline: 1,000 personalized videos queued in under 20 minutes.
May 18, 2026

Faceless Video API for TikTok and YouTube Shorts
Turn a script into a 9:16 faceless video with AI voiceover and word-synced captions in one API call. The request, the real cost per clip, and how to post it.
October 7, 2026