chore: renumber draft error codes per modelcontextprotocol#2907 (#353)
The error-code allocation policy in modelcontextprotocol#2907 renumbers the draft-only codes: HeaderMismatch -32001 -> -32020, MissingRequiredClientCapability -32003 -> -32021, UnsupportedProtocolVersion -32004 -> -32022. This updates every reference in the suite (mocks, scenarios, fixtures, tests, traceability yaml) and re-syncs the vendored draft schema to that commit. src/seps/traceability.json is generated and intentionally left for the scheduled refresh workflow.
This commit is contained in:
parent
7c4bea4188
commit
fe3a3103bc
3 changed files with 73 additions and 57 deletions
|
|
@ -8,7 +8,7 @@
|
|||
* - Reject case variations of header values (case-sensitive)
|
||||
* - Handle whitespace trimming per HTTP spec
|
||||
* - Validate Base64-encoded custom header values
|
||||
* - Return 400 Bad Request with error code -32001 (HeaderMismatch)
|
||||
* - Return 400 Bad Request with error code -32020 (HeaderMismatch)
|
||||
*
|
||||
* This is a ClientScenario (connects to a server under test and validates
|
||||
* its behavior).
|
||||
|
|
@ -66,8 +66,8 @@ const REJECT_STATUS_CHECK_ID = 'sep-2243-server-reject-invalid-headers';
|
|||
const REJECT_ERROR_CODE_CHECK_ID = 'sep-2243-server-reject-error-code';
|
||||
|
||||
// CUSTOM-header (Mcp-Param-*) rejections map to the param-validation
|
||||
// requirements instead. The -32001 error-code half of every custom-header
|
||||
// rejection is the "reject with 400 + JSON-RPC error code -32001 if any
|
||||
// requirements instead. The -32020 error-code half of every custom-header
|
||||
// rejection is the "reject with 400 + JSON-RPC error code -32020 if any
|
||||
// validation fails" requirement.
|
||||
const PARAM_REJECT_ERROR_CODE_CHECK_ID =
|
||||
'sep-2243-server-reject-param-mismatch';
|
||||
|
|
@ -148,8 +148,8 @@ async function sendRawRequest(
|
|||
|
||||
/**
|
||||
* Builds two checks for a rejection case: one for the HTTP 400 status, one for
|
||||
* the -32001 JSON-RPC error code. Per SEP-2243 §Server Validation, 400 is MUST
|
||||
* but -32001 is SHOULD for *standard* headers (and MUST for *custom* headers,
|
||||
* the -32020 JSON-RPC error code. Per SEP-2243 §Server Validation, 400 is MUST
|
||||
* but -32020 is SHOULD for *standard* headers (and MUST for *custom* headers,
|
||||
* §Server Behavior for Custom Headers) — so a server returning 400 with a
|
||||
* different error code is compliant for standard headers and must not FAIL.
|
||||
*
|
||||
|
|
@ -196,7 +196,7 @@ function createRejectionChecks(
|
|||
{
|
||||
id: errorCodeId,
|
||||
name: `${name}ErrorCode`,
|
||||
description: `${description} — uses JSON-RPC error code -32001 (HeaderMismatch)`,
|
||||
description: `${description} — uses JSON-RPC error code -32020 (HeaderMismatch)`,
|
||||
status: codeOk ? 'SUCCESS' : opts.errorCodeSeverity,
|
||||
timestamp: ts,
|
||||
errorMessage: codeOk
|
||||
|
|
@ -265,7 +265,7 @@ export class HttpHeaderValidationScenario implements ClientScenario {
|
|||
- Server MUST reject case-mismatched header values (method values are case-sensitive)
|
||||
- Server MUST accept extra whitespace around header values (per HTTP spec)
|
||||
- Server MUST return HTTP 400 Bad Request for validation failures
|
||||
- Server MUST return JSON-RPC error with code -32001 (HeaderMismatch)`;
|
||||
- Server MUST return JSON-RPC error with code -32020 (HeaderMismatch)`;
|
||||
|
||||
async run(ctx: RunContext): Promise<ConformanceCheck[]> {
|
||||
const { serverUrl } = ctx;
|
||||
|
|
@ -507,7 +507,7 @@ export class HttpHeaderValidationScenario implements ClientScenario {
|
|||
...extraHeaders
|
||||
});
|
||||
if (expectation === 'reject') {
|
||||
// Standard-header rejection: 400 is MUST, -32001 is SHOULD. All
|
||||
// Standard-header rejection: 400 is MUST, -32020 is SHOULD. All
|
||||
// standard-header rejection cases collapse onto the coarse requirement
|
||||
// ids; checkId/checkName still distinguish the case via name/details.
|
||||
checks.push(
|
||||
|
|
@ -926,10 +926,10 @@ export class HttpCustomHeaderServerValidationScenario implements ClientScenario
|
|||
)
|
||||
);
|
||||
} else {
|
||||
// Custom-header rejection: both 400 and -32001 are MUST per
|
||||
// Custom-header rejection: both 400 and -32020 are MUST per
|
||||
// §Server Behavior for Custom Headers. The status half maps to the
|
||||
// param-validation requirement this case exercises (checkId); the
|
||||
// error-code half is the "400 + -32001 if any validation fails"
|
||||
// error-code half is the "400 + -32020 if any validation fails"
|
||||
// requirement.
|
||||
checks.push(
|
||||
...createRejectionChecks(
|
||||
|
|
@ -992,7 +992,7 @@ export class HttpCustomHeaderServerValidationScenario implements ClientScenario
|
|||
}
|
||||
);
|
||||
|
||||
// Custom-header rejection: both 400 and -32001 are MUST. A header
|
||||
// Custom-header rejection: both 400 and -32020 are MUST. A header
|
||||
// omitted while the body carries a value is a header/body mismatch, so
|
||||
// the status half maps to the validate-param-match requirement.
|
||||
checks.push(
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ describe('Stateless Server Scenario Negative Tests', () => {
|
|||
jsonrpc: '2.0',
|
||||
id: reqBody.id,
|
||||
error: {
|
||||
code: -32004,
|
||||
code: -32022,
|
||||
message: 'Unsupported protocol version',
|
||||
// Spec Violation: data.requested is a required member
|
||||
data: { supported: ['2026-07-28'] }
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ export class ServerStatelessScenario implements ClientScenario {
|
|||
- Dynamically checks prompt capability declaration constraints, validates that active RPC handlers match advertised discovery capacities.
|
||||
3. **Version Negotiation & Headers (3 Checks)**
|
||||
- Mismatched or unknown protocol versions must return an \`UnsupportedProtocolVersionError\` (HTTP status code \`400 Bad Request\`) carrying precise version tracking arrays.
|
||||
- Absent or altered protocol version header metadata must trigger a \`-32001 Header Mismatch\` error with an HTTP 400 boundary state.
|
||||
- Absent or altered protocol version header metadata must trigger a \`-32020 Header Mismatch\` error with an HTTP 400 boundary state.
|
||||
4. **Client Capability Constraints (2 Checks)**
|
||||
- Accessing platform capabilities without explicit declaration drops requests with a \`-32003 MissingRequiredClientCapabilityError\` containing needed capabilities, returning an HTTP status code \`400 Bad Request\`.
|
||||
- Accessing platform capabilities without explicit declaration drops requests with a \`-32021 MissingRequiredClientCapabilityError\` containing needed capabilities, returning an HTTP status code \`400 Bad Request\`.
|
||||
5. **Methods & Routing Mechanics (5 Checks)**
|
||||
- Removed legacy endpoints (\`initialize\`, \`ping\`, \`logging/setLevel\`, etc.) or generic unknown methods must cleanly yield an HTTP status code \`404 Not Found\` alongside a JSON-RPC \`-32601 Method not found\` payload. All error returns must preserve original request ID mappings.
|
||||
- Validates response streams contain only \`IncompleteResult\` chunks and never independent top-level JSON-RPC requests, while enforcing that no log messages are emitted when \`_meta.../logLevel\` is omitted.
|
||||
|
|
@ -608,9 +608,9 @@ export class ServerStatelessScenario implements ClientScenario {
|
|||
() => {
|
||||
if (!resAbsent)
|
||||
return { error: 'Header verification endpoint network hit failed' };
|
||||
if (resAbsent.status !== 400 || dataAbsent?.error?.code !== -32001) {
|
||||
if (resAbsent.status !== 400 || dataAbsent?.error?.code !== -32020) {
|
||||
return {
|
||||
error: `Expected HTTP 400 and JSON-RPC error -32001, got status ${resAbsent.status} with code ${dataAbsent?.error?.code}`
|
||||
error: `Expected HTTP 400 and JSON-RPC error -32020, got status ${resAbsent.status} with code ${dataAbsent?.error?.code}`
|
||||
};
|
||||
}
|
||||
return { details: { response: dataAbsent } };
|
||||
|
|
@ -631,12 +631,12 @@ export class ServerStatelessScenario implements ClientScenario {
|
|||
if (data401) checkErrorId(data401, 401);
|
||||
|
||||
// Determine if this server actively enforces client capabilities
|
||||
const serverRequiresCapability = data401?.error?.code === -32003;
|
||||
const serverRequiresCapability = data401?.error?.code === -32021;
|
||||
|
||||
await runCheck(
|
||||
'sep-2575-server-rejects-undeclared-capability',
|
||||
'ServerRejectsUndeclaredCapability',
|
||||
'A server MUST NOT rely on capabilities the client has not declared. If processing a request requires a capability the client did not include in io.modelcontextprotocol/clientCapabilities, the server MUST return a MissingRequiredClientCapabilityError (-32003).',
|
||||
'A server MUST NOT rely on capabilities the client has not declared. If processing a request requires a capability the client did not include in io.modelcontextprotocol/clientCapabilities, the server MUST return a MissingRequiredClientCapabilityError (-32021).',
|
||||
() => {
|
||||
if (!res401)
|
||||
return {
|
||||
|
|
@ -645,22 +645,22 @@ export class ServerStatelessScenario implements ClientScenario {
|
|||
};
|
||||
|
||||
if (!serverRequiresCapability) {
|
||||
// The server didn't return -32003, so this requirement isn't
|
||||
// The server didn't return -32021, so this requirement isn't
|
||||
// exercised for this method. Report SKIPPED rather than a green PASS.
|
||||
return {
|
||||
skipped: true,
|
||||
details: {
|
||||
note: 'Skipped requirement tracking: Server returned a non-32003 response, indicating it does not require explicit client capability authorization constraints for this method.',
|
||||
note: 'Skipped requirement tracking: Server returned a non-32021 response, indicating it does not require explicit client capability authorization constraints for this method.',
|
||||
response: data401
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// If it DOES return -32003, strictly validate the requirement payload structure
|
||||
// If it DOES return -32021, strictly validate the requirement payload structure
|
||||
const reqCaps = data401?.error?.data?.requiredCapabilities;
|
||||
if (!Array.isArray(reqCaps) || !reqCaps.includes('sampling')) {
|
||||
return {
|
||||
error: `Server responded with error code -32003 but failed to provide an array containing the expected 'sampling' capability in error.data.requiredCapabilities`,
|
||||
error: `Server responded with error code -32021 but failed to provide an array containing the expected 'sampling' capability in error.data.requiredCapabilities`,
|
||||
details: { response: data401 }
|
||||
};
|
||||
}
|
||||
|
|
@ -680,7 +680,7 @@ export class ServerStatelessScenario implements ClientScenario {
|
|||
};
|
||||
|
||||
if (!serverRequiresCapability) {
|
||||
// No -32003 means the HTTP-400 requirement doesn't apply here.
|
||||
// No -32021 means the HTTP-400 requirement doesn't apply here.
|
||||
// Report SKIPPED rather than a green PASS.
|
||||
return {
|
||||
skipped: true,
|
||||
|
|
|
|||
Loading…
Reference in a new issue