SEP-2229: Unsolicited Tasks#2229
SEP-2229: Unsolicited Tasks#2229LucaButBoring wants to merge 9 commits intomodelcontextprotocol:mainfrom
Conversation
b2295ba to
9acd930
Compare
|
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. |
|
|
||
| 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 |
There was a problem hiding this comment.
Shouldn't this be in the "Specification" section, not the "Rationale" section?
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
This seems difficult in practice - many eventually consistent systems don't give you a consistency signal to tell you that data propagation is completed.
There was a problem hiding this comment.
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/getrequests 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.
There was a problem hiding this comment.
References:
- OpenSearch (
wait_for_active_shards): https://docs.opensearch.org/latest/api-reference/document-apis/index-document/#query-parameters - Cassandra/Scylla (
CONSISTENCY): https://docs.datastax.com/en/cql/hcd/reference/cqlsh-commands/consistency.html
There was a problem hiding this comment.
I was thinking about DynamoDB specifically, but I guess in practice you would just set writes to be strongly consistent for that
Maintainer Activity CheckHi @LucaButBoring! You're assigned to this SEP but there hasn't been any activity from you in 20 days. Please provide an update on:
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. |
29c651b to
226f114
Compare
Deprecate capabilities.tasks.requests and execution.taskSupport in schema, update spec docs to reflect receiver-driven task creation, add consistency requirement, and remove -32600 error.
226f114 to
d45bbb6
Compare
SamMorrowDrums
left a comment
There was a problem hiding this comment.
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,
|
@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). |
|
@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 |
|
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. |
|
Boring perhaps but maybe "Unsolicited Tasks" Agree it's hard, sorry for the hassling. |
|
Tolerable - updated the name. |
There was a problem hiding this comment.
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.
|
Is there a problem with the current proposed phrasing on that front?
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 |
|
@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. |
Worries me, because they just might not. Non-compliance isn't as big a deal is it should be 😅. |
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 Whether the capability is declared or not, every implementation needs to support an unsolicited
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. |
|
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. |
Maintainer Activity CheckHi @LucaButBoring! You're assigned to this SEP but there hasn't been any activity from you in 18 days. Please provide an update on:
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. |
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:
tools/listcall prior to making any task-augmented tool call.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
Checklist
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.