Skip to content

Introduce extension SDK for TS - #21

Draft
LucaButBoring wants to merge 33 commits into
modelcontextprotocol:mainfrom
LucaButBoring:feat/ts-sdk-tasks
Draft

LucaButBoring wants to merge 33 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.

🟡 Changes recommended

V2 validation, capability merging, and documented signal behavior contain interoperability issues.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (4)

Previously missed (2) — in code that hasn't changed since the last review.

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

  • This overwrites an existing io.modelcontextprotocol/clientCapabilities object. For custom ports, request metadata that already advertises sampling, elicitation, or another extension loses those capabilities whenever Tasks framing is added. Merge the existing capability object and its extensions map, then add the Tasks key, matching the merge performed by frameV2TaskRequest().
    typescript/client/execution.md:93
  • This states that signal bounds the whole operation, but after callTool() returns a task execution the implementation disposes the linked call signal and constructs the execution with only the session lifecycle signal. Aborting the supplied signal later therefore does not stop task polling or input handling. Either retain that signal in the task execution lifecycle or document that it only bounds task creation.

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

  • The wire schema accepts any JSON value as a root, so values such as { roots: [null, "x"] } pass validation and are sent in tasks/update. The 2026-07-28 schema requires each root to be an object with a string uri (plus optional name and _meta). Validate the actual Root shape here.
    packages/ext-tasks/src/core/v2/schemas.ts:259
  • This schema only validates action; because openObject treats content and _meta as undeclared keys, it accepts any JSON value for either. The protocol requires content to be an object whose values are strings, integers, booleans, or string arrays, and _meta to be an object. Invalid handler output currently passes and is sent to the server.
  • Files reviewed: 65/69 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread packages/ext-tasks/src/core/v2/schemas.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.

🟡 Changes recommended

Lifecycle cancellation, protocol decoding, polling, and schema-validation defects can cause invalid traffic or broken task executions.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (8)

Previously missed (7) — in code that hasn't changed since the last review.

packages/ext-tasks/src/client/execution.ts:74

  • A missing server polling hint currently causes 100 tasks/get requests per second per active task. For minute-long tasks or many concurrent executions this can overwhelm both client and server; use a production-safe default cadence (typically on the order of seconds) or make it configurable.
    packages/ext-tasks/src/client/execution.ts:574
  • A successful direct execution.cancel() does not end the input lifetime, so an in-flight application input handler can continue and submit tasks/update after cancellation was accepted. End input handling when the shared cancellation promise succeeds (but not when cancellation fails).
    packages/ext-tasks/src/client/session.ts:260
  • Input is aborted before remote cancellation is known to have succeeded. If the cancellation RPC fails, the still-running task permanently loses its input handler and can no longer progress. Abort the input lifetime only after execution.cancel() resolves.
    packages/ext-tasks/src/client/session.ts:425
  • This disposes the link to ToolCallOptions.signal as soon as task creation returns. Consequently aborting that signal later does not stop task polling or task-scoped input, despite the public contract documenting that it bounds the operation lifecycle. Keep the linked lifecycle alive for task executions and dispose it when that execution ends.
    packages/ext-tasks/src/client/task-protocol-v2.ts:179
  • Including the initial hint in every Math.max makes a later lower pollIntervalMs ineffective, although the wire contract allows this value to change over a task's lifetime. Once a detailed snapshot exists, honor its current hint rather than permanently retaining the creation-time value.
    packages/ext-tasks/src/core/v1/schemas.ts:37
  • The V1 wire schema defines JSON-RPC request IDs as strings or integers, but z.number() also accepts fractions. This lets the exported guards/types accept invalid request envelopes; use z.int() to match the pinned schema.
    packages/ext-tasks/src/core/v2/schemas.ts:256
  • ListRootsResult requires an array of Root objects with a string uri, but this accepts any JSON values (including numbers and strings). Since this schema validates application input responses before tasks/update, malformed roots can be emitted on the wire instead of being rejected locally.

This issue also appears on line 257 of the same file.

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

  • content is a declared part of an elicitation result, but leaving it to the open-object catchall accepts arbitrary nested JSON. The protocol restricts each submitted field to string, number, boolean, or string array, so invalid handler output currently passes validation and is sent in tasks/update. Add the declared content schema.
  • Files reviewed: 65/69 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment thread packages/ext-tasks/src/client/execution.ts Outdated
Comment thread packages/ext-tasks/src/client/session.ts Outdated
Comment thread packages/ext-tasks/src/client/tool-declarations.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.

🔵 Needs a closer look

Public input types and runtime schemas accept invalid protocol data, JSON validation has an edge-case bypass, and declaration projection loses extension fields.

Review details

Suppressed comments (7)

Previously missed (6) — in code that hasn't changed since the last review.

packages/ext-tasks/src/client/api.ts:165

  • The public callback type permits nested objects, nulls, and arbitrary arrays in elicitation content, although those values are not valid on the wire. This makes type-correct handlers fail only when their response is encoded; narrow the value type to the protocol's scalar/string-array union.
    packages/ext-tasks/src/client/api.ts:177
  • A root is typed as an arbitrary record, so TypeScript accepts { roots: [{}] } even though every protocol root requires a string uri. Model the required root fields here so invalid handler implementations are rejected at compile time.
    packages/ext-tasks/src/client/internal.ts:160
  • When projecting a discovered V1 tool, only taskSupport is retained from execution; every other nested execution field is silently discarded even though ToolDeclaration.executionExtensions promises to retain such data for inspection and projection.

This issue also appears on line 203 of the same file.
packages/ext-tasks/src/core/index.ts:166

  • This sparse-array check can be bypassed by an enumerable non-index property: an array with one hole and one extra property has length === Object.keys(...).length, while every() skips the hole. isJsonValue() then returns true even though serialization changes the value to [null]. Verify that every index is an own property in addition to rejecting extra keys.
    packages/ext-tasks/src/core/v2/schemas.ts:256
  • This accepts any JSON value as a root, so callback output such as { roots: [null] } passes validation and is sent in tasks/update. The protocol requires each root to have a string uri (with optional name and _meta); validate that shape here.
    packages/ext-tasks/src/core/v2/schemas.ts:259
  • The elicitation result schema validates only action; because the object is open, any JSON value is accepted for content. This lets invalid form responses reach tasks/update, while the protocol limits content values to strings, numbers, booleans, or string arrays.

packages/ext-tasks/src/client/internal.ts:209

  • executionExtensions is part of the public neutral declaration specifically to retain nested execution fields, but V1 projection drops it and emits only taskSupport. A declaration created by toolDeclarationFromMcpTool() therefore cannot round-trip vendor execution data.
  return generation === "v1"
    ? {
        ...common,
        ...(declaration.taskSupport === undefined
          ? {}
          : { execution: { taskSupport: declaration.taskSupport } }),
      }
  • Files reviewed: 66/70 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

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

Task cancellation, V1 result retrieval, capability merging, and malformed input handling contain unresolved correctness issues.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (3)

Previously missed (3) — in code that hasn't changed since the last review.

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

  • Installing the Tasks capability replaces any existing value under io.modelcontextprotocol/clientCapabilities, including other capabilities and extensions supplied by a custom port caller. Merge the existing capability object and its extensions map before adding the Tasks key, as frameV2TaskRequest() already does for SDK-backed ports.
    packages/ext-tasks/src/receiver/index.ts:160
  • A non-null scalar task value is treated as valid augmentation, so malformed requests such as { task: true } bypass the SDK validator and create retained tasks. Require an object-shaped task metadata value (and validate ttl when present); malformed augmentation can then continue through the SDK validation path instead of the receiver handler.
    packages/ext-tasks/src/receiver/index.ts:451
  • The 2025-11-25 tasks/result operation is a blocking result retrieval, but this rejects whenever work is still pending. A conforming client may call it immediately after task creation and should be allowed to await record.result; the current behavior breaks those clients even though this package's own requester happens to poll first.
  • Files reviewed: 65/70 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread packages/ext-tasks/src/client/execution.ts
Comment thread packages/ext-tasks/src/client/task-protocol-v2.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.

🔵 Needs a closer look

Task cancellation signals, recovery request context, and V1 manual cancellation outcomes are not preserved correctly.

Review details

Suppressed comments (3)

Previously missed (3) — in code that hasn't changed since the last review.

packages/ext-tasks/src/client/session.ts:433

  • The call-scoped signal is disconnected as soon as the initial tools/call returns: this finally disposes its linkage, and both task constructors below receive only this.lifecycleController.signal. Consequently, aborting options.signal after callTool() returns does not stop polling or abort task input, despite the documented contract that the signal bounds the operation's local lifecycle. Transfer the linked lifecycle to task-backed executions and dispose it when those executions settle/detach; only dispose it here for immediate/error paths.
    packages/ext-tasks/src/client/session.ts:575
  • Recovery dispatches tasks/get without any DispatchContext, and the recovered execution is likewise created without one. Since TaskRecoveryOptions exposes no headers or request timeout, a task originally called with per-request authentication cannot be resumed after reconnecting: every follow-up silently loses that required context. Add recovery request-context options and propagate them to the initial lookup and the recovered execution for both generations.
    packages/ext-tasks/src/client/task-controller.ts:113
  • The V1 branch calls tasks/result directly and wraps every rejection as a failed outcome. Under the V1 protocol, tasks/result returns an error for any non-completed task, so a cancelled task can never produce the cancelled outcome promised by this generation-neutral API (and a known failed task loses its task snapshot). Poll tasks/get to a terminal state first, as the owned V1 execution does, then classify cancelled/failed and call tasks/result only for completed tasks.
  • Files reviewed: 64/70 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

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

Runtime schema, recovery lifecycle, fallback routing, receiver error handling, and release validation issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

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

  • ApplicationElicitContentValue and the pinned MCP ElicitResult.content type both allow any JSON number, but this schema accepts only integers. A type-correct handler returning a decimal (for example, a form field with 1.5) will fail response validation, so the task update is skipped and the task can remain input_required. Use z.number() here.
    packages/ext-tasks/src/receiver/index.ts:241
  • report() runs from detached promise rejection handlers (notification failures and late callback failures). If the consumer's onError callback throws, those detached promises reject with no observer and can trigger an unhandled rejection. Guard the error sink, as the client session's reportBackgroundError already does, so reporting cannot create a second background failure.
  • Files reviewed: 62/70 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment thread .github/workflows/npm-publish.yml
Comment thread packages/ext-tasks/src/client/sdk-client-adapter.ts
Comment thread packages/ext-tasks/src/client/session.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.

🔵 Needs a closer look

Protocol validation, V1 task requirements, lifecycle cancellation, and unsafe operational defaults need correction before release.

Review details

Suppressed comments (6)

Previously missed (4) — in code that hasn't changed since the last review.

packages/ext-tasks/src/client/execution.ts:85

  • A missing server polling hint currently produces one tasks/get every 10 ms per active task (100 requests/second/task). This default can overwhelm both client and server under ordinary concurrent workloads; use a production-safe cadence unless the server explicitly requests faster polling.
    packages/ext-tasks/src/client/session.ts:237
  • Unlike calls and task-controller operations, listTasks() passes only the caller signal to the port. Closing or invalidating the session therefore does not abort an in-flight list request, so it can hang or resolve after the session is unusable. Link the caller signal with this.lifecycleController.signal, dispose that link in finally, and re-check session usability after dispatch.

This issue also appears on line 320 of the same file.
packages/ext-tasks/src/core/v2/integration.ts:43

  • This predicate reports Tasks support for any owned value, including null, true, or a non-empty object, although TasksExtensionCapabilityV2Schema requires an empty object. Callers can therefore enable V2 behavior from a malformed capability envelope. Validate the extension value as well as the key's presence.
    packages/ext-tasks/src/receiver/index.ts:184
  • This accepts task.ttl: null, even though the package's own 2025-11-25 TaskMetadataV1Schema defines ttl as an optional integer and rejects null. A malformed task augmentation therefore reaches the receiver and creates a task; omission should represent an unspecified TTL.

This issue also appears on line 214 of the same file.

packages/ext-tasks/src/receiver/index.ts:217

  • The default combination retains tasks forever (ttlMs === null) but rejects every new task once 1,000 records have accumulated. Because there is no per-task deletion API, a long-lived receiver using defaults permanently stops accepting work after its first 1,000 requests. Please pair the finite capacity with a finite default retention period, provide terminal-record eviction, or otherwise make the defaults preserve availability.
    packages/ext-tasks/src/client/session.ts:324
  • For V1, preference: "forbid" forces callAsTaskV1 false even when the declaration says taskSupport: "required"; likewise, missing server task capability falls through to an ordinary call. Both paths violate the known tool contract and dispatch a request that cannot validly execute. Reject this conflict before dispatch instead.
  • Files reviewed: 60/70 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

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