import { Logger } from './types.js'; /** * Task status values as per MCP spec * * Lifecycle: * - `working` → `input_required` | `completed` | `failed` | `cancelled` * - `input_required` → `working` | `completed` | `failed` | `cancelled` * - `completed`, `failed`, `cancelled` are terminal — no further transitions */ export type TaskStatus = 'working' | 'input_required' | 'completed' | 'failed' | 'cancelled'; /** * Terminal statuses — tasks in these states cannot transition further */ export declare const TERMINAL_STATUSES: TaskStatus[]; /** * Check if a status is terminal */ export declare function isTerminalStatus(status: TaskStatus): boolean; /** * Caller access context for task authorization and tenant isolation */ export interface TaskAccessContext { /** User/Subject ID of the caller */ userId?: string; /** Tenant ID of the caller */ tenantId?: string; /** MCP Session ID of the caller */ sessionId?: string; } /** * Task data structure as per MCP spec */ export interface TaskData { /** Unique identifier for the task */ taskId: string; /** Current state of the task execution */ status: TaskStatus; /** Optional human-readable message describing the current state */ statusMessage?: string; /** ISO 8601 timestamp when the task was created */ createdAt: string; /** ISO 8601 timestamp when the task status was last updated */ lastUpdatedAt: string; /** Time in milliseconds from creation before task may be deleted */ ttl: number | null; /** Suggested time in milliseconds between status checks */ pollInterval?: number; /** User/Subject ID of the task creator */ ownerId?: string; /** Tenant ID of the task creator */ tenantId?: string; /** MCP Session ID of the task creator (in stateful mode) */ sessionId?: string; } /** * Task parameters that can be sent with a task-augmented request */ export interface TaskParams { /** Requested TTL in milliseconds */ ttl?: number; /** User ID */ ownerId?: string; /** Tenant ID */ tenantId?: string; /** Session ID */ sessionId?: string; } /** * Related task metadata for associating messages with tasks */ export interface RelatedTaskMeta { taskId: string; } /** * CreateTaskResult — returned when a task-augmented request is accepted */ export interface CreateTaskResult { task: TaskData; } /** * Task execution support level for tools */ export type TaskSupportLevel = 'required' | 'optional' | 'forbidden'; /** * Internal task entry with execution details */ export interface TaskEntry { /** Task data (protocol-visible) */ data: TaskData; /** The pending result (resolved when task completes) */ result?: unknown; /** Error if the task failed */ error?: { code: number; message: string; data?: unknown; }; /** Abort controller for cancellation */ abortController: AbortController; /** Promise that resolves when the task reaches a terminal state */ completionPromise: Promise; /** Resolver for the completion promise */ resolveCompletion: () => void; /** Associated tool name */ toolName?: string; /** User/Subject ID */ ownerId?: string; /** Tenant ID */ tenantId?: string; /** Session ID */ sessionId?: string; } /** * TaskStore interface for abstracting task state storage. * Defaults to InMemoryTaskStore and allows drop-in distributed backends (Redis, PostgreSQL, DynamoDB) * to support multi-replica horizontally scaled deployments. */ export interface TaskStore { get(taskId: string): TaskEntry | undefined; set(taskId: string, entry: TaskEntry): void; delete(taskId: string): boolean; has(taskId: string): boolean; list(): TaskEntry[]; cleanupExpired?(now: number): number; destroy?(): void; } /** * In-memory implementation of TaskStore. */ export declare class InMemoryTaskStore implements TaskStore { private tasks; get(taskId: string): TaskEntry | undefined; set(taskId: string, entry: TaskEntry): void; delete(taskId: string): boolean; has(taskId: string): boolean; list(): TaskEntry[]; cleanupExpired(now: number): number; destroy(): void; } export interface TaskManagerOptions { logger: Logger; /** Custom pluggable task store (default: InMemoryTaskStore) */ store?: TaskStore; /** Default TTL in ms (default: 300000 = 5 minutes) */ defaultTtl?: number; /** Default poll interval in ms (default: 2000 = 2 seconds) */ defaultPollInterval?: number; /** Callback fired on every status change (for notifications) */ onStatusChange?: (taskData: TaskData) => void; } /** * TaskManager handles the full lifecycle of MCP tasks. * * It provides: * - Pluggable task storage (in-memory or distributed) with TTL cleanup * - Task creation, status updates, and result retrieval * - Cancellation support * - Status change notifications via callbacks */ export declare class TaskManager { private store; private logger; private defaultTtl; private defaultPollInterval; private cleanupInterval?; private onStatusChange?; constructor(options: TaskManagerOptions); /** Access the underlying TaskStore */ getStore(): TaskStore; /** * Create a new task */ createTask(params?: TaskParams, toolName?: string, accessContext?: TaskAccessContext): TaskData; /** * Verify caller authorization against task owner/tenant/session metadata * @throws TaskNotFoundError if access is denied (to avoid disclosing task existence across tenants) */ checkTaskAccess(entry: TaskEntry, context?: TaskAccessContext): void; /** * Get task data by ID * @throws Error if task not found or access denied */ getTask(taskId: string, context?: TaskAccessContext): TaskData; /** * Update task status * @throws Error if transition is invalid or access denied */ updateStatus(taskId: string, status: TaskStatus, statusMessage?: string, context?: TaskAccessContext): TaskData; /** * Complete a task with a successful result */ completeTask(taskId: string, result: unknown, statusMessage?: string, context?: TaskAccessContext): TaskData; /** * Fail a task with an error */ failTask(taskId: string, error: { code: number; message: string; data?: unknown; }, statusMessage?: string, context?: TaskAccessContext): TaskData; /** * Cancel a task * @throws Error if task is already in a terminal state or access denied */ cancelTask(taskId: string, context?: TaskAccessContext): TaskData; /** * Get the result of a completed task. * If the task is still working, this blocks until it reaches a terminal state. */ getResult(taskId: string, context?: TaskAccessContext): Promise<{ result?: unknown; error?: { code: number; message: string; data?: unknown; }; }>; /** * Get the AbortSignal for a task (useful for cancellation-aware handlers) */ getAbortSignal(taskId: string, context?: TaskAccessContext): AbortSignal; /** * List all tasks with optional cursor-based pagination and tenant/user filtering */ listTasks(cursor?: string, limit?: number, context?: TaskAccessContext): { tasks: TaskData[]; nextCursor?: string; }; /** * Check if a task exists */ hasTask(taskId: string, context?: TaskAccessContext): boolean; /** * Cleanup expired tasks * Only terminal tasks (completed, failed, cancelled) are evicted after their TTL expires. * Active tasks (working, input_required) are never evicted while execution is ongoing. */ private cleanupExpiredTasks; /** * Get internal entry or throw */ getEntry(taskId: string, context?: TaskAccessContext): TaskEntry; /** * Validate a status transition */ private validateTransition; /** * Stop the cleanup interval (call on server shutdown) */ destroy(): void; } /** * TaskContext provides a developer-friendly interface for working with tasks * inside tool handlers. It wraps the TaskManager and provides simple methods * to update progress and check for cancellation. * * @example * ```typescript * const tool = new Tool({ * name: 'process_data', * taskSupport: 'optional', * handler: async (input, context) => { * const task = context.task; // TaskContext if task-augmented * * if (task) { * task.updateProgress('Starting data processing...'); * * for (let i = 0; i < items.length; i++) { * task.throwIfCancelled(); // Throws if client cancelled * await processItem(items[i]); * task.updateProgress(`Processed ${i + 1}/${items.length} items`); * } * } * * return { processed: items.length }; * } * }); * ``` */ export declare class TaskContext { private taskManager; private _taskId; private _abortSignal; constructor(taskManager: TaskManager, taskId: string); /** The task ID */ get taskId(): string; /** AbortSignal that triggers when the task is cancelled */ get abortSignal(): AbortSignal; /** Whether the task has been cancelled */ get isCancelled(): boolean; /** * Update the task status message (keeps status as 'working') */ updateProgress(message: string): void; /** * Transition to input_required status */ requestInput(message: string): void; /** * Throw a TaskCancelledError if the task has been cancelled. * Call this periodically in long-running handlers to support cancellation. */ throwIfCancelled(): void; /** * Push an intermediate task update (MCP 2026-07-28 `tasks/update`). * * On the modern path this records progress that the client observes via * `tasks/get`; the optional `data` is attached to the status message. * Behaves like `updateProgress` on the legacy path so handlers are written * once. */ update(message: string, data?: unknown): void; /** * Get the current task data */ getTaskData(): TaskData; } /** * Task not found error (maps to JSON-RPC -32602) */ export declare class TaskNotFoundError extends Error { readonly taskId: string; readonly code = -32602; constructor(taskId: string); } /** * Task already in terminal state error (maps to JSON-RPC -32602) */ export declare class TaskAlreadyTerminalError extends Error { readonly taskId: string; readonly status: TaskStatus; readonly code = -32602; constructor(taskId: string, status: TaskStatus); } /** * Invalid task status transition error */ export declare class InvalidTaskTransitionError extends Error { readonly fromStatus: TaskStatus; readonly toStatus: TaskStatus; readonly code = -32603; constructor(fromStatus: TaskStatus, toStatus: TaskStatus); } /** * Task cancelled error (thrown by throwIfCancelled()) */ export declare class TaskCancelledError extends Error { readonly taskId: string; constructor(taskId: string); } /** * Task augmentation required error (maps to JSON-RPC -32600) */ export declare class TaskAugmentationRequiredError extends Error { readonly code = -32600; constructor(); } /** * Task expired error (maps to JSON-RPC -32602) */ export declare class TaskExpiredError extends Error { readonly taskId: string; readonly code = -32602; constructor(taskId: string); } //# sourceMappingURL=task.d.ts.map