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
Introduces an extension SDK for Tasks support, layered on top of the general TS SDK. Supports both the 2025-11-25 and 2026-07-28 specifications. Original implementation comes from the Inspector and has been reshaped to make a cleaner public API.
- add package-level format and format-check scripts
- enforce formatting in the package check workflow
- preserve immutable schema artifacts through ignore rules
- Add V1 and V2 task drivers with polling, notifications, and retries
- Implement conflated updates, cancellation, and lifecycle cleanup
- Cover protocol envelopes and adversarial races with property tests
- Add type-aware ESLint configuration for the ext-tasks package
- Integrate linting into package checks and prepack verification
- Fix type-safety, lifecycle, and test diagnostics without suppressions
- Bind serialized references to durable endpoint identities
- Resume V1 and V2 tasks with generation-specific lifecycles
- Adapt Client 2.0 through public request and handler seams
- Extract input projection, correlation, and context utilities
- Decompose V2 input resolution and schema construction
- Clarify task update queues and close a notification startup race
Centralize snapshot arbitration and observation sequencing behind named driver contexts. Decompose V2 task and input processing, with regression coverage for terminal authority and one-shot input keys.
Replace forward-declared branch results with focused helpers and explicit outcomes. Keep timing-sensitive session locals and iterative cursor state unchanged.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Introduces a publishable TypeScript SDK for MCP Tasks, supporting V1/V2 requester workflows and V1 receivers, with documentation, tests, packaging, and CI integration.
Predicates can throw on hostile objects or proxies
packages/ext-tasks/src/core/index.ts:174
As a public predicate over unknown, this can throw instead of returning false for objects with throwing getters or proxies: Object.values() and Reflect.getPrototypeOf() both execute user-controlled traps. JsonValueCodec.parse() delegates here as well, so malformed host input can escape the codec rather than produce a decode failure.
Sparse arrays bypass this validation because Array.prototype.every() skips holes. For example, { notifications: { taskIds: [, "task"] } } returns [undefined, "task"] despite the declared readonly string[] return type and the function's promise to reject any non-string ID.
Handler installation lacks rollback on failure
packages/ext-tasks/src/receiver/index.ts:380
Handler installation is not transactional. If a later setRequestHandler call throws (for example, sampling is declared but elicitation is not), earlier handlers have already replaced the client's handlers, yet construction throws before returning a binding that can restore them. Wrap the installation sequence in rollback logic so failed binding cannot leave the client partially modified.
maxInputRounds is used as a numeric counter limit without any runtime validation. Values such as 1.5 allow two rounds, negative values reject even the first round, and NaN silently disables the cap. Validate this public option when constructing the session, consistently with retentionMs and the receiver limits.
Enforce ToolAnnotations field types
packages/ext-tasks/src/core/v1/schemas.ts:76
annotations is validated only as arbitrary JSON, so invalid declarations such as { readOnlyHint: "yes" } are accepted. The pinned V1 ToolAnnotations schema requires booleans for the four hint fields and a string for title (packages/ext-tasks/schema/v1/schema.json:3708-3733); this runtime schema should enforce those types before managed discovery exposes the tool.
Enforce Icon schema constraints
packages/ext-tasks/src/core/v1/schemas.ts:77
This schema accepts any JSON object as an icon, including {} or { src: 42 }. The pinned 2025-11-25 Icon schema requires a string src and constrains mimeType, sizes, and theme (packages/ext-tasks/schema/v1/schema.json:1303-1334), so malformed tools/list data currently passes discovery and is exposed as a valid declaration.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
Runtime schemas and public result types currently permit protocol-invalid sampling and elicitation payloads.
Review effort: Balanced Findings: None
Previously missed (4)
In code that hasn't changed since last review
Narrow ApplicationCreateMessageResult content type
packages/ext-tasks/src/client/api.ts:180
ApplicationCreateMessageResult.content is much wider than the runtime contract used for both request continuation and task updates: null, numbers, and arbitrary objects type-check here but are rejected by CreateMessageResultV2Schema. This defeats the promise that createApplicationInputHandler() keeps request and response types paired and turns type-correct callbacks into runtime failures. Expose a generation-neutral union of valid sampling content blocks instead of JsonValue.
These V1 content schemas put declared protocol fields into an unrestricted JSON catchall. For example, { type: "text", text: "x", annotations: true } currently parses successfully, although the pinned V1 schema requires annotations and _meta to be objects with typed annotation fields. As a result malformed tool results are exposed as valid CallToolResultV1 values. Model the shared content fields (and the declared resource-link fields) explicitly before allowing genuinely unknown extensions.
Validate sampling request parameters against V2 schema
The exported sampling request schema treats params as any JSON object, so inputs such as { method: "sampling/createMessage", params: {} } pass even though the V2 wire contract requires the sampling fields (for example messages and maxTokens). Because this schema is also used inside InputRequestsV2Schema, malformed task input reaches application handlers as valid. Validate against the actual V2 CreateMessageRequestParams shape rather than a generic record.
This issue also appears on line 220 of the same file.
CreateMessageResult explicitly declares _meta as a metadata object, but leaving it to openObject()'s catchall accepts values such as _meta: true. That malformed handler output can then be submitted in tasks/update as if it were a valid sampling response. Add _meta to the declared shape so it is validated consistently with the other V2 result schemas.
Malformed pagination can either silently truncate discovery or loop forever here: a non-string nextCursor is treated as end-of-list, while a repeated string cursor keeps issuing tools/list indefinitely. Validate a present cursor and reject already-seen cursors so calls fail deterministically instead of using incomplete declarations or flooding the server.
This public type guard only validates the Tasks entry, so values like { extensions: { "io.modelcontextprotocol/tasks": {}, other: undefined } } return true even though they are not ServerTaskCapabilityEnvelopeV2. Validate the complete envelope before narrowing; otherwise callers can unsafely treat unrelated extension values as JsonValue.
The pinned V2 schema restricts includeContext to "allServers", "none", or "thisServer"; accepting any string lets malformed sampling input pass the exported wire schema and reach application handlers as valid.
This issue also appears in the following locations of the same file:
line 248
line 366
line 391
Prevent multiple active receiver bindings
packages/ext-tasks/src/receiver/index.ts:218
Multiple receiver bindings can be created for the same client. If binding A is closed while binding B is active, then closing B restores A's now-closed handlers, leaving task methods permanently rejecting instead of restoring the original handlers. Reject a second active binding (as the client adapter does) or maintain binding ownership so closed handlers are never restored.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduces an extension SDK for Tasks support, layered on top of the general TS SDK. Supports both the
2025-11-25and2026-07-28specifications. Original implementation comes from the Inspector and has been reshaped to make a cleaner public API.Motivation and Context
Unblocks support for Tasks for TS SDK consumers.
How Has This Been Tested?
Integrated into the MCP Inspector in a branch (modelcontextprotocol/inspector#2308).
Breaking Changes
N/A; new package.
Types of changes
Checklist
Additional context
We'll need to set up CI/CD to actually publish this separately. Need to figure out how to do this.