You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The wire-schema validator introduced in #399 discriminates resultType === 'input_required' before falling back to the request method's result definition, but has no branch for resultType === 'task'. A well-formed SEP-2663 task envelope answering tools/call is therefore validated against CallToolResult and fails with must have required property 'content'.
The envelope shape cannot be present in the core spec schema, since tasks moved to an extension as of SEP-2663. So any SDK that implements the tasks extension and passes wire validation on everything else still fails these checks. In our runs (mcpkit) all 8 tasks scenarios fail exactly one check each (wire-schema-valid) for this reason but every other check in those scenarios passes.
Sample violation from tasks-lifecycle. here is the response that the validator rejected:
The result carries resultType: "task" and the SEP-2663 envelope fields. There is nothing for CallToolResult.content to match because it is not a CallToolResult.
Possible fixes, in rough order of preference:
Treat an unrecognized resultType value as an extension result and skip typed validation for it (fall back to the generic JSONRPCResultResponse envelope check), since resultType is exactly the discriminator the final revision added for this purpose.
Vendor the tasks extension's envelope schema alongside the core schema and add a task branch, if extension-aware validation is wanted.
Happy to contribute a PR for either direction if maintainers have a preference.
Confirming this independently from a second SDK. Still reproduces at 0.2.0-alpha.11.
We hit exactly the pattern you describe in nexusphp/mcp (PHP, spec 2026-07-28): 8 of our 10 server-side tasks scenarios fail exactly one check each, wire-schema-valid, with CallToolResult: must have required property 'content'. Every other check in those scenarios passes. The two that don't fail (tasks-required-task-error, tasks-status-notifications) are the two that never emit a CreateTaskResult on a tools/call. Our envelope is field-identical to the one in your report.
Two things from the referee's own artefacts that may help when weighing this:
The suite contradicts itself on the same message. In tasks-capability-negotiation, tasks-per-request-meta-opt-in passes because the response is a CreateTaskResult, and wire-schema-valid fails on that same response for not being a CallToolResult. Both checks, same envelope, same run.
Reference-fixture CI cannot catch this.requirements/2026-07-28.yaml marks every tasks scenario not_scored with note: io.modelcontextprotocol/tasks (SEP-2663); pending against the reference fixture, run for visibility, and typescript-sdk's spec.types.2026-07-28.ts contains no CreateTaskResult at all (versus 2 occurrences in its spec.types.2025-11-25.ts). So the only implementations that trip this are ones that have already shipped the extension.
On the proposed fixes, option 1 looks right on spec grounds, beyond just being cheaper. SEP-2663 §"Polymorphic Results" defines the discriminator as open:
and the core schema's ResultType is a bare "type": "string" describing only complete and input_required. So an unrecognised resultType is precisely the "this is an extension result" signal, and falling back to the generic JSONRPCResultResponse envelope check generalises to the next extension without vendoring anything. Option 2 would fix tasks and leave the same hole for the next extension result type.
Happy to test a patch against our suite if that's useful.
Awesome. Confirming the fix. Ran the tasks scenarios against mcpkit's SEP-2663 server (examples/tasks-v2, Go, spec 2026-07-28) on both sides of the merge:
before (74edef3)
after (a983ba9)
scenarios with a wire-schema-valid failure
8
0
tasks checks
36 pass / 8 fail
44 pass / 0 fail
The 8 were one wire-schema-valid each, all CallToolResult: must have required property 'content', with every other check in those scenarios passing. Same pattern reported for nexusphp/mcp, down to which two scenarios never failed: tasks-required-task-error and tasks-status-notifications, neither of which emits a CreateTaskResult on a tools/call.
Thanks for taking option 1. Just a note - the merged version is a bit broader than what we originally for. The x-acme/streamed case means a private extension result that happens to satisfy the method's own schema passes too, so the next extension needs a code change here only if it also changes the result shape.
@paulbalandan since you offered to test a patch against your suite, and this is on main now if you want to re-run it.
All ten server-side tasks scenarios, --spec-version 2026-07-28 --force. The eight per-check entries in our expected-failures.yaml now report as stale. The rest of the server suite is unchanged at 145 passed. The one new failure elsewhere was resource-parameter-matches-prm from #488, a real bug on our side, fixed.
On the breadth: a private extension result that satisfies the method's own schema is wire-valid by construction, so passing it fits the check's name. The case it misses is an extension result that is both unrecognised and malformed. That belongs to the extension's own schema once one is versioned.
We will drop the eight baseline entries when this ships in a release.
Activity
paulbalandan commentedon Aug 10, 2026
Confirming this independently from a second SDK. Still reproduces at
0.2.0-alpha.11.We hit exactly the pattern you describe in nexusphp/mcp (PHP, spec
2026-07-28): 8 of our 10 server-side tasks scenarios fail exactly one check each,wire-schema-valid, withCallToolResult: must have required property 'content'. Every other check in those scenarios passes. The two that don't fail (tasks-required-task-error,tasks-status-notifications) are the two that never emit aCreateTaskResulton atools/call. Our envelope is field-identical to the one in your report.Two things from the referee's own artefacts that may help when weighing this:
The suite contradicts itself on the same message. In
tasks-capability-negotiation,tasks-per-request-meta-opt-inpasses because the response is aCreateTaskResult, andwire-schema-validfails on that same response for not being aCallToolResult. Both checks, same envelope, same run.Reference-fixture CI cannot catch this.
requirements/2026-07-28.yamlmarks every tasks scenarionot_scoredwithnote: io.modelcontextprotocol/tasks (SEP-2663); pending against the reference fixture, run for visibility, andtypescript-sdk'sspec.types.2026-07-28.tscontains noCreateTaskResultat all (versus 2 occurrences in itsspec.types.2025-11-25.ts). So the only implementations that trip this are ones that have already shipped the extension.On the proposed fixes, option 1 looks right on spec grounds, beyond just being cheaper. SEP-2663 §"Polymorphic Results" defines the discriminator as open:
and the core schema's
ResultTypeis a bare"type": "string"describing onlycompleteandinput_required. So an unrecognisedresultTypeis precisely the "this is an extension result" signal, and falling back to the genericJSONRPCResultResponseenvelope check generalises to the next extension without vendoring anything. Option 2 would fix tasks and leave the same hole for the next extension result type.Happy to test a patch against our suite if that's useful.
fix(validation): accept extension result envelopes (#468)
panyam commentedon Sep 7, 2026
Awesome. Confirming the fix. Ran the tasks scenarios against mcpkit's SEP-2663 server (
examples/tasks-v2, Go, spec2026-07-28) on both sides of the merge:74edef3)a983ba9)wire-schema-validfailureThe 8 were one
wire-schema-valideach, allCallToolResult: must have required property 'content', with every other check in those scenarios passing. Same pattern reported for nexusphp/mcp, down to which two scenarios never failed:tasks-required-task-errorandtasks-status-notifications, neither of which emits aCreateTaskResulton atools/call.Thanks for taking option 1. Just a note - the merged version is a bit broader than what we originally for. The
x-acme/streamedcase means a private extension result that happens to satisfy the method's own schema passes too, so the next extension needs a code change here only if it also changes the result shape.@paulbalandan since you offered to test a patch against your suite, and this is on main now if you want to re-run it.
paulbalandan commentedon Sep 8, 2026
Re-ran against
a983ba9.0.2.0-alpha.11a983ba9wire-schema-validfailureAll ten server-side tasks scenarios,
--spec-version 2026-07-28 --force. The eight per-check entries in ourexpected-failures.yamlnow report as stale. The rest of the server suite is unchanged at 145 passed. The one new failure elsewhere wasresource-parameter-matches-prmfrom #488, a real bug on our side, fixed.On the breadth: a private extension result that satisfies the method's own schema is wire-valid by construction, so passing it fits the check's name. The case it misses is an extension result that is both unrecognised and malformed. That belongs to the extension's own schema once one is versioned.
We will drop the eight baseline entries when this ships in a release.