Skip to content

Commit 3d7343a

Browse files
authored
Merge pull request #1 from modelcontextprotocol/pcarleton-runner1
Adjust test and allow running in interactive mode
2 parents f32b01c + b78f6a5 commit 3d7343a

File tree

2 files changed

+58
-22
lines changed

2 files changed

+58
-22
lines changed

src/checks.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,17 @@ export function createClientInitializationCheck(initializeRequest: any, expected
3131
};
3232
}
3333

34-
export function createServerInfoCheck(serverInfo: { name?: string; version?: string } | null): ConformanceCheck {
35-
const hasName = !!serverInfo?.name;
36-
const hasVersion = !!serverInfo?.version;
37-
const status: CheckStatus = hasName && hasVersion ? 'SUCCESS' : 'FAILURE';
38-
39-
const errors: string[] = [];
40-
if (!hasName) errors.push('Server name missing');
41-
if (!hasVersion) errors.push('Server version missing');
42-
34+
export function createServerInfoCheck(serverInfo: { name: string; version: string }): ConformanceCheck {
4335
return {
4436
id: 'server-info',
4537
name: 'ServerInfo',
4638
description: 'Test server info returned to client',
47-
status,
39+
status: 'INFO',
4840
timestamp: new Date().toISOString(),
4941
specReferences: [{ id: 'MCP-Lifecycle', url: 'https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle' }],
5042
details: {
51-
serverName: serverInfo?.name,
52-
serverVersion: serverInfo?.version,
53-
hasName,
54-
hasVersion
55-
},
56-
errorMessage: errors.length > 0 ? errors.join('; ') : undefined,
57-
logs: errors.length > 0 ? errors : undefined
43+
serverName: serverInfo.name,
44+
serverVersion: serverInfo.version
45+
}
5846
};
5947
}

src/runner/index.ts

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,41 @@ export async function runConformanceTest(
122122
}
123123
}
124124

125+
async function runInteractiveMode(scenarioName: string): Promise<void> {
126+
await ensureResultsDir();
127+
const resultDir = createResultDir(scenarioName);
128+
await fs.mkdir(resultDir, { recursive: true });
129+
130+
const scenario = getScenario(scenarioName);
131+
if (!scenario) {
132+
throw new Error(`Unknown scenario: ${scenarioName}`);
133+
}
134+
135+
console.log(`Starting scenario: ${scenarioName}`);
136+
const urls = await scenario.start();
137+
138+
console.log(`Server URL: ${urls.serverUrl}`);
139+
console.log('Press Ctrl+C to stop and save checks...');
140+
141+
const handleShutdown = async () => {
142+
console.log('\nShutting down...');
143+
144+
const checks = scenario.getChecks();
145+
await fs.writeFile(path.join(resultDir, 'checks.json'), JSON.stringify(checks, null, 2));
146+
147+
console.log(`\nChecks:\n${JSON.stringify(checks, null, 2)}`);
148+
console.log(`\nChecks saved to ${resultDir}/checks.json`);
149+
150+
await scenario.stop();
151+
process.exit(0);
152+
};
153+
154+
process.on('SIGINT', handleShutdown);
155+
process.on('SIGTERM', handleShutdown);
156+
157+
await new Promise(() => {});
158+
}
159+
125160
async function main(): Promise<void> {
126161
const args = process.argv.slice(2);
127162
let command: string | null = null;
@@ -137,21 +172,34 @@ async function main(): Promise<void> {
137172
}
138173
}
139174

140-
if (!command || !scenario) {
141-
console.error('Usage: runner --command "<command>" --scenario <scenario>');
142-
console.error('Example: runner --command "tsx examples/clients/typescript/test1.ts" --scenario initialize');
175+
if (!scenario) {
176+
console.error('Usage: runner --scenario <scenario> [--command "<command>"]');
177+
console.error('Example: runner --scenario initialize --command "tsx examples/clients/typescript/test1.ts"');
178+
console.error('Or run without --command for interactive mode');
143179
process.exit(1);
144180
}
145181

182+
if (!command) {
183+
try {
184+
await runInteractiveMode(scenario);
185+
} catch (error) {
186+
console.error('Interactive mode error:', error);
187+
process.exit(1);
188+
}
189+
return;
190+
}
191+
146192
try {
147193
const result = await runConformanceTest(command, scenario);
148194

195+
const denominator = result.checks.filter(c => c.status === 'SUCCESS' || c.status == 'FAILURE').length;
149196
const passed = result.checks.filter(c => c.status === 'SUCCESS').length;
150197
const failed = result.checks.filter(c => c.status === 'FAILURE').length;
151198

199+
console.log(`Checks:\n${JSON.stringify(result.checks, null, 2)}`);
200+
152201
console.log(`\nTest Results:`);
153-
console.log(`Passed: ${passed}/${result.checks.length}`);
154-
console.log(`Failed: ${failed}/${result.checks.length}`);
202+
console.log(`Passed: ${passed}/${denominator}, ${failed} failed`);
155203

156204
if (failed > 0) {
157205
console.log('\nFailed Checks:');

0 commit comments

Comments
 (0)