mcp: add tasks extension capability negotiation - #755
Conversation
a502979 to
8213c3c
Compare
|
Please delete the guidelines and write a proper commit message. Link to the part of the spec that defines tasks. |
|
Also link to our issue about tasks. |
|
I just skimmed the spec. It is huge. I think we should implement it in multiple PRs. Let's start with the relatively easy stuff. How about a PR for capabilities first? And maybe one for the task data structure and related code, like generating the task ID? |
|
I don't quite understand how calling a tool with a task works. It looks like the tool itself doesn't have to know about tasks. Where is the code that returns the task result immediately and then handles task lifetime management? I think everything else is pretty straightforward, but this part of the design needs to be discussed on our tasks issue. |
|
Hey @jba pr is a draft and I assumed it's clear that it's not ready for a review yet. Body would be filled once the implementation is done. |
Add ExtensionTasks, the identifier of the io.modelcontextprotocol/tasks extension, and nil-safe HasExtension accessors on ClientCapabilities and ServerCapabilities, so both peers can negotiate the extension defined by SEP-2663. AddExtension already covered declaring an extension; there was no supported way to test for one. Task execution is not implemented, and neither NewClient nor NewServer declares the extension by default: declaring it obliges a client to handle a task handle in place of any result, and a server to serve tasks/get. Reserve the "task" resultType discriminator and reject it while decoding. Previously a CreateTaskResult decoded into an empty CallToolResult with no error, so a tool call against a task-returning server silently appeared to succeed and return nothing. It now fails with UnsupportedTaskResultError, which carries the task ID. Tasks moved out of the core protocol into an extension in 2026-07-28; the earlier in-core design (SEP-1686, 2025-11-25) is not implemented. For modelcontextprotocol#626
8213c3c to
449a0cd
Compare
SEP-2663 has merged, and the tasks extension now has a published specification document. Point at both rather than at the SEP pull request and the ext-tasks repository root.
|
Hey @jba, this is the capabilities-only pr you suggested, out of draft now. Scope is just negotiation: On your question about where task lifetime is handled - it isn't. Nothing is declared by default on either side, so we never promise a peer we can serve tasks. Happy to discuss the execution design in #626. Two things changed since you last looked. Tasks moved out of core into an extension (SEP-2663) so I rewrote the branch against ext-tasks. And this fixes a bug: a Also ci has never run here, I think it needs your approval. |
Adds capability negotiation for the MCP Tasks extension (
io.modelcontextprotocol/tasks). First step of #626; task execution follows in later PRs.Why
Tasks moved out of the core protocol and into an official extension in
2026-07-28(SEP-2663), now specified in modelcontextprotocol/ext-tasks. The in-core design this PR originally implemented (SEP-1686,2025-11-25) is gone from the current schema. The branch is rewritten against the extension, and scoped to capabilities only.This also fixes a live bug. A
CreateTaskResultdecoded into an emptyCallToolResultwithout error, so a tool call against any server that returns a task silently looked like it succeeded and returned nothing.What
ExtensionTasks: the extension identifier.HasExtensiononClientCapabilitiesandServerCapabilities— the read-side counterpart to the existingAddExtension, which had no equivalent for testing whether a peer declared an extension. Generic, not tasks-specific."task"resultTypediscriminator and reject it while decoding, returningUnsupportedTaskResultErrorwith the task ID.Negotiation is then one line on each side, over plumbing that already exists:
The guard lives in
UnmarshalJSONrather than inCallToolor a middleware: a middleware can be disabled viaMultiRoundTrip.Disabled, which is the wrong shape for a correctness check.tools/callis the only task-eligible method today, but the spec asks implementations to accommodate more in future revisions, so the guard also coversprompts/getandresources/read. It adds no extra parsing, since all three result types already decoderesultType.Nothing is declared by default, on either side. Declaring the extension obliges a client to poll task handles and a server to serve
tasks/*, neither of which the SDK implements yet; users with their own implementation can still declare it viaAddExtension.Note for whoever implements
tasks/get: the error code for "Missing Required Client Capability" is-32021, so this SDK's existingCodeMissingRequiredClientCapabilitiesis already correct. The ext-tasks prose briefly said-32003— a slip introduced when SEP-2663 was ported into that repo, where the SEP itself, the core2026-07-28schema and the TypeScript SDK all use-32021. Fixed upstream in modelcontextprotocol/ext-tasks#15, so the spec and this SDK now agree.