Skip to content

SEP-2229: Unsolicited Tasks#2229

Open
LucaButBoring wants to merge 9 commits intomodelcontextprotocol:mainfrom
LucaButBoring:feat/task-jumpscares
Open

SEP-2229: Unsolicited Tasks#2229
LucaButBoring wants to merge 9 commits intomodelcontextprotocol:mainfrom
LucaButBoring:feat/task-jumpscares

Conversation

@LucaButBoring
Copy link
Copy Markdown
Contributor

@LucaButBoring LucaButBoring commented Feb 10, 2026

This proposal builds on tasks by removing per-request task capabilities and tool-level task support declarations, and instead allowing tasks to be returned in response to any request without the requestor opting into this behavior. This removes an unneeded state contract, simplifies supporting tasks at a per-tool level, and allows peers to skip task creation when no persistent work needs to be performed.

Motivation and Context

Today, tasks require their requestor to be cooperative, in the sense that the requestor of a task must explicitly opt into task-augmented execution on a request. While this contract ensures that both the requestor and receiver understand their peer's capabilities and safely agree on the request and response formats in advance, it also has a few conceptual flaws:

  1. It requires requestors to explicitly check the capabilities of receivers. This introduces an unnecessary state contract that may be violated during mid-session deployments under the Streamable HTTP transport, and also raises concerns about the capability exchange growing in payload size indefinitely as more methods are supported.
  2. It requires a tool-specific behavior carveout which gets pushed onto the client to navigate. Related to this, it forces clients to cache a tools/list call prior to making any task-augmented tool call.
  3. It requires host application developers to explicitly choose to opt into task support from request to request, rather than relying on a single, consistent request construction path for all protocol operations.

In practical terms, these flaws imply that an MCP server cannot make a clean break from non-Task to task-augmented execution on its tools, even if clients have implemented support for tasks already; the server must wait for all host applications to additionally opt into tasks as well and sit in an awkward in-between state in the meantime, where it must choose to either break compatibility with host applications (even if those host applications have an updated client SDK) or accept the costs of task-optional execution and poll on tasks internally sometimes.

To both improve the adoption of tasks and to reduce their upfront messaging overhead, this proposal simplifies their execution model by allowing peers to raise unsolicited tasks to each other.

How Has This Been Tested?

TBD

Breaking Changes

Yes - this is covered in the proposal.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Partially overlaps with #1905, particularly the immediate result acceptance part of that proposal.

This SEP came out of discussions related to the Multi Round-Trip Requests (MRTR) draft proposal from the Transports Working Group, but the two are not coupled with one another.


AI Use Disclosure: The core SEP document was written entirely by me, but the actual specification and schema changes were written with Claude Code. The LLM-annotated diff validating the specification and schema changes against the SEP requirements is available here.

@LucaButBoring LucaButBoring requested a review from a team as a code owner February 10, 2026 03:13
@LucaButBoring LucaButBoring changed the title SEP-0000: Task Jumpscares SEP-2229: Task Jumpscares Feb 10, 2026
@LucaButBoring LucaButBoring self-assigned this Feb 10, 2026
@He-Pin
Copy link
Copy Markdown
Contributor

He-Pin commented Feb 10, 2026

This is necessary, especially when we are in the process of converting design drafts into code. If a duplicate design draft appears as a task, we need to return the result immediately.

Copy link
Copy Markdown

@markdroth markdroth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great!


This happens to align with the [Multi Round-Trip Requests (MRTR)](https://github.com/modelcontextprotocol/transports-wg/pull/12) draft proposal from the Transports Working Group, but the two are not coupled with one another.

### Waiting for Consistency
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be in the "Specification" section, not the "Rationale" section?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was on the fence about this, I actually originally had it in the specification section, but I figured the reasoning for the requirement was a bit specific and didn't belong in the text of the spec proper (or at least not the full explanation). I think we would benefit from a bit more than zero explanation in the actual spec, however - I'll consider adjusting it.

> 1. Requestors **MUST** be prepared for a `CreateTaskResult` to be returned in response to any request, whether or not the `task` parameter is present in the request.
> 2. Receivers **MAY** return a `CreateTaskResult` in response to any request, whether or not the `task` parameter is present in the request.
> 3. Receivers that receive a `task` parameter in a request and do not wish to create a task **MUST** ignore the parameter.
> 4. Receivers **MUST NOT** return a `CreateTaskResult` unless and until a `tasks/get` request would return that task; that is, in eventually-consistent systems, receivers **MUST** wait for consistency.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems difficult in practice - many eventually consistent systems don't give you a consistency signal to tell you that data propagation is completed.

Copy link
Copy Markdown
Contributor Author

@LucaButBoring LucaButBoring Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is correct - I'm very open to suggestions on this point, though I'm not sure if there's any way around this. In systems I've worked with where consistency cannot be guaranteed, we've had to handle that on an ad-hoc basis by just speculatively polling until we can see an update has gone through. In MCP, that seems untenable, as that would mean clients wouldn't know if a task hasn't started yet or has been dropped entirely, and I'm not sure if there's a reliable way to handle that.

Essentially, this is saying: If as a server, you are relying on an eventually-consistent system to store task metadata, it is your responsibility as a server to enforce our abstraction by doing something internally instead. I'm aware of mechanisms for enforcing this in OpenSearch, Cassandra, and Scylla, but I'm not sure about other databases.

edit: also addressed in the rationale section

This addition is intended to avoid speculative tasks/get requests from requestors that would otherwise not know if a task has silently been dropped or if it simply has not been created yet. While this does increase latency costs in distributed systems that did not already behave this way, explicitly introducing this requirement simplifies client implementations and eliminates a source of undefined behavior.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about DynamoDB specifically, but I guess in practice you would just set writes to be strongly consistent for that

@sep-automation-bot
Copy link
Copy Markdown

Maintainer Activity Check

Hi @LucaButBoring!

You're assigned to this SEP but there hasn't been any activity from you in 20 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@LucaButBoring LucaButBoring requested a review from a team as a code owner March 10, 2026 21:36
Copy link
Copy Markdown
Contributor

@SamMorrowDrums SamMorrowDrums left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe trivial feedback, but the title might be better being "address task jumpscares"

Or I'd suggest "de-risk Task specification" or something like that,

@LucaButBoring
Copy link
Copy Markdown
Contributor Author

@SamMorrowDrums I'm not addressing task jumpscares, though - I'm introducing them 🙂

As for the other suggestion, it'd be a bit ambiguous with #2339; I figure it's best to have well-scoped proposals with independent purposes/names, even if they serve a similar high-level goal (at least as long as they don't implicitly depend on each other, which isn't the case here).

@SamMorrowDrums
Copy link
Copy Markdown
Contributor

@LucaButBoring mskes sense but I do wonder if there's a better name, maybe it's just me but I put off reading for a while because I was thinking "I have zero idea what this is going to be about"

Could just be me though

@LucaButBoring
Copy link
Copy Markdown
Contributor Author

You're driving a hard bargain here, it's quite hard to come up with interesting-sounding titles. Maybe just "Surprise Tasks" will work? The key idea I'm attempting to capture in the title is the new unexpectedness of a task.

@SamMorrowDrums
Copy link
Copy Markdown
Contributor

Boring perhaps but maybe "Unsolicited Tasks"

Agree it's hard, sorry for the hassling.

@LucaButBoring LucaButBoring changed the title SEP-2229: Task Jumpscares SEP-2229: Unsolicited Tasks Mar 11, 2026
@LucaButBoring
Copy link
Copy Markdown
Contributor Author

Tolerable - updated the name.

Copy link
Copy Markdown
Contributor

@SamMorrowDrums SamMorrowDrums left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these changes make a lot of sense, and I think from my angle the most important thing is that the capability availability/negotiation is clear, so we don't end up with the Resource response problem where many clients still just ignore Resources returned from tool calls.

@LucaButBoring
Copy link
Copy Markdown
Contributor Author

Is there a problem with the current proposed phrasing on that front?

Servers and clients that support task RPC methods (tasks/get, tasks/result, tasks/list, tasks/cancel) MUST declare a tasks capability during initialization. This capability is not required for handling CreateTaskResult responses, which all parties MUST support.

In short, the angle I'm pushing for is that there is no such thing as ignoring a task; that makes a requestor noncompliant. In SDKs, that will force some degree of encapsulation of the task lifecycle (e.g. how callToolStream behaves in the TS SDK today).

@SamMorrowDrums
Copy link
Copy Markdown
Contributor

@LucaButBoring to understand correctly, it's the case that if they advertise the capability they MUST handle the responses?

That seems fine, the problem with Resources in practice as tool responses is that clients don't have a way to say they do or don't support those, and implementation has been patchy.

@SamMorrowDrums
Copy link
Copy Markdown
Contributor

This capability is not required for handling CreateTaskResult responses, which all parties MUST support.

Worries me, because they just might not. Non-compliance isn't as big a deal is it should be 😅.

@LucaButBoring
Copy link
Copy Markdown
Contributor Author

@LucaButBoring to understand correctly, it's the case that if they advertise the capability they MUST handle the responses?

Even further: The capability describes if invoking task-related methods is supported on that party, so a client that declares it must support at least tasks/get and tasks/result; and the same applies to servers.

Whether the capability is declared or not, every implementation needs to support an unsolicited CreateTaskResult.

Worries me, because they just might not. Non-compliance isn't as big a deal is it should be 😅.

This is why I think that in practice, SDKs should encapsulate at least some of that logic, so that it really is as simple as upgrading the SDK in the most basic case (it would of course be more complex if you then wanted to leverage the benefits of tasks to support proper backgrounding etc.). But yes, it is possible that some implementations might simply not.

@SamMorrowDrums
Copy link
Copy Markdown
Contributor

Thank you, I now understand the encapsulation suggestion properly and that makes sense.

Although to leverage the resource content example, there is no reason why SDKs couldn't offer to return it as regular tool response content in the same way, and that has never been done.

@sep-automation-bot
Copy link
Copy Markdown

Maintainer Activity Check

Hi @LucaButBoring!

You're assigned to this SEP but there hasn't been any activity from you in 18 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

draft SEP proposal with a sponsor. SEP

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

6 participants