[SEP-2663] refactor!: remove 2025-11 experimental tasks (#2128)

This commit is contained in:
Felix Weinberger 2026-06-02 13:04:18 +01:00 • committed by GitHub
commit c8d7401b46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 423 additions and 18280 deletions

View file

@ -8,8 +8,6 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet<string> = new Set([
'CallToolRequestParamsSchema',
'CallToolRequestSchema',
'CallToolResultSchema',
'CancelTaskRequestSchema',
'CancelTaskResultSchema',
'CancelledNotificationParamsSchema',
'CancelledNotificationSchema',
'ClientCapabilitiesSchema',
@ -25,7 +23,6 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet<string> = new Set([
'CreateMessageRequestSchema',
'CreateMessageResultSchema',
'CreateMessageResultWithToolsSchema',
'CreateTaskResultSchema',
'CursorSchema',
'ElicitRequestFormParamsSchema',
'ElicitRequestParamsSchema',
@ -40,10 +37,6 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet<string> = new Set([
'GetPromptRequestParamsSchema',
'GetPromptRequestSchema',
'GetPromptResultSchema',
'GetTaskPayloadRequestSchema',
'GetTaskPayloadResultSchema',
'GetTaskRequestSchema',
'GetTaskResultSchema',
'IconSchema',
'IconsSchema',
'ImageContentSchema',
@ -70,8 +63,6 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet<string> = new Set([
'ListResourcesResultSchema',
'ListRootsRequestSchema',
'ListRootsResultSchema',
'ListTasksRequestSchema',
'ListTasksResultSchema',
'ListToolsRequestSchema',
'ListToolsResultSchema',
'LoggingLevelSchema',
@ -110,7 +101,6 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet<string> = new Set([
'ReadResourceRequestParamsSchema',
'ReadResourceRequestSchema',
'ReadResourceResultSchema',
'RelatedTaskMetadataSchema',
'RequestIdSchema',
'RequestMetaSchema',
'RequestSchema',
@ -140,13 +130,6 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet<string> = new Set([
'StringSchemaSchema',
'SubscribeRequestParamsSchema',
'SubscribeRequestSchema',
'TaskAugmentedRequestParamsSchema',
'TaskCreationParamsSchema',
'TaskMetadataSchema',
'TaskSchema',
'TaskStatusNotificationParamsSchema',
'TaskStatusNotificationSchema',
'TaskStatusSchema',
'TextContentSchema',
'TextResourceContentsSchema',
'TitledMultiSelectEnumSchemaSchema',

View file

@ -13,10 +13,7 @@ export const CONTEXT_PROPERTY_MAP: ContextMapping[] = [
{ from: '.sessionId', to: '.sessionId' },
{ from: '.requestInfo', to: '.http?.req' },
{ from: '.closeSSEStream', to: '.http?.closeSSE' },
{ from: '.closeStandaloneSSEStream', to: '.http?.closeStandaloneSSE' },
{ from: '.taskStore', to: '.task?.store' },
{ from: '.taskId', to: '.task?.id' },
{ from: '.taskRequestedTtl', to: '.task?.requestedTtl' }
{ from: '.closeStandaloneSSEStream', to: '.http?.closeStandaloneSSE' }
];
export const EXTRA_PARAM_NAME = 'extra';

View file

@ -152,12 +152,14 @@ export const IMPORT_MAP: Record<string, ImportMapping> = {
},
'@modelcontextprotocol/sdk/experimental/tasks': {
target: '@modelcontextprotocol/server',
status: 'moved'
target: '',
status: 'removed',
removalMessage: 'Experimental tasks removed in v2 (SEP-2663 — tasks moved to the Extensions Track). No v2 equivalent.'
},
'@modelcontextprotocol/sdk/experimental/tasks.js': {
target: '@modelcontextprotocol/server',
status: 'moved'
target: '',
status: 'removed',
removalMessage: 'Experimental tasks removed in v2 (SEP-2663 — tasks moved to the Extensions Track). No v2 equivalent.'
},
'@modelcontextprotocol/sdk/inMemory.js': {

View file

@ -14,11 +14,7 @@ export const SCHEMA_TO_METHOD: Record<string, string> = {
SetLevelRequestSchema: 'logging/setLevel',
PingRequestSchema: 'ping',
CompleteRequestSchema: 'completion/complete',
ListRootsRequestSchema: 'roots/list',
ListTasksRequestSchema: 'tasks/list',
GetTaskRequestSchema: 'tasks/get',
GetTaskPayloadRequestSchema: 'tasks/result',
CancelTaskRequestSchema: 'tasks/cancel'
ListRootsRequestSchema: 'roots/list'
};
export const NOTIFICATION_SCHEMA_TO_METHOD: Record<string, string> = {
@ -31,6 +27,5 @@ export const NOTIFICATION_SCHEMA_TO_METHOD: Record<string, string> = {
CancelledNotificationSchema: 'notifications/cancelled',
InitializedNotificationSchema: 'notifications/initialized',
RootsListChangedNotificationSchema: 'notifications/roots/list_changed',
TaskStatusNotificationSchema: 'notifications/tasks/status',
ElicitationCompleteNotificationSchema: 'notifications/elicitation/complete'
};

View file

@ -8,7 +8,7 @@ import { CONTEXT_PROPERTY_MAP, CTX_PARAM_NAME, EXTRA_PARAM_NAME } from '../mappi
const HANDLER_METHODS = new Set(['setRequestHandler', 'setNotificationHandler']);
const REGISTER_METHODS = new Set(['registerTool', 'registerPrompt', 'registerResource', 'registerToolTask', 'tool', 'prompt', 'resource']);
const REGISTER_METHODS = new Set(['registerTool', 'registerPrompt', 'registerResource', 'tool', 'prompt', 'resource']);
/**
* Attempt to rename the second parameter of a callback from 'extra' to 'ctx'
@ -219,7 +219,7 @@ export const contextTypesTransform: Transform = {
if (!callbackArg) continue;
// Handle ObjectLiteralExpression for registerToolTask-style callbacks
// Handle ObjectLiteralExpression callback containers (handler maps)
if (Node.isObjectLiteralExpression(callbackArg)) {
for (const prop of callbackArg.getProperties()) {
let callbackNode: Node | undefined;

View file

@ -3,7 +3,7 @@ import { Node, SyntaxKind } from 'ts-morph';
import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types.js';
import { info, warning } from '../../../utils/diagnostics.js';
import { isOriginalNameImportedFromMcp, resolveLocalImportName } from '../../../utils/importUtils.js';
import { isOriginalNameImportedFromMcp } from '../../../utils/importUtils.js';
export const mcpServerApiTransform: Transform = {
name: 'McpServer API migration',
@ -121,8 +121,6 @@ export const mcpServerApiTransform: Transform = {
}
}
changesCount += migrateConstructorTaskOptions(sourceFile, diagnostics);
return { changesCount, diagnostics };
}
};
@ -394,130 +392,3 @@ function migrateResourceCall(call: CallExpression, _sourceFile: SourceFile): boo
return true;
}
const TASK_OPTIONS = ['taskStore', 'taskMessageQueue'] as const;
function migrateConstructorTaskOptions(sourceFile: SourceFile, diagnostics: Diagnostic[]): number {
const localName = resolveLocalImportName(sourceFile, 'McpServer');
if (!localName) return 0;
let changes = 0;
for (const node of sourceFile.getDescendantsOfKind(SyntaxKind.NewExpression)) {
if (node.wasForgotten()) continue;
const expr = node.getExpression();
if (!Node.isIdentifier(expr) || expr.getText() !== localName) continue;
const args = node.getArguments();
if (args.length < 2) continue;
const optionsArg = args[1]!;
if (!Node.isObjectLiteralExpression(optionsArg)) continue;
// Check if any task options are present at the top level
const propsToMove: string[] = [];
for (const propName of TASK_OPTIONS) {
if (optionsArg.getProperty(propName)) {
propsToMove.push(propName);
}
}
if (propsToMove.length === 0) continue;
// Find the tasks object's position within the options text using AST,
// then do all mutations via a single text replacement to avoid node invalidation.
const capabilitiesProp = optionsArg.getProperty('capabilities');
let tasksObjStart = -1;
let tasksObjEnd = -1;
const optionsStart = optionsArg.getStart();
if (capabilitiesProp && Node.isPropertyAssignment(capabilitiesProp)) {
const capInit = capabilitiesProp.getInitializer();
if (capInit && Node.isObjectLiteralExpression(capInit)) {
const tasksProp = capInit.getProperty('tasks');
if (tasksProp && Node.isPropertyAssignment(tasksProp)) {
const tasksInit = tasksProp.getInitializer();
if (tasksInit && Node.isObjectLiteralExpression(tasksInit)) {
tasksObjStart = tasksInit.getStart() - optionsStart;
tasksObjEnd = tasksInit.getEnd() - optionsStart;
}
}
}
}
if (tasksObjStart === -1) {
for (const propName of propsToMove) {
diagnostics.push(
warning(
sourceFile.getFilePath(),
node.getStartLineNumber(),
`Move '${propName}' from McpServer options into capabilities.tasks — v2 expects task runtime options inside the tasks capability.`
)
);
}
continue;
}
// Single text replacement: remove top-level props and insert into tasks object.
// Use AST nodes (already located via getProperty) to get brace-balanced text and
// exact positions, avoiding regex truncation on values containing commas/braces.
// Collect all properties first, then process in reverse position order so each
// removal doesn't invalidate the positions of subsequent removals.
let optionsText = optionsArg.getText();
const argStart = optionsArg.getStart();
const propsWithPositions: { text: string; start: number; end: number }[] = [];
for (const propName of propsToMove) {
const prop = optionsArg.getProperty(propName);
if (!prop) continue;
propsWithPositions.push({
text: prop.getText(),
start: prop.getStart() - argStart,
end: prop.getEnd() - argStart
});
}
const propTexts = propsWithPositions.map(p => p.text);
// Remove in reverse position order so earlier positions remain valid
const sortedProps = propsWithPositions.toSorted((a, b) => b.start - a.start);
for (const { start, end } of sortedProps) {
let remStart = start;
let remEnd = end;
// Consume trailing comma and whitespace
const afterProp = optionsText.slice(remEnd);
const trailingMatch = afterProp.match(/^\s*,?\s*/);
if (trailingMatch) {
remEnd += trailingMatch[0].length;
}
// Consume leading whitespace/newline
const beforeProp = optionsText.slice(0, remStart);
const leadingMatch = beforeProp.match(/[\n\r]?\s*$/);
if (leadingMatch) {
remStart -= leadingMatch[0].length;
}
optionsText = optionsText.slice(0, remStart) + optionsText.slice(remEnd);
// Adjust tasks position if removal was before it
if (remStart < tasksObjStart) {
const shift = remEnd - remStart;
tasksObjStart -= shift;
tasksObjEnd -= shift;
}
}
if (propTexts.length === 0) continue;
// Insert into the tasks object (just before its closing brace)
const tasksText = optionsText.slice(tasksObjStart, tasksObjEnd);
const closingBrace = tasksText.lastIndexOf('}');
const before = tasksText.slice(0, closingBrace).trimEnd();
const sep = before.length > 1 ? ',\n' : '\n';
const newTasksText = before + sep + propTexts.join(',\n') + '\n' + tasksText.slice(closingBrace);
optionsText = optionsText.slice(0, tasksObjStart) + newTasksText + optionsText.slice(tasksObjEnd);
// Clean up double/trailing commas
optionsText = optionsText.replaceAll(/,(\s*,)/g, ',');
optionsText = optionsText.replaceAll(/,(\s*})/g, '$1');
optionsArg.replaceWithText(optionsText);
changes += propTexts.length;
}
return changes;
}