Skip to content

Commit fffa835

Browse files
authored
Merge branch 'main' into fix_server_elicitation_conf
2 parents 6af0bcc + 82d83f2 commit fffa835

13 files changed

Lines changed: 370 additions & 335 deletions

File tree

.github/workflows/pr-publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ jobs:
2424
- name: Build
2525
run: npm run build
2626
- name: Publish
27-
run: npx pkg-pr-new publish
27+
run: npx pkg-pr-new publish --bin

lefthook.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# lefthook.yml
22
# Configuration reference: https://lefthook.dev/configuration/
33

4-
assert_lefthook_installed: true
4+
assert_lefthook_installed: false
55

66
output:
77
- meta # Print lefthook version

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@modelcontextprotocol/conformance",
3-
"version": "0.1.5",
3+
"version": "0.1.6",
44
"type": "module",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",
@@ -36,6 +36,7 @@
3636
"cors": "^2.8.5",
3737
"eslint": "^9.8.0",
3838
"eslint-config-prettier": "^10.1.8",
39+
"lefthook": "^2.0.2",
3940
"prettier": "3.6.2",
4041
"tsdown": "^0.15.12",
4142
"tsx": "^4.7.0",
@@ -47,7 +48,6 @@
4748
"@modelcontextprotocol/sdk": "^1.22.0",
4849
"commander": "^14.0.2",
4950
"express": "^5.1.0",
50-
"lefthook": "^2.0.2",
5151
"zod": "^3.25.76"
5252
}
5353
}

src/index.ts

Lines changed: 121 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import {
1313
import {
1414
listScenarios,
1515
listClientScenarios,
16-
listActiveClientScenarios
16+
listActiveClientScenarios,
17+
listAuthScenarios,
18+
listMetadataScenarios
1719
} from './scenarios';
1820
import { ConformanceCheck } from './types';
1921
import { ClientOptionsSchema, ServerOptionsSchema } from './schemas';
@@ -33,34 +35,141 @@ program
3335
'Run conformance tests against a client implementation or start interactive mode'
3436
)
3537
.option('--command <command>', 'Command to run the client')
36-
.requiredOption('--scenario <scenario>', 'Scenario to test')
38+
.option('--scenario <scenario>', 'Scenario to test')
39+
.option('--suite <suite>', 'Run a suite of tests in parallel (e.g., "auth")')
3740
.option('--timeout <ms>', 'Timeout in milliseconds', '30000')
3841
.option('--verbose', 'Show verbose output')
3942
.action(async (options) => {
4043
try {
41-
// Validate options with Zod
44+
const timeout = parseInt(options.timeout, 10);
45+
const verbose = options.verbose ?? false;
46+
47+
// Handle suite mode
48+
if (options.suite) {
49+
if (!options.command) {
50+
console.error('--command is required when using --suite');
51+
process.exit(1);
52+
}
53+
54+
const suites: Record<string, () => string[]> = {
55+
auth: listAuthScenarios,
56+
metadata: listMetadataScenarios
57+
};
58+
59+
const suiteName = options.suite.toLowerCase();
60+
if (!suites[suiteName]) {
61+
console.error(`Unknown suite: ${suiteName}`);
62+
console.error(`Available suites: ${Object.keys(suites).join(', ')}`);
63+
process.exit(1);
64+
}
65+
66+
const scenarios = suites[suiteName]();
67+
console.log(
68+
`Running ${suiteName} suite (${scenarios.length} scenarios) in parallel...\n`
69+
);
70+
71+
const results = await Promise.all(
72+
scenarios.map(async (scenarioName) => {
73+
try {
74+
const result = await runConformanceTest(
75+
options.command,
76+
scenarioName,
77+
timeout
78+
);
79+
return {
80+
scenario: scenarioName,
81+
checks: result.checks,
82+
error: null
83+
};
84+
} catch (error) {
85+
return {
86+
scenario: scenarioName,
87+
checks: [
88+
{
89+
id: scenarioName,
90+
name: scenarioName,
91+
description: 'Failed to run scenario',
92+
status: 'FAILURE' as const,
93+
timestamp: new Date().toISOString(),
94+
errorMessage:
95+
error instanceof Error ? error.message : String(error)
96+
}
97+
],
98+
error
99+
};
100+
}
101+
})
102+
);
103+
104+
console.log('\n=== SUITE SUMMARY ===\n');
105+
106+
let totalPassed = 0;
107+
let totalFailed = 0;
108+
let totalWarnings = 0;
109+
110+
for (const result of results) {
111+
const passed = result.checks.filter(
112+
(c) => c.status === 'SUCCESS'
113+
).length;
114+
const failed = result.checks.filter(
115+
(c) => c.status === 'FAILURE'
116+
).length;
117+
const warnings = result.checks.filter(
118+
(c) => c.status === 'WARNING'
119+
).length;
120+
121+
totalPassed += passed;
122+
totalFailed += failed;
123+
totalWarnings += warnings;
124+
125+
const status = failed === 0 ? '✓' : '✗';
126+
console.log(
127+
`${status} ${result.scenario}: ${passed} passed, ${failed} failed`
128+
);
129+
130+
if (verbose && failed > 0) {
131+
result.checks
132+
.filter((c) => c.status === 'FAILURE')
133+
.forEach((c) => {
134+
console.log(
135+
` - ${c.name}: ${c.errorMessage || c.description}`
136+
);
137+
});
138+
}
139+
}
140+
141+
console.log(
142+
`\nTotal: ${totalPassed} passed, ${totalFailed} failed, ${totalWarnings} warnings`
143+
);
144+
process.exit(totalFailed > 0 ? 1 : 0);
145+
}
146+
147+
// Require either --scenario or --suite
148+
if (!options.scenario) {
149+
console.error('Either --scenario or --suite is required');
150+
console.error('\nAvailable client scenarios:');
151+
listScenarios().forEach((s) => console.error(` - ${s}`));
152+
console.error('\nAvailable suites: auth, metadata');
153+
process.exit(1);
154+
}
155+
156+
// Validate options with Zod for single scenario mode
42157
const validated = ClientOptionsSchema.parse(options);
43158

44159
// If no command provided, run in interactive mode
45160
if (!validated.command) {
46-
await runInteractiveMode(
47-
validated.scenario,
48-
validated.verbose ?? false
49-
);
161+
await runInteractiveMode(validated.scenario, verbose);
50162
process.exit(0);
51163
}
52164

53165
// Otherwise run conformance test
54166
const result = await runConformanceTest(
55167
validated.command,
56168
validated.scenario,
57-
validated.timeout ?? 30000
169+
timeout
58170
);
59171

60-
const { failed } = printClientResults(
61-
result.checks,
62-
validated.verbose ?? false
63-
);
172+
const { failed } = printClientResults(result.checks, verbose);
64173
process.exit(failed > 0 ? 1 : 0);
65174
} catch (error) {
66175
if (error instanceof ZodError) {

src/scenarios/client/auth/basic-dcr.ts

Lines changed: 0 additions & 93 deletions
This file was deleted.

0 commit comments

Comments
 (0)