Skip to content

Introduce extension SDK for TS - #21

Merged
LucaButBoring merged 44 commits into
modelcontextprotocol:mainfrom
LucaButBoring:feat/ts-sdk-tasks
Sep 23, 2026
Merged

LucaButBoring merged 44 commits into
modelcontextprotocol:mainfrom
LucaButBoring:feat/ts-sdk-tasks

Conversation

@LucaButBoring

@LucaButBoring LucaButBoring commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

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.

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

  • 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

We'll need to set up CI/CD to actually publish this separately. Need to figure out how to do this.

- add provenance-checked V1 and V2 schema artifacts
- implement generation-specific declarations and strict codecs
- cover protocol invariants with property-based tests
- implement the connected session port and immediate executions
- manage tool declarations with abortable ordered refreshes
- add input routing, lifecycle guards, and V2 tool codecs
- 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
- Correlate V1 task input with related-task metadata
- Handle keyed V2 input through validated partial updates
- Add fail-closed and lifecycle race coverage
- 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
- Split client and core monoliths into cohesive internal modules
- Consolidate generation-specific task drivers and remove pre-release aliases
- Strengthen codec, export, packed-consumer, and CI contracts
- Share generation-neutral codec validation and path helpers
- Preserve generation-specific request and wire decoding
- Require and add JSDoc for exported functions
- Replace handwritten V1/V2 codecs and wire types with inferred Zod schemas
- Accept caller result schemas directly and remove custom codec compatibility APIs
- Harden schema exports, protocol defaults, and packed dependency contracts
- Enable the strict type-checked typescript-eslint preset
- Resolve all unsafe, redundant, and confusing typed lint findings
- Strengthen runtime boundary checks and race/property tests
- 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.
- Finalize generation-tagged declarations and codec-neutral results
- Correct task input routing, recovery ownership, and lifecycle cleanup
- Add packed exports and SDK peer-range contract validation
- Document the initial client integration API without naming consumers

Signed-off-by: Luca Chang <lucalc@amazon.com>
- Add semantic task sessions, controllers, settlement, and input routing
- Add SDK raw-dispatch integration and receiver task bindings
- Add runtime boundary adapters and generation-neutral projections
- Remove obsolete task-result bridging and session history APIs
- Expand protocol, lifecycle, packaging, and consumer validation

Signed-off-by: Luca Chang <lucalc@amazon.com>
- Add per-request timeout options to tool calls and task controllers
- Preserve timeout context across initiating and follow-up requests
- Forward timeout values through the SDK client adapter
- Cover managed and detached task request propagation

Signed-off-by: Luca Chang <lucalc@amazon.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Protocol routing, task preference enforcement, schema validation, timer handling, and lifecycle issues remain unresolved.

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.

Changes:

  • Adds generation-neutral task sessions, execution lifecycle, recovery, input routing, and receiver APIs.
  • Adds runtime schemas, adapters, extensive tests, and package validation.
  • Adds TypeScript guides and repository CI/documentation integration.
File summaries
File Description
.github/workflows/ci.yml Expands package, documentation, and peer-range CI.
.github/workflows/deploy.yml Validates the repository before documentation deployment.
.gitignore Ignores package tarballs.
.vitepress/config.mts Adds TypeScript SDK navigation.
README.md Documents the TypeScript package and development commands.
package-lock.json Locks workspace dependencies.
package.json Configures workspaces and root scripts.
packages/ext-tasks/.prettierignore Excludes generated/package artifacts.
packages/ext-tasks/LICENSE Adds package licensing.
packages/ext-tasks/README.md Documents package usage and entry points.
packages/ext-tasks/eslint.config.mjs Configures package linting.
packages/ext-tasks/package.json Defines package exports, dependencies, and scripts.
packages/ext-tasks/schema/v1/schema.json Adds the pinned V1 JSON schema.
packages/ext-tasks/schema/v1/schema.ts Adds pinned V1 TypeScript declarations.
packages/ext-tasks/schema/v2/schema.json Adds the pinned V2 JSON schema.
packages/ext-tasks/schema/v2/schema.ts Adds pinned V2 TypeScript declarations.
packages/ext-tasks/scripts/check-exports.mjs Validates package and consumer contracts.
packages/ext-tasks/scripts/check-peer-range.mjs Checks supported client peer versions.
packages/ext-tasks/scripts/check-schema-provenance.mjs Verifies pinned schema provenance.
packages/ext-tasks/src/client/api.ts Defines the public client API.
packages/ext-tasks/src/client/client-adapter.test.ts Tests SDK client adaptation.
packages/ext-tasks/src/client/declarations-capabilities.test.ts Tests declarations and negotiated capabilities.
packages/ext-tasks/src/client/execution.ts Implements execution state, observation, and settlement.
packages/ext-tasks/src/client/immediate-session-basics.test.ts Tests immediate execution and session basics.
packages/ext-tasks/src/client/index.ts Exposes the client entry point.
packages/ext-tasks/src/client/input-routing.ts Implements application-input routing.
packages/ext-tasks/src/client/internal.ts Provides generation-neutral projections.
packages/ext-tasks/src/client/port.ts Implements task RPC dispatch.
packages/ext-tasks/src/client/protocol-matrix.test.ts Tests V1/V2 semantic parity.
packages/ext-tasks/src/client/request-input-continuation.test.ts Tests request-scoped input continuation.
packages/ext-tasks/src/client/sdk-client-adapter.ts Adapts SDK clients to task sessions.
packages/ext-tasks/src/client/session-facade.test.ts Tests the public session facade.
packages/ext-tasks/src/client/session.ts Implements task-enabled sessions.
packages/ext-tasks/src/client/task-controller.test.ts Tests manual task controllers.
packages/ext-tasks/src/client/task-controller.ts Implements manual task operations.
packages/ext-tasks/src/client/task-lifecycle-races.test.ts Tests lifecycle and concurrency races.
packages/ext-tasks/src/client/task-protocol-v1.ts Implements V1 task execution.
packages/ext-tasks/src/client/task-protocol-v2.ts Implements V2 task execution and input.
packages/ext-tasks/src/client/task-resumption.test.ts Tests task recovery and ownership.
packages/ext-tasks/src/client/tool-declarations.ts Manages tool discovery and refreshes.
packages/ext-tasks/src/client/v1-input-task.test.ts Tests V1 input routing.
packages/ext-tasks/src/client/v2-input-task.test.ts Tests V2 task input handling.
packages/ext-tasks/src/core/index.test.ts Tests core JSON and codec utilities.
packages/ext-tasks/src/core/index.ts Adds common types, codecs, and errors.
packages/ext-tasks/src/core/v1/index.test.ts Tests V1 schemas and negotiation.
packages/ext-tasks/src/core/v1/index.ts Exposes V1 APIs.
packages/ext-tasks/src/core/v1/negotiation.ts Implements V1 capability negotiation.
packages/ext-tasks/src/core/v1/schemas.ts Defines V1 runtime schemas.
packages/ext-tasks/src/core/v2/index.test.ts Tests V2 runtime contracts.
packages/ext-tasks/src/core/v2/index.ts Exposes V2 APIs.
packages/ext-tasks/src/core/v2/integration.ts Adds V2 capability and subscription helpers.
packages/ext-tasks/src/core/v2/schemas.ts Defines V2 runtime schemas.
packages/ext-tasks/src/receiver/index.ts Implements the V1 Tasks receiver.
packages/ext-tasks/src/receiver/receiver.test.ts Tests receiver lifecycle behavior.
packages/ext-tasks/test-support/client/fake-port.ts Adds a client test port.
packages/ext-tasks/test-support/client/semantic.ts Adds semantic test adapters.
packages/ext-tasks/tsconfig.eslint.json Configures lint type information.
packages/ext-tasks/tsconfig.json Configures package compilation.
packages/ext-tasks/tsconfig.test.json Configures test type-checking.
packages/ext-tasks/vitest.config.ts Configures package tests.
tsconfig.package.json Adds shared package compiler settings.
typescript/adapters-and-schemas.md Documents advanced adapters and schemas.
typescript/client/execution.md Documents execution control.
typescript/client/input-and-recovery.md Documents input handling and recovery.
typescript/getting-started.md Adds a requester quick start.
typescript/index.md Adds the TypeScript SDK overview.
typescript/migrating-from-the-sdk.md Documents SDK migration.
typescript/receiver.md Documents V1 receiver usage.
typescript/troubleshooting.md Documents common lifecycle failures.
Review details
  • Files reviewed: 65/69 changed files
  • Comments generated: 9
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/ext-tasks/src/client/port.ts
Comment thread packages/ext-tasks/src/core/v2/schemas.ts
Comment thread packages/ext-tasks/src/client/execution.ts Outdated
Comment thread packages/ext-tasks/src/client/execution.ts
Comment thread packages/ext-tasks/src/client/execution.ts
Comment thread packages/ext-tasks/src/client/session.ts Outdated
Comment thread packages/ext-tasks/src/client/session.ts Outdated
Comment thread packages/ext-tasks/src/client/session.ts
Comment thread packages/ext-tasks/src/receiver/index.ts

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Valid V2 tasks can fail after ten input rounds, and malformed task augmentation can bypass receiver validation.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
Resolved since last review (1)

Comment thread packages/ext-tasks/src/client/task-protocol-v2.ts Outdated
Comment thread packages/ext-tasks/src/receiver/index.ts

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Runtime validation, receiver protocol handling, setup rollback, and V2 onboarding contain unresolved correctness issues.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 High severity

Open (2)
Resolved since last review (2)
Previously missed (3)

In code that hasn't changed since last review

Medium severity 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.

Medium severity Sparse arrays bypass task ID validation

packages/​ext-tasks/​src/​core/​v2/​integration.ts:181

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.

Medium severity 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.

Comment thread packages/ext-tasks/src/core/v1/schemas.ts Outdated
Comment thread packages/ext-tasks/src/receiver/index.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Public option validation and V1 schema conformance issues must be corrected before release.

Review effort: Balanced
Findings: None

Resolved since last review (2)
Previously missed (3)

In code that hasn't changed since last review

Medium severity Validate maxInputRounds at session construction

packages/​ext-tasks/​src/​client/​session.ts:157

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.

Medium severity 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.

Medium severity 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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Medium severity 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.

Medium severity Explicitly validate V1 content fields

packages/​ext-tasks/​src/​core/​v1/​schemas.ts:110

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.

Medium severity Validate sampling request parameters against V2 schema

packages/​ext-tasks/​src/​core/​v2/​schemas.ts:215

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.

Medium severity Validate _meta in CreateMessageResult

packages/​ext-tasks/​src/​core/​v2/​schemas.ts:253

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Task identity validation, tool-pagination handling, and published declaration compatibility need correction before release.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 High severity

Open (2)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Reject invalid or repeated pagination cursors

packages/​ext-tasks/​src/​client/​tool-declarations.ts:152

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.

Comment thread packages/ext-tasks/src/client/port.ts Outdated
Comment thread packages/ext-tasks/src/client/port.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Runtime schema fidelity, task identity validation, and receiver binding lifecycle issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Resolved since last review (2)
Previously missed (3)

In code that hasn't changed since last review

Medium severity Validate the complete task capability envelope

packages/​ext-tasks/​src/​core/​v2/​integration.ts:117

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.

Medium severity Restrict includeContext to supported enum values

packages/​ext-tasks/​src/​core/​v2/​schemas.ts:229

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
Medium severity 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.

Comment thread packages/ext-tasks/src/client/port.ts

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The troubleshooting guide incorrectly documents which recovery failures produce TaskRecoveryOwnershipError.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@LucaButBoring
LucaButBoring marked this pull request as ready for review September 23, 2026 21:30
@LucaButBoring
LucaButBoring merged commit 6c0997f into modelcontextprotocol:main Sep 23, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants