Skip to content

Commit 36f9b6a

Browse files
committed
server/http-standard-headers: severity fixes for whitespace + malformed-base64 tests
These five tests assert behavior the SEP-2243 text doesn't pin down. Kept because they're useful consistency signals across SDKs, but adjusted so they don't FAIL spec-compliant servers: - server-accepts-whitespace-header-value: this IS a MUST, but per RFC 9110 §5.5 (field parsing MUST exclude OWS), not SEP-2243. Kept as FAILURE, specReference now cites RFC 9110. - server-rejects-invalid-base64-padding / -chars: downgraded to WARNING. SEP-2243 says only 'MUST decode them accordingly' without picking RFC 4648 strict vs lenient. Node's Buffer.from() accepts unpadded/dirty input and decodes to a matching value (server accepts); .NET's Convert.FromBase64String throws (server rejects). Either is currently compliant. WARNING surfaces the inconsistency without false-redding lenient-decoder stacks. - server-literal-missing-base64-prefix / -suffix: unchanged. The wrapper syntax is '=?base64?{x}?=' complete; treating partial wrappers as literal is the natural reading. Plumbing: createRejectionCheck gains an optional failSeverity param; testBase64Case gains a 'reject-warn' mode. (This is also the hook for the larger 400-MUST / -32001-SHOULD split that still needs doing.)
1 parent cb482e8 commit 36f9b6a

1 file changed

Lines changed: 31 additions & 15 deletions

File tree

src/scenarios/server/http-standard-headers.ts

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ const SPEC_REFERENCE_CASE = {
3333
url: 'https://modelcontextprotocol.io/specification/draft/basic/transports#case-sensitivity'
3434
};
3535

36+
// OWS handling is an RFC 9110 §5.5 MUST ("a field parsing implementation MUST
37+
// exclude such whitespace prior to evaluating the field value"), not a
38+
// SEP-2243 requirement. Kept as a check because a server stack that fails it
39+
// has a real HTTP-layer bug that will manifest as header-mismatch rejections.
40+
const SPEC_REFERENCE_RFC9110_OWS = {
41+
id: 'RFC-9110-5.5-Field-Values',
42+
url: 'https://www.rfc-editor.org/rfc/rfc9110#section-5.5'
43+
};
44+
3645
const SPEC_REFERENCE_BASE64 = {
3746
id: 'SEP-2243-Value-Encoding',
3847
url: 'https://modelcontextprotocol.io/specification/draft/basic/transports#value-encoding'
@@ -110,7 +119,8 @@ function createRejectionCheck(
110119
description: string,
111120
response: { status: number; body: any },
112121
specRef: { id: string; url: string },
113-
details: Record<string, unknown>
122+
details: Record<string, unknown>,
123+
failSeverity: 'FAILURE' | 'WARNING' = 'FAILURE'
114124
): ConformanceCheck {
115125
const errors: string[] = [];
116126
if (response.status !== 400) {
@@ -127,7 +137,7 @@ function createRejectionCheck(
127137
id,
128138
name,
129139
description,
130-
status: errors.length > 0 ? 'FAILURE' : 'SUCCESS',
140+
status: errors.length > 0 ? failSeverity : 'SUCCESS',
131141
timestamp: new Date().toISOString(),
132142
errorMessage: errors.length > 0 ? errors.join('; ') : undefined,
133143
specReferences: [specRef],
@@ -314,7 +324,7 @@ export class HttpHeaderValidationScenario implements ClientScenario {
314324
'accept',
315325
'server-accepts-whitespace-header-value',
316326
'ServerAcceptsWhitespaceHeaderValue',
317-
'Server MUST accept extra whitespace in Mcp-Name value (trimmed per HTTP spec)',
327+
'Server MUST accept leading/trailing whitespace in Mcp-Name value (RFC 9110 §5.5: field parsing MUST exclude OWS before evaluating)',
318328
{
319329
jsonrpc: '2.0',
320330
id: 0,
@@ -325,7 +335,7 @@ export class HttpHeaderValidationScenario implements ClientScenario {
325335
'Mcp-Method': 'tools/call',
326336
'Mcp-Name': ` ${toolName} `
327337
},
328-
SPEC_REFERENCE,
338+
SPEC_REFERENCE_RFC9110_OWS,
329339
{
330340
headerValue: ` ${toolName} `,
331341
bodyValue: toolName,
@@ -638,16 +648,21 @@ export class HttpCustomHeaderServerValidationScenario implements ClientScenario
638648
defaultHeaders
639649
);
640650

641-
// Invalid Base64 padding - server MUST reject
651+
// Invalid Base64 padding — WARNING, not FAILURE. SEP-2243 says only
652+
// "MUST decode them accordingly" without specifying RFC 4648 strictness.
653+
// Lenient decoders (Node Buffer.from, browser atob) accept 'SGVsbG8' →
654+
// server matches → accepts. Strict decoders (.NET Convert.FromBase64String)
655+
// throw → server rejects. Either is currently spec-compliant, so this is
656+
// a consistency signal pending upstream clarification.
642657
await this.testBase64Case(
643658
checks,
644659
serverUrl,
645660
baseHeaders,
646661
nextId,
647-
'reject',
662+
'reject-warn',
648663
'server-rejects-invalid-base64-padding',
649664
'ServerRejectsInvalidBase64Padding',
650-
'Server MUST reject header with invalid Base64 padding',
665+
'Server should reject header with invalid Base64 padding (spec does not mandate strict decoding; lenient decoders may accept)',
651666
xMcpTool.name,
652667
paramName,
653668
'Hello',
@@ -657,16 +672,16 @@ export class HttpCustomHeaderServerValidationScenario implements ClientScenario
657672
defaultHeaders
658673
);
659674

660-
// Invalid Base64 characters - server MUST reject
675+
// Invalid Base64 characters — WARNING for the same reason as padding.
661676
await this.testBase64Case(
662677
checks,
663678
serverUrl,
664679
baseHeaders,
665680
nextId,
666-
'reject',
681+
'reject-warn',
667682
'server-rejects-invalid-base64-chars',
668683
'ServerRejectsInvalidBase64Chars',
669-
'Server MUST reject header with invalid Base64 characters',
684+
'Server should reject header with invalid Base64 characters (spec does not mandate strict decoding; lenient decoders may accept)',
670685
xMcpTool.name,
671686
paramName,
672687
'Hello',
@@ -747,7 +762,7 @@ export class HttpCustomHeaderServerValidationScenario implements ClientScenario
747762
serverUrl: string,
748763
baseHeaders: Record<string, string>,
749764
nextId: () => number,
750-
expectation: 'accept' | 'reject',
765+
expectation: 'accept' | 'reject' | 'reject-warn',
751766
checkId: string,
752767
checkName: string,
753768
description: string,
@@ -789,22 +804,23 @@ export class HttpCustomHeaderServerValidationScenario implements ClientScenario
789804
};
790805

791806
checks.push(
792-
expectation === 'reject'
793-
? createRejectionCheck(
807+
expectation === 'accept'
808+
? createAcceptanceCheck(
794809
checkId,
795810
checkName,
796811
description,
797812
response,
798813
SPEC_REFERENCE_BASE64,
799814
details
800815
)
801-
: createAcceptanceCheck(
816+
: createRejectionCheck(
802817
checkId,
803818
checkName,
804819
description,
805820
response,
806821
SPEC_REFERENCE_BASE64,
807-
details
822+
details,
823+
expectation === 'reject-warn' ? 'WARNING' : 'FAILURE'
808824
)
809825
);
810826
} catch (error) {

0 commit comments

Comments
 (0)