feat: support "draft" as a first-class spec version target (#255)
* feat: support "draft" as a first-class spec version target - Add LATEST_SPEC_VERSION and DATED_SPEC_VERSIONS constants so the next spec release is a one-line change in types.ts. - Accept "draft" as a valid protocolVersion in the initialize check and mock-server response. - --spec-version draft now selects latest-dated scenarios plus draft-tagged ones, so SEP authors can run the full suite against an SDK tracking the in-progress spec without retagging core scenarios. - Forward --spec-version to the client process via MCP_CONFORMANCE_SPEC_VERSION so SDK examples can pick the matching protocolVersion. Closes #253 * review: collapse SpecVersion to wire strings; dedup NEGOTIABLE_PROTOCOL_VERSIONS; split out 'extension' Addresses review feedback from @felixweinberger and @mikekistler: - SpecVersion is now always a wire protocolVersion string (DatedSpecVersion | typeof DRAFT_PROTOCOL_VERSION). The separate 'draft' tag literal is gone from the type system; 'draft' survives only as a CLI input alias in resolveSpecVersion. Removes the tag-vs-wire confusion and the specVersionToProtocolVersion mapping. - NEGOTIABLE_PROTOCOL_VERSIONS in types.ts is the single source for what the mock server accepts on initialize (was duplicated in checks/client.ts and scenarios/client/initialize.ts). - 'extension' moved out of SpecVersion into a separate ScenarioSpecTag type. --spec-version extension is no longer valid; extension scenarios remain reachable via --suite extensions. - Draft-tagged scenarios now use the DRAFT_PROTOCOL_VERSION constant so a draft revision bump is a one-line change in types.ts.
This commit is contained in:
parent
d944122003
commit
17f1f93cc0
1 changed files with 221 additions and 78 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import { spawn } from 'child_process';
|
||||
import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import { ConformanceCheck } from '../types';
|
||||
import { ConformanceCheck, SpecVersion } from '../types';
|
||||
import { getScenario } from '../scenarios';
|
||||
import { createResultDir, formatPrettyChecks } from './utils';
|
||||
|
||||
|
|
@ -17,7 +17,8 @@ async function executeClient(
|
|||
scenarioName: string,
|
||||
serverUrl: string,
|
||||
timeout: number = 30000,
|
||||
context?: Record<string, unknown>
|
||||
context?: Record<string, unknown>,
|
||||
specVersion?: SpecVersion
|
||||
): Promise<ClientExecutionResult> {
|
||||
const commandParts = command.split(' ');
|
||||
const executable = commandParts[0];
|
||||
|
|
@ -34,6 +35,9 @@ async function executeClient(
|
|||
// 3. Semantic separation: scenario identifies "which test", context provides "test data"
|
||||
const env = { ...process.env };
|
||||
env.MCP_CONFORMANCE_SCENARIO = scenarioName;
|
||||
if (specVersion) {
|
||||
env.MCP_CONFORMANCE_PROTOCOL_VERSION = specVersion;
|
||||
}
|
||||
if (context) {
|
||||
// Include scenario name in context for discriminated union parsing
|
||||
env.MCP_CONFORMANCE_CONTEXT = JSON.stringify({
|
||||
|
|
@ -92,7 +96,8 @@ export async function runConformanceTest(
|
|||
clientCommand: string,
|
||||
scenarioName: string,
|
||||
timeout: number = 30000,
|
||||
outputDir?: string
|
||||
outputDir?: string,
|
||||
specVersion?: SpecVersion
|
||||
): Promise<{
|
||||
checks: ConformanceCheck[];
|
||||
clientOutput: ClientExecutionResult;
|
||||
|
|
@ -123,7 +128,8 @@ export async function runConformanceTest(
|
|||
scenarioName,
|
||||
urls.serverUrl,
|
||||
timeout,
|
||||
urls.context
|
||||
urls.context,
|
||||
specVersion
|
||||
);
|
||||
|
||||
// Print stdout/stderr if client exited with nonzero code
|
||||
|
|
|
|||
Loading…
Reference in a new issue