From c606d5b9da673128237628bfbb7424866cb23af3 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Tue, 11 Nov 2025 16:06:27 +0000 Subject: [PATCH 1/4] Add SEP-1330 conformance test for elicitation enum schemas Adds server-side conformance test that validates servers properly request elicitation with SEP-1330 enum schema improvements: - Untitled single-select enum (type: string, enum: [...]) - Titled single-select enum (oneOf with const/title) - Legacy titled enum (enumNames for backward compatibility) - Untitled multi-select enum (type: array, items.enum) - Titled multi-select enum (items.anyOf with const/title) Test expects server to implement `test_elicitation_sep1330_enums` tool. --- src/scenarios/index.ts | 4 + src/scenarios/server/elicitation-enums.ts | 375 ++++++++++++++++++++++ 2 files changed, 379 insertions(+) create mode 100644 src/scenarios/server/elicitation-enums.ts diff --git a/src/scenarios/index.ts b/src/scenarios/index.ts index 8141b4d..8f23eb1 100644 --- a/src/scenarios/index.ts +++ b/src/scenarios/index.ts @@ -28,6 +28,7 @@ import { } from './server/tools.js'; import { ElicitationDefaultsScenario } from './server/elicitation-defaults.js'; +import { ElicitationEnumsScenario } from './server/elicitation-enums.js'; import { ResourcesListScenario, @@ -81,6 +82,9 @@ export const clientScenarios = new Map([ // Elicitation scenarios (SEP-1034) ['elicitation-sep1034-defaults', new ElicitationDefaultsScenario()], + // Elicitation scenarios (SEP-1330) + ['elicitation-sep1330-enums', new ElicitationEnumsScenario()], + // Resources scenarios ['resources-list', new ResourcesListScenario()], ['resources-read-text', new ResourcesReadTextScenario()], diff --git a/src/scenarios/server/elicitation-enums.ts b/src/scenarios/server/elicitation-enums.ts new file mode 100644 index 0000000..93bb44c --- /dev/null +++ b/src/scenarios/server/elicitation-enums.ts @@ -0,0 +1,375 @@ +/** + * SEP-1330: Elicitation enum schema improvements test scenarios for MCP servers + */ + +import { ClientScenario, ConformanceCheck } from '../../types.js'; +import { connectToServer } from './client-helper.js'; +import { ElicitRequestSchema } from '@modelcontextprotocol/sdk/types.js'; + +export class ElicitationEnumsScenario implements ClientScenario { + name = 'elicitation-sep1330-enums'; + description = 'Test elicitation with enum schema improvements (SEP-1330)'; + + async run(serverUrl: string): Promise { + const checks: ConformanceCheck[] = []; + + try { + const connection = await connectToServer(serverUrl); + + let capturedRequest: any = null; + connection.client.setRequestHandler( + ElicitRequestSchema, + async (request) => { + capturedRequest = request; + // Return mock data for all enum types + return { + action: 'accept', + content: { + untitledSingle: 'option1', + titledSingle: 'value1', + legacyEnum: 'opt1', + untitledMulti: ['option1', 'option2'], + titledMulti: ['value1', 'value2'] + } + }; + } + ); + + await connection.client.callTool({ + name: 'test_elicitation_sep1330_enums', + arguments: {} + }); + + // Validate that elicitation was requested + if (!capturedRequest) { + checks.push({ + id: 'elicitation-sep1330-general', + name: 'ElicitationSEP1330General', + description: 'Server requests elicitation with enum schemas', + status: 'FAILURE', + timestamp: new Date().toISOString(), + errorMessage: 'Server did not request elicitation from client', + specReferences: [ + { + id: 'SEP-1330', + url: 'https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330' + } + ] + }); + await connection.close(); + return checks; + } + + const schema = capturedRequest.params?.requestedSchema; + const properties = schema?.properties; + + // Validate untitled single-select enum + const untitledSingleErrors: string[] = []; + if (!properties?.untitledSingle) { + untitledSingleErrors.push( + 'Missing untitled single-select enum field "untitledSingle"' + ); + } else { + if (properties.untitledSingle.type !== 'string') { + untitledSingleErrors.push( + `Expected type "string", got "${properties.untitledSingle.type}"` + ); + } + if ( + !properties.untitledSingle.enum || + !Array.isArray(properties.untitledSingle.enum) + ) { + untitledSingleErrors.push('Missing or invalid enum array'); + } + if (properties.untitledSingle.oneOf) { + untitledSingleErrors.push( + 'Untitled enum should not have oneOf property' + ); + } + if (properties.untitledSingle.enumNames) { + untitledSingleErrors.push( + 'Untitled enum should not have enumNames property' + ); + } + } + + checks.push({ + id: 'elicitation-sep1330-untitled-single', + name: 'ElicitationSEP1330UntitledSingle', + description: 'Untitled single-select enum schema uses enum array', + status: untitledSingleErrors.length === 0 ? 'SUCCESS' : 'FAILURE', + timestamp: new Date().toISOString(), + errorMessage: + untitledSingleErrors.length > 0 + ? untitledSingleErrors.join('; ') + : undefined, + specReferences: [ + { + id: 'SEP-1330', + url: 'https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330' + } + ], + details: { + field: 'untitledSingle', + schema: properties?.untitledSingle + } + }); + + // Validate titled single-select enum (using oneOf with const/title) + const titledSingleErrors: string[] = []; + if (!properties?.titledSingle) { + titledSingleErrors.push( + 'Missing titled single-select enum field "titledSingle"' + ); + } else { + if (properties.titledSingle.type !== 'string') { + titledSingleErrors.push( + `Expected type "string", got "${properties.titledSingle.type}"` + ); + } + if ( + !properties.titledSingle.oneOf || + !Array.isArray(properties.titledSingle.oneOf) + ) { + titledSingleErrors.push( + 'Missing or invalid oneOf array for titled enum' + ); + } else { + // Validate oneOf structure has const/title pairs + const invalidItems = properties.titledSingle.oneOf.filter( + (item: any) => + typeof item.const !== 'string' || typeof item.title !== 'string' + ); + if (invalidItems.length > 0) { + titledSingleErrors.push( + `oneOf items must have "const" (string) and "title" (string) properties` + ); + } + } + if (properties.titledSingle.enum) { + titledSingleErrors.push( + 'Titled enum should use oneOf instead of enum array' + ); + } + } + + checks.push({ + id: 'elicitation-sep1330-titled-single', + name: 'ElicitationSEP1330TitledSingle', + description: + 'Titled single-select enum schema uses oneOf with const/title', + status: titledSingleErrors.length === 0 ? 'SUCCESS' : 'FAILURE', + timestamp: new Date().toISOString(), + errorMessage: + titledSingleErrors.length > 0 + ? titledSingleErrors.join('; ') + : undefined, + specReferences: [ + { + id: 'SEP-1330', + url: 'https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330' + } + ], + details: { + field: 'titledSingle', + schema: properties?.titledSingle + } + }); + + // Validate legacy titled enum (using enumNames - deprecated) + const legacyEnumErrors: string[] = []; + if (!properties?.legacyEnum) { + legacyEnumErrors.push('Missing legacy titled enum field "legacyEnum"'); + } else { + if (properties.legacyEnum.type !== 'string') { + legacyEnumErrors.push( + `Expected type "string", got "${properties.legacyEnum.type}"` + ); + } + if ( + !properties.legacyEnum.enum || + !Array.isArray(properties.legacyEnum.enum) + ) { + legacyEnumErrors.push('Missing or invalid enum array'); + } + if ( + !properties.legacyEnum.enumNames || + !Array.isArray(properties.legacyEnum.enumNames) + ) { + legacyEnumErrors.push( + 'Missing or invalid enumNames array for legacy titled enum' + ); + } else if ( + properties.legacyEnum.enum && + properties.legacyEnum.enumNames.length !== + properties.legacyEnum.enum.length + ) { + legacyEnumErrors.push( + `enumNames length (${properties.legacyEnum.enumNames.length}) must match enum length (${properties.legacyEnum.enum.length})` + ); + } + } + + checks.push({ + id: 'elicitation-sep1330-legacy-enumnames', + name: 'ElicitationSEP1330LegacyEnumNames', + description: 'Legacy titled enum schema uses enumNames (deprecated)', + status: legacyEnumErrors.length === 0 ? 'SUCCESS' : 'FAILURE', + timestamp: new Date().toISOString(), + errorMessage: + legacyEnumErrors.length > 0 ? legacyEnumErrors.join('; ') : undefined, + specReferences: [ + { + id: 'SEP-1330', + url: 'https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330' + } + ], + details: { + field: 'legacyEnum', + schema: properties?.legacyEnum + } + }); + + // Validate untitled multi-select enum + const untitledMultiErrors: string[] = []; + if (!properties?.untitledMulti) { + untitledMultiErrors.push( + 'Missing untitled multi-select enum field "untitledMulti"' + ); + } else { + if (properties.untitledMulti.type !== 'array') { + untitledMultiErrors.push( + `Expected type "array", got "${properties.untitledMulti.type}"` + ); + } + if (!properties.untitledMulti.items) { + untitledMultiErrors.push('Missing items property for array type'); + } else { + if (properties.untitledMulti.items.type !== 'string') { + untitledMultiErrors.push( + `Expected items.type "string", got "${properties.untitledMulti.items.type}"` + ); + } + if ( + !properties.untitledMulti.items.enum || + !Array.isArray(properties.untitledMulti.items.enum) + ) { + untitledMultiErrors.push('Missing or invalid items.enum array'); + } + if (properties.untitledMulti.items.anyOf) { + untitledMultiErrors.push( + 'Untitled multi-select should use items.enum, not items.anyOf' + ); + } + } + } + + checks.push({ + id: 'elicitation-sep1330-untitled-multi', + name: 'ElicitationSEP1330UntitledMulti', + description: + 'Untitled multi-select enum schema uses array with items.enum', + status: untitledMultiErrors.length === 0 ? 'SUCCESS' : 'FAILURE', + timestamp: new Date().toISOString(), + errorMessage: + untitledMultiErrors.length > 0 + ? untitledMultiErrors.join('; ') + : undefined, + specReferences: [ + { + id: 'SEP-1330', + url: 'https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330' + } + ], + details: { + field: 'untitledMulti', + schema: properties?.untitledMulti + } + }); + + // Validate titled multi-select enum (using items.anyOf with const/title) + const titledMultiErrors: string[] = []; + if (!properties?.titledMulti) { + titledMultiErrors.push( + 'Missing titled multi-select enum field "titledMulti"' + ); + } else { + if (properties.titledMulti.type !== 'array') { + titledMultiErrors.push( + `Expected type "array", got "${properties.titledMulti.type}"` + ); + } + if (!properties.titledMulti.items) { + titledMultiErrors.push('Missing items property for array type'); + } else { + if ( + !properties.titledMulti.items.anyOf || + !Array.isArray(properties.titledMulti.items.anyOf) + ) { + titledMultiErrors.push( + 'Missing or invalid items.anyOf array for titled multi-select' + ); + } else { + // Validate anyOf structure has const/title pairs + const invalidItems = properties.titledMulti.items.anyOf.filter( + (item: any) => + typeof item.const !== 'string' || typeof item.title !== 'string' + ); + if (invalidItems.length > 0) { + titledMultiErrors.push( + `items.anyOf entries must have "const" (string) and "title" (string) properties` + ); + } + } + if (properties.titledMulti.items.enum) { + titledMultiErrors.push( + 'Titled multi-select should use items.anyOf, not items.enum' + ); + } + } + } + + checks.push({ + id: 'elicitation-sep1330-titled-multi', + name: 'ElicitationSEP1330TitledMulti', + description: + 'Titled multi-select enum schema uses array with items.anyOf', + status: titledMultiErrors.length === 0 ? 'SUCCESS' : 'FAILURE', + timestamp: new Date().toISOString(), + errorMessage: + titledMultiErrors.length > 0 + ? titledMultiErrors.join('; ') + : undefined, + specReferences: [ + { + id: 'SEP-1330', + url: 'https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330' + } + ], + details: { + field: 'titledMulti', + schema: properties?.titledMulti + } + }); + + await connection.close(); + } catch (error) { + checks.push({ + id: 'elicitation-sep1330-general', + name: 'ElicitationSEP1330General', + description: 'Server requests elicitation with enum schemas', + status: 'FAILURE', + timestamp: new Date().toISOString(), + errorMessage: `Failed: ${error instanceof Error ? error.message : String(error)}`, + specReferences: [ + { + id: 'SEP-1330', + url: 'https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330' + } + ] + }); + } + + return checks; + } +} From 7d927afe3e2f8f63ea6f09d90d58b9819a5d2088 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Tue, 11 Nov 2025 16:24:03 +0000 Subject: [PATCH 2/4] Add reference server implementation for SEP-1330 conformance test Adds test_elicitation_sep1330_enums tool to everything-server that requests elicitation with all 5 enum schema variants. Also updates SERVER_REQUIREMENTS.md with full specification. --- SERVER_REQUIREMENTS.md | 90 +++++++++++++++++ .../servers/typescript/everything-server.ts | 99 +++++++++++++++++++ 2 files changed, 189 insertions(+) diff --git a/SERVER_REQUIREMENTS.md b/SERVER_REQUIREMENTS.md index 1c8de1f..91bc39d 100644 --- a/SERVER_REQUIREMENTS.md +++ b/SERVER_REQUIREMENTS.md @@ -463,6 +463,96 @@ If no progress token provided, just execute with delays. **Reference**: [SEP-1034](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1034) +#### `test_elicitation_sep1330_enums` + +**Arguments**: None + +**Behavior**: Request user input from the client using `elicitation/create` with enum schema improvements (SEP-1330) + +**Elicitation Request**: + +```json +{ + "method": "elicitation/create", + "params": { + "message": "Please select options from the enum fields", + "requestedSchema": { + "type": "object", + "properties": { + "untitledSingle": { + "type": "string", + "description": "Select one option", + "enum": ["option1", "option2", "option3"] + }, + "titledSingle": { + "type": "string", + "description": "Select one option with titles", + "oneOf": [ + { "const": "value1", "title": "First Option" }, + { "const": "value2", "title": "Second Option" }, + { "const": "value3", "title": "Third Option" } + ] + }, + "legacyEnum": { + "type": "string", + "description": "Select one option (legacy)", + "enum": ["opt1", "opt2", "opt3"], + "enumNames": ["Option One", "Option Two", "Option Three"] + }, + "untitledMulti": { + "type": "array", + "description": "Select multiple options", + "minItems": 1, + "maxItems": 3, + "items": { + "type": "string", + "enum": ["option1", "option2", "option3"] + } + }, + "titledMulti": { + "type": "array", + "description": "Select multiple options with titles", + "minItems": 1, + "maxItems": 3, + "items": { + "anyOf": [ + { "const": "value1", "title": "First Choice" }, + { "const": "value2", "title": "Second Choice" }, + { "const": "value3", "title": "Third Choice" } + ] + } + } + }, + "required": [] + } + } +} +``` + +**Returns**: Text content with the elicitation result + +```json +{ + "content": [ + { + "type": "text", + "text": "Elicitation completed: action=, content={...}" + } + ] +} +``` + +**Implementation Note**: This tool tests SEP-1330 support for enum schema improvements including: +- Untitled single-select enums (type: string with enum array) +- Titled single-select enums (using oneOf with const/title objects) +- Legacy titled enums (using deprecated enumNames array) +- Untitled multi-select enums (type: array with items.enum) +- Titled multi-select enums (using items.anyOf with const/title objects) + +If the client doesn't support elicitation (no `elicitation` capability), return an error. + +**Reference**: [SEP-1330](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330) + --- ## 3. Resources Requirements diff --git a/examples/servers/typescript/everything-server.ts b/examples/servers/typescript/everything-server.ts index 4507bca..be90caf 100644 --- a/examples/servers/typescript/everything-server.ts +++ b/examples/servers/typescript/everything-server.ts @@ -472,6 +472,105 @@ function createMcpServer() { } ); + // SEP-1330: Elicitation with enum schema improvements + mcpServer.registerTool( + 'test_elicitation_sep1330_enums', + { + description: + 'Tests elicitation with enum schema improvements per SEP-1330', + inputSchema: {} + }, + async () => { + try { + // Request user input with all 5 enum schema variants + const result = await mcpServer.server.request( + { + method: 'elicitation/create', + params: { + message: 'Please select options from the enum fields', + requestedSchema: { + type: 'object', + properties: { + // Untitled single-select enum (basic) + untitledSingle: { + type: 'string', + description: 'Select one option', + enum: ['option1', 'option2', 'option3'] + }, + // Titled single-select enum (using oneOf with const/title) + titledSingle: { + type: 'string', + description: 'Select one option with titles', + oneOf: [ + { const: 'value1', title: 'First Option' }, + { const: 'value2', title: 'Second Option' }, + { const: 'value3', title: 'Third Option' } + ] + }, + // Legacy titled enum (using enumNames - deprecated) + legacyEnum: { + type: 'string', + description: 'Select one option (legacy)', + enum: ['opt1', 'opt2', 'opt3'], + enumNames: ['Option One', 'Option Two', 'Option Three'] + }, + // Untitled multi-select enum + untitledMulti: { + type: 'array', + description: 'Select multiple options', + minItems: 1, + maxItems: 3, + items: { + type: 'string', + enum: ['option1', 'option2', 'option3'] + } + }, + // Titled multi-select enum (using anyOf with const/title) + titledMulti: { + type: 'array', + description: 'Select multiple options with titles', + minItems: 1, + maxItems: 3, + items: { + anyOf: [ + { const: 'value1', title: 'First Choice' }, + { const: 'value2', title: 'Second Choice' }, + { const: 'value3', title: 'Third Choice' } + ] + } + } + }, + required: [] + } + } + }, + z + .object({ method: z.literal('elicitation/create') }) + .passthrough() as any + ); + + const elicitResult = result as any; + return { + content: [ + { + type: 'text', + text: `Elicitation completed: action=${elicitResult.action}, content=${JSON.stringify(elicitResult.content || {})}` + } + ] + }; + } catch (error: any) { + return { + content: [ + { + type: 'text', + text: `Elicitation not supported or error: ${error.message}` + } + ] + }; + } + } + ); + // Dynamic tool (registered later via timer) // ===== RESOURCES ===== From 204160b572cd6e35e1b9179735ea9e81249c89fb Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Tue, 11 Nov 2025 16:39:28 +0000 Subject: [PATCH 3/4] Fix prettier formatting --- SERVER_REQUIREMENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SERVER_REQUIREMENTS.md b/SERVER_REQUIREMENTS.md index 91bc39d..9898a22 100644 --- a/SERVER_REQUIREMENTS.md +++ b/SERVER_REQUIREMENTS.md @@ -543,6 +543,7 @@ If no progress token provided, just execute with delays. ``` **Implementation Note**: This tool tests SEP-1330 support for enum schema improvements including: + - Untitled single-select enums (type: string with enum array) - Titled single-select enums (using oneOf with const/title objects) - Legacy titled enums (using deprecated enumNames array) From 35cdae799bac17f08f08145d674fd0ae612226d4 Mon Sep 17 00:00:00 2001 From: Paul Carleton Date: Tue, 11 Nov 2025 19:32:48 +0000 Subject: [PATCH 4/4] only test active tests (#24) * refactor maps to pull names from the test * bring names back * separate active from pending * only test active --- src/index.ts | 10 +- src/scenarios/client/auth/basic-dcr.ts | 2 +- .../client/auth/basic-metadata-var1.ts | 2 +- src/scenarios/index.ts | 110 +++++++++++------- src/scenarios/server/all-scenarios.test.ts | 4 +- 5 files changed, 80 insertions(+), 48 deletions(-) diff --git a/src/index.ts b/src/index.ts index d35c676..6585551 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,11 @@ import { printServerResults, printServerSummary } from './runner'; -import { listScenarios, listClientScenarios } from './scenarios'; +import { + listScenarios, + listClientScenarios, + listActiveClientScenarios +} from './scenarios'; import { ConformanceCheck } from './types'; import { ClientOptionsSchema, ServerOptionsSchema } from './schemas'; import packageJson from '../package.json'; @@ -84,8 +88,8 @@ program const { failed } = printServerResults(result.checks); process.exit(failed > 0 ? 1 : 0); } else { - // Run all scenarios - const scenarios = listClientScenarios(); + // Run all active scenarios + const scenarios = listActiveClientScenarios(); console.log( `Running ${scenarios.length} scenarios against ${validated.url}\n` ); diff --git a/src/scenarios/client/auth/basic-dcr.ts b/src/scenarios/client/auth/basic-dcr.ts index 12d35a2..77524cc 100644 --- a/src/scenarios/client/auth/basic-dcr.ts +++ b/src/scenarios/client/auth/basic-dcr.ts @@ -6,7 +6,7 @@ import { ServerLifecycle } from './helpers/serverLifecycle.js'; import { Request, Response } from 'express'; export class AuthBasicDCRScenario implements Scenario { - name = 'auth-basic-dcr'; + name = 'auth/basic-dcr'; description = 'Tests Basic OAuth flow with DCR, PRM at path-based location, OAuth metadata at root location, and no scopes required'; private authServer = new ServerLifecycle(() => this.authBaseUrl); diff --git a/src/scenarios/client/auth/basic-metadata-var1.ts b/src/scenarios/client/auth/basic-metadata-var1.ts index 3e8043f..e8ae638 100644 --- a/src/scenarios/client/auth/basic-metadata-var1.ts +++ b/src/scenarios/client/auth/basic-metadata-var1.ts @@ -6,7 +6,7 @@ import { ServerLifecycle } from './helpers/serverLifecycle.js'; export class AuthBasicMetadataVar1Scenario implements Scenario { // TODO: name should match what we put in the scenario map - name = 'auth-basic-metadata-var1'; + name = 'auth/basic-metadata-var1'; description = 'Tests Basic OAuth flow with DCR, PRM at root location, OAuth metadata at OpenID discovery path, and no scopes required'; private authServer = new ServerLifecycle(() => this.authBaseUrl); diff --git a/src/scenarios/index.ts b/src/scenarios/index.ts index 8f23eb1..13f4aa1 100644 --- a/src/scenarios/index.ts +++ b/src/scenarios/index.ts @@ -47,59 +47,83 @@ import { PromptsGetWithImageScenario } from './server/prompts.js'; -export const scenarios = new Map([ - ['initialize', new InitializeScenario()], - ['tools-call', new ToolsCallScenario()], - ['auth/basic-dcr', new AuthBasicDCRScenario()], - ['auth/basic-metadata-var1', new AuthBasicMetadataVar1Scenario()], - [ - 'elicitation-sep1034-client-defaults', - new ElicitationClientDefaultsScenario() - ] -]); - -export const clientScenarios = new Map([ +// Pending client scenarios (not yet fully tested/implemented) +const pendingClientScenariosList: ClientScenario[] = [ + // Elicitation scenarios (SEP-1330) + new ElicitationEnumsScenario() +]; + +// All client scenarios +const allClientScenariosList: ClientScenario[] = [ // Lifecycle scenarios - ['server-initialize', new ServerInitializeScenario()], + new ServerInitializeScenario(), // Utilities scenarios - ['logging-set-level', new LoggingSetLevelScenario()], - ['completion-complete', new CompletionCompleteScenario()], + new LoggingSetLevelScenario(), + new CompletionCompleteScenario(), // Tools scenarios - ['tools-list', new ToolsListScenario()], - ['tools-call-simple-text', new ToolsCallSimpleTextScenario()], - ['tools-call-image', new ToolsCallImageScenario()], - ['tools-call-audio', new ToolsCallAudioScenario()], - ['tools-call-embedded-resource', new ToolsCallEmbeddedResourceScenario()], - ['tools-call-mixed-content', new ToolsCallMultipleContentTypesScenario()], - ['tools-call-with-logging', new ToolsCallWithLoggingScenario()], - ['tools-call-error', new ToolsCallErrorScenario()], - ['tools-call-with-progress', new ToolsCallWithProgressScenario()], - ['tools-call-sampling', new ToolsCallSamplingScenario()], - ['tools-call-elicitation', new ToolsCallElicitationScenario()], + new ToolsListScenario(), + new ToolsCallSimpleTextScenario(), + new ToolsCallImageScenario(), + new ToolsCallAudioScenario(), + new ToolsCallEmbeddedResourceScenario(), + new ToolsCallMultipleContentTypesScenario(), + new ToolsCallWithLoggingScenario(), + new ToolsCallErrorScenario(), + new ToolsCallWithProgressScenario(), + new ToolsCallSamplingScenario(), + new ToolsCallElicitationScenario(), // Elicitation scenarios (SEP-1034) - ['elicitation-sep1034-defaults', new ElicitationDefaultsScenario()], + new ElicitationDefaultsScenario(), - // Elicitation scenarios (SEP-1330) - ['elicitation-sep1330-enums', new ElicitationEnumsScenario()], + // Elicitation scenarios (SEP-1330) - pending + ...pendingClientScenariosList, // Resources scenarios - ['resources-list', new ResourcesListScenario()], - ['resources-read-text', new ResourcesReadTextScenario()], - ['resources-read-binary', new ResourcesReadBinaryScenario()], - ['resources-templates-read', new ResourcesTemplateReadScenario()], - ['resources-subscribe', new ResourcesSubscribeScenario()], - ['resources-unsubscribe', new ResourcesUnsubscribeScenario()], + new ResourcesListScenario(), + new ResourcesReadTextScenario(), + new ResourcesReadBinaryScenario(), + new ResourcesTemplateReadScenario(), + new ResourcesSubscribeScenario(), + new ResourcesUnsubscribeScenario(), // Prompts scenarios - ['prompts-list', new PromptsListScenario()], - ['prompts-get-simple', new PromptsGetSimpleScenario()], - ['prompts-get-with-args', new PromptsGetWithArgsScenario()], - ['prompts-get-embedded-resource', new PromptsGetEmbeddedResourceScenario()], - ['prompts-get-with-image', new PromptsGetWithImageScenario()] -]); + new PromptsListScenario(), + new PromptsGetSimpleScenario(), + new PromptsGetWithArgsScenario(), + new PromptsGetEmbeddedResourceScenario(), + new PromptsGetWithImageScenario() +]; + +// Active client scenarios (excludes pending) +const activeClientScenariosList: ClientScenario[] = + allClientScenariosList.filter( + (scenario) => + !pendingClientScenariosList.some( + (pending) => pending.name === scenario.name + ) + ); + +// Client scenarios map - built from list +export const clientScenarios = new Map( + allClientScenariosList.map((scenario) => [scenario.name, scenario]) +); + +// Scenario scenarios +const scenariosList: Scenario[] = [ + new InitializeScenario(), + new ToolsCallScenario(), + new AuthBasicDCRScenario(), + new AuthBasicMetadataVar1Scenario(), + new ElicitationClientDefaultsScenario() +]; + +// Scenarios map - built from list +export const scenarios = new Map( + scenariosList.map((scenario) => [scenario.name, scenario]) +); export function registerScenario(name: string, scenario: Scenario): void { scenarios.set(name, scenario); @@ -120,3 +144,7 @@ export function listScenarios(): string[] { export function listClientScenarios(): string[] { return Array.from(clientScenarios.keys()); } + +export function listActiveClientScenarios(): string[] { + return activeClientScenariosList.map((scenario) => scenario.name); +} diff --git a/src/scenarios/server/all-scenarios.test.ts b/src/scenarios/server/all-scenarios.test.ts index 0ee5b7e..545bf4c 100644 --- a/src/scenarios/server/all-scenarios.test.ts +++ b/src/scenarios/server/all-scenarios.test.ts @@ -1,5 +1,5 @@ import { spawn, ChildProcess } from 'child_process'; -import { listClientScenarios, getClientScenario } from '../index.js'; +import { getClientScenario, listActiveClientScenarios } from '../index.js'; import path from 'path'; describe('Server Scenarios', () => { @@ -76,7 +76,7 @@ describe('Server Scenarios', () => { }); // Generate individual test for each scenario - const scenarios = listClientScenarios(); + const scenarios = listActiveClientScenarios(); for (const scenarioName of scenarios) { it(`${scenarioName}`, async () => {