Key takeaways
- SDK 1.30.0 treated timeout: 40 as a deadline for each JSON-RPC request. Fourteen prompt tasks/get responses prevented that timeout from becoming a 40 ms wall-clock limit for the task stream.
- The fixture advertised ttl: 120, yet the last working status arrived at 355 ms and polling ended at 382 ms only because a separate AbortSignal fired at 360 ms. TTL is receiver retention metadata, not an agent execution budget.
- The 90 ms response-delay control rejected the first tasks/get at 42 ms with Request timed out, proving the same 40 ms setting was active at the per-request layer.
- Aborting the shared signal emitted 15 notifications/cancelled messages: one for the completed task-creation request and one for each of 14 completed polls, because successful requests left abort listeners attached in this tested path.
- Production hosts need separate per-request, overall task, idle-progress and business deadlines, plus explicit task cancellation and deduplicated cancellation telemetry.
The sharp question: what actually stops a long-running agent tool?
MCP tasks move polling out of the language model and into deterministic host code. That is the right direction for deep research, code migration, evaluation runs and other AI work that lasts longer than one request. But deterministic polling still needs a wall-clock boundary. A timeout value that only protects one status request does not cap the whole agent operation.
In this SDK 1.30.0 fixture, timeout: 40 did not end the task stream after 40 ms. The server fixture answered every tasks/get promptly with working, so the client made 14 polls and accepted its last status at 355 ms. The stream ended at 382 ms only after a separate AbortSignal fired at 360 ms.
Chronology: tasks replaced model-driven waiting with host-driven state
SEP-1391 was proposed on August 26, 2025 to address long-running MCP operations. Its examples included multi-minute deep research, code migrations, test systems and multi-agent work. The accepted SEP-1686 followed on October 20 and explicitly described agent-driven polling as expensive and inconsistent: a model may poll once, claim to be waiting and then require another user turn.
MCP 2025-11-25 introduced the experimental task primitive with task IDs, status retrieval and deferred results. SDK 1.30.0 shipped July 27, 2026. On September 2, this AccessAllGPT run tested how the official client’s automatic task stream combines request timeout, TTL, polling interval and caller cancellation.
The specification defines retention and polling, not one universal deadline
The task specification calls tasks durable state machines and makes the requestor responsible for polling. It says requestors should continue until completed, failed, cancelled or input_required, and should respect a receiver-provided pollInterval. The schema carries createdAt, lastUpdatedAt, ttl and optional pollInterval.
TTL has narrower semantics than its name may suggest. The receiver reports how long task resources are retained from creation and may delete a task and its result after that lifetime, regardless of status. The specification does not define TTL as a command to abort execution or as a host-side overall deadline. Converting it into either behavior would be an application policy decision.
The implementation loops around individually timed requests
At SDK tag 1.30.0, requestStream creates the task and enters while (true). Each iteration awaits getTask with the same options, yields taskStatus, checks terminal states, sleeps for task.pollInterval or a default, then asks the supplied AbortSignal to throw if it has been aborted.
getTask delegates to the general request method. That method installs the options.timeout timer for the individual JSON-RPC request. A quick tasks/get response resolves before its timer, after which the outer loop starts another independently timed request. There is no elapsed-time or task.ttl comparison in this polling loop.
The fixture isolated three clocks
The synthetic transport returned a valid 2025-11-25 initialize response and accepted a task-augmented tools/call. Every task object used the same task ID, working status, 120 ms TTL and 25 ms poll interval. No real tool ran. The first mode answered every tasks/get on the next microtask and armed one caller AbortSignal for 360 ms.
The control kept the same 40 ms request timeout but delayed its first tasks/get response by 90 ms. That separated a per-request timeout from an overall task limit: if timeout governed the stream, both modes would end near 40 ms; if it governed each poll, only the delayed status request would do so.
Fast working responses kept resetting the practical wait
The main run yielded taskCreated, then 14 working taskStatus messages. The final working status arrived at 355 ms—nearly nine times the 40 ms request timeout. No individual poll was slow enough to trigger its own timer, so automatic polling continued.
Calling this a timeout reset is shorthand for the observed effect, not an implementation claim that one timer object was reused. The code created a new request and timeout on every iteration. The operational result is the same: a responsive server can keep the task stream alive indefinitely unless another boundary intervenes.
The 120 ms TTL passed without stopping the client
The fixture’s 120 ms TTL had elapsed before most of the observed statuses. Polls still returned working at 135, 162, 190, 217, 244, 271, 298, 325 and 355 ms. The client did not calculate createdAt plus ttl or convert that point into an error.
That is consistent with TTL being server-controlled retention rather than a required client deadline. A conforming receiver may delete the task after TTL and return an error on the next lookup; it may also keep it. A host that needs a guaranteed end must record and enforce its own deadline rather than assuming task metadata supplies one.
One slow poll proved the 40 ms timer was real
In the control, the fixture waited 90 ms before delivering the first tasks/get response. The stream rejected at 42 ms with MCP error -32001, Request timed out. It yielded no taskStatus and sent one notifications/cancelled message for that pending request.
This control rules out a misspelled or ignored timeout option. The setting worked exactly where the request layer applied it. What it did not provide was a cumulative budget across task creation, every successful poll, sleep intervals and result retrieval.
The outer abort worked, but only at the polling checkpoint
The caller AbortSignal fired at 360 ms. The stream produced its final error at 382 ms, after the current 25 ms polling sleep reached the implementation’s throwIfAborted checkpoint. The measured 22 ms difference is one local timer observation, not a universal cancellation latency.
For production, this means an outer signal is necessary but not sufficient evidence of immediate release. Test abort during an in-flight poll, during sleep, during tasks/result and during transport failure. Size the gap against lease, worker and user-facing deadlines rather than assuming abort means synchronous settlement.
The abort also cancelled requests that had already completed
The main run emitted 15 notifications/cancelled messages when the one signal aborted: one corresponding to task creation and one for each of 14 completed tasks/get requests. That was unexpected. The first harness version asserted zero cancellation notifications and failed with an observed count of 15.
The pinned request implementation adds an abort listener for every request. Its successful response handler resolves the promise, but this path does not remove that listener. When the shared signal later aborts, every retained listener calls cancel and sends a notification with its historical request ID. The messages do not prove 15 live operations were cancelled.
Cancellation telemetry needs a task identity and a request lifecycle
An operator counting notifications/cancelled as active-work cancellations could infer a cancellation storm from one intended overall deadline. Servers may ignore cancellation for already-completed request IDs, but logs, counters and alerting still need to distinguish duplicate or stale request cancellation from tasks/cancel against the durable task itself.
Record task ID, JSON-RPC request ID, request creation and settlement time, poll sequence, cancellation source and receiver acknowledgement. Deduplicate by request lifecycle, not notification count. If the business action must stop, call the task cancellation operation when supported and verify the returned task state; aborting local polling only proves the caller stopped waiting.
Use four separate deadlines for autonomous AI work
Set a per-request deadline for one network exchange, an overall task deadline from accepted creation to final result, an idle-progress deadline for a task whose lastUpdatedAt or meaningful progress has stopped advancing, and a business deadline after which the result is no longer useful or authorized. These clocks answer different failure questions and should produce different telemetry.
Do not silently derive the overall deadline from TTL. TTL is negotiated receiver retention and may be null. Instead, bind the overall deadline to workload consequence and recovery objective, carry it through retries, and make its expiry trigger an explicit host state such as deadline_exceeded_pending_cancel rather than pretending the remote action never ran.
Bound polling cost independently from wall time
A generous outer deadline can still generate excessive polls if a server advertises a very short interval. Enforce a minimum and maximum poll interval, jitter concurrent clients, cap polls and concurrent tasks per server and tenant, and reserve capacity for status and cancellation traffic. Treat implausible intervals as untrusted remote input.
Conversely, an interval longer than the remaining deadline should not postpone local settlement past the budget. Race sleep against the outer signal or deadline, then preserve the task handle for asynchronous recovery. These are AccessAllGPT implementation recommendations, not requirements stated by the MCP specification.
What failed, what repeated and what remains unknown
The first checked-in harness run failed because it expected no cancellation messages after the outer abort; the observed value was 15. I inspected the signal-listener path, corrected the assertion and article, and reran the final 20-assertion harness. A second completed run reproduced 14 polls, a last status beyond 350 ms, overall settlement near 380 ms, 15 abort-triggered cancellation notifications and a 42 ms slow-poll timeout.
The experiment did not test a language model, real task store, production server, network, HTTP transport, proxy, authentication, tasks/cancel acknowledgement, result retrieval, input_required, terminal transitions, process crash, concurrency, load, v2 split SDK, another language SDK or external effect. Targeted issue searches found no independent reproduction of this exact behavior. The result is source-bound local evidence, not a prevalence estimate or security vulnerability claim.
Decision: deploy task polling only with an owned overall budget
Deploy automatic MCP task polling for autonomous AI work only when the host enforces a cumulative deadline, interruptible waits, bounded poll cadence, task-aware cancellation, unknown-outcome recovery and request-lifecycle telemetry. Regression-test prompt working responses beyond TTL, a hung status request, stale lastUpdatedAt, abort during sleep and I/O, terminal result retrieval, task deletion and cancellation acknowledgement on the exact SDK and transport path.
Constrain long-running tools to supervised or read-only work when the host has only per-request timeout. Roll back or circuit-break when a server can retain workers beyond the business deadline, task cancellation cannot be verified, stale cancellation messages corrupt operational signals, or deadline handling automatically replays a consequential action. A responsive poll is evidence that status transport works. It is not evidence that the task still deserves to run.
Copy-ready MCP task deadline gate
Complete this record for every long-running tool class before an AI agent may start it autonomously.
Entries stay in this browser tab and are not submitted to AccessAllGPT. Blank responses are copied as [Unresolved].
Server, tool, task support mode, side effect, idempotency, compensation and maximum useful completion time.
Protocol, SDK, distributed source digest, transport, task-store behavior and receiver TTL policy.
Per-request, overall task, idle-progress and business deadlines; owners, evidence and settlement states for each.
Receiver suggestion, host floor and ceiling, jitter, maximum polls, concurrency and remaining-budget handling.
Local AbortSignal, tasks/cancel support, acknowledgement, remote-work termination evidence and late-result policy.
State retained after local deadline or response loss; task lookup, idempotency and evidence required before replay.
Task ID, request ID, poll sequence, created/updated/settled times, deadline source, cancellation source and deduplication rule.
Fast perpetual working, slow poll, deleted task, stale status, malformed time, input required, terminal state, abort and transport loss.
Per-server and tenant task caps, retained context, recovery capacity, rate limits, circuit break and alert thresholds.
Budget overrun, uninterruptible sleep or I/O, unverified remote cancellation, cancellation fan-out or unsafe automatic replay.
Primary sources
Browse the publication-wide evidence index →
- Tasks (protocol version 2025-11-25)Model Context Protocol Specification · Reviewed: Definitions, requestor-driven model, task creation, polling, status lifecycle, TTL and resource management, result retrieval and cancellation · Retrieved · Supports: The experimental task specification defines durable requestor-polled state, says requestors should poll until a terminal or input-required state, permits receivers to delete tasks after TTL, and treats pollInterval as a polling suggestion.
- MCP schema at the 2025-11-25 specification commitModel Context Protocol · Reviewed: TaskStatus, TaskMetadata, Task, CreateTaskResult, tasks/get and tasks/result type definitions · Retrieved · Supports: The pinned schema defines working, input_required, completed, failed and cancelled states; Task carries createdAt, lastUpdatedAt, ttl and optional pollInterval but no overall execution deadline field.
- TypeScript SDK release 1.30.0Model Context Protocol TypeScript SDK · Reviewed: Release identity, tag, publication date, v1.x branch and changed-package record · Retrieved · Supports: The official release record binds the tested package to SDK 1.30.0, released July 27, 2026 on the v1.x line.
- Protocol request and task polling implementation at SDK 1.30.0Model Context Protocol TypeScript SDK · Reviewed: requestStream polling loop, terminal-state handling, poll interval, AbortSignal check, request timeout setup, cancellation listener and tasks/get dispatch · Retrieved · Supports: The pinned implementation applies request options to each tasks/get call, loops until status changes, sleeps by pollInterval, checks AbortSignal after sleep, and attaches the same signal cancellation listener to every request without removing it after a successful response.
- @modelcontextprotocol/sdk 1.30.0 registry recordnpm Registry · Reviewed: Package identity, version, distribution integrity, publication metadata, repository and runtime requirements · Retrieved · Supports: The npm registry identifies the installable official SDK 1.30.0 artifact used in the clean temporary reproduction.
- SEP-1686: TasksModel Context Protocol proposal archive · Reviewed: Accepted proposal abstract, motivation, agent-driven polling problem, long-running AI use cases, requestor orchestration and retention design · Retrieved · Supports: The accepted proposal explains why host-driven polling replaced model-driven polling for long-running tools, including deep research, code migration and multi-agent use cases; it is design history, not independent validation of SDK behavior.
Limitations
This is a bounded local reproduction on Node v24.10.0, Darwin arm64, @modelcontextprotocol/sdk 1.30.0 and Zod 3.25.76 using a synthetic in-process transport, one task-augmented tools/call, working-only statuses, a 25 ms poll interval, 120 ms TTL, 40 ms request timeout, 360 ms AbortSignal and one 90 ms delayed-poll control. It did not test a model, production agent, remote server, real tool or task store, network transport, proxy, authentication, task cancellation acknowledgement, result retrieval, input_required, terminal transitions, process crash, concurrency, load, v2 package, another SDK, external side effect or user data. Millisecond timings and cancellation counts are observations from this deterministic fixture and two completed runs, not a performance benchmark or prevalence estimate. The specification is experimental and permits receiver deletion after TTL; this article does not claim that the client must treat TTL as an execution deadline or prescribe an SDK fix.
Disclosures
AccessAllGPT created and ran only the synthetic local fixture in the checked-in harness. I found no independent public reproduction of the exact overall-deadline and completed-request cancellation-listener behavior in targeted MCP specification and TypeScript SDK issue searches; SEP-1686 is cited as primary design history, not independent validation. No model, production client, third-party server, credential, endpoint, external action or user data was used. The MCP project, proposal authors, SDK maintainers, npm and Zod maintainers did not review this article or provide access, private data, payment or endorsement. AccessAllGPT Research is operated by NeuralArc, is independent, and is not affiliated with OpenAI, Anthropic, the MCP project, npm or Zod. Publication-wide relationships are listed on the disclosures page.
Further AccessAllGPT guidance
- A Lost MCP SSE Response Can Hold an AI Agent Until Its Timeout
- An Optional MCP Task Schema Can Strand an Agent’s Completed Result
- MCP v2 Can Return a Partial Tool List as Complete
- MCP Pagination Can Evict Earlier Tool Validators
- MCP Output Validation Depends on Tool Discovery
- MCP’s readOnlyHint Is Not a Permission Boundary
- Where Human Approval Belongs in AI Automation
- AccessAllGPT Research methodology
- Publication disclosures
Continue the research
Get evidence-led updates for teams making production AI decisions.