Skip to content

Align x-mcp-header implementation with SEP-2243 spec clarifications#1619

Open
tarekgh wants to merge 2 commits into
modelcontextprotocol:mainfrom
tarekgh:sep-2243-spec-compliance
Open

Align x-mcp-header implementation with SEP-2243 spec clarifications#1619
tarekgh wants to merge 2 commits into
modelcontextprotocol:mainfrom
tarekgh:sep-2243-spec-compliance

Conversation

@tarekgh
Copy link
Copy Markdown
Contributor

@tarekgh tarekgh commented Jun 1, 2026

Summary

Implements the spec clarifications from modelcontextprotocol/modelcontextprotocol#2772 to ensure the SDK fully complies with SEP-2243.

Changes

RFC 9110 tchar validation for header names

  • Replace loose ASCII range check with strict RFC 9110 Section 5.6.2 tchar character set
  • Use SearchValues on .NET 8+ for SIMD-accelerated matching
  • Use bitmap lookup (two ulong values covering ASCII 0-127) on netstandard2.0
  • Share validation logic between McpHeaderAttribute and McpHeaderExtractor via internal FindFirstNonTchar method

Remove "number" from allowed x-mcp-header types

  • Only "string", "integer", and "boolean" are permitted per the updated spec
  • Client-side: McpHeaderExtractor.ValidateToolSchema rejects tools with type "number" on x-mcp-header properties
  • Server-side: IsPrimitiveHeaderType no longer accepts float, double, or decimal for [McpHeader]

Base64 sentinel collision check

  • McpHeaderEncoder.RequiresBase64Encoding now detects values matching the =?base64?...?= pattern and forces base64 encoding to prevent round-trip confusion
  • DecodeValue changed from case-insensitive to case-sensitive prefix matching per spec requirement that sentinel markers must appear exactly as shown (lowercase)

Nested property support

  • Client-side header extraction and validation now recursively traverse nested "properties" objects at any depth, per the spec allowance for x-mcp-header at any nesting depth
  • Server-side StreamableHttpHandler adds recursive ValidateCustomParamHeadersFromProperties for header/body comparison on nested properties

Tests

28 new tests added:

  • 14 tchar validation tests (McpHeaderAttributeTests)
  • 7 sentinel collision tests (McpHeaderEncoderTests)
  • 7 integration tests for number rejection, nested properties, and tchar enforcement (McpHeaderExtractorValidationTests, new file)

All existing tests pass across net8.0, net9.0, net10.0, and net472.

- Enforce RFC 9110 tchar validation for header names using SearchValues on
  .NET 8+ and bitmap lookup on netstandard2.0
- Remove 'number' from allowed x-mcp-header types (only string, integer,
  boolean are permitted); reject float/double/decimal in [McpHeader]
- Add base64 sentinel collision check in McpHeaderEncoder.RequiresBase64Encoding
  so literal values resembling =?base64?...?= are encoded to avoid confusion
- Fix DecodeValue to use case-sensitive prefix matching per spec requirement
  that sentinel markers must appear exactly as shown (lowercase)
- Support nested property traversal for x-mcp-header validation and extraction
  on both client and server sides
- Share tchar validation logic between McpHeaderAttribute and McpHeaderExtractor
  via internal FindFirstNonTchar method
- Add recursive ValidateCustomParamHeadersFromProperties in StreamableHttpHandler
  for server-side nested property header/body comparison
- Add 28 new tests covering tchar validation, sentinel collision encoding,
  number type rejection, nested property handling, and case-sensitive decoding
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the SDK’s SEP-2243 x-mcp-header handling to match the latest spec clarifications, tightening header-name validation, restricting allowed header types, hardening Base64 sentinel parsing, and extending validation/extraction to nested schema properties.

Changes:

  • Enforce RFC 9110 tchar validation for x-mcp-header / [McpHeader] names and share that logic across client/server code.
  • Disallow "number" / floating-point header types for x-mcp-header (client-side schema rejection; server-side attribute/type checks).
  • Make Base64 sentinel decoding case-sensitive and add “sentinel collision” encoding safeguards; add nested-schema traversal for x-mcp-header.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/ModelContextProtocol.Tests/Server/McpHeaderAttributeTests.cs Expands test coverage for RFC 9110 tchar header-name validation.
tests/ModelContextProtocol.Tests/Client/McpHeaderExtractorValidationTests.cs Adds integration tests for number rejection, nested properties, and tchar enforcement.
tests/ModelContextProtocol.Tests/Client/McpHeaderEncoderTests.cs Adds sentinel-collision tests and asserts case-sensitive sentinel decoding.
src/ModelContextProtocol.Core/Server/McpHeaderAttribute.cs Switches header-name validation to RFC 9110 tchar via shared helper.
src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs Tightens [McpHeader] supported types to integer/string/boolean (removes float/double/decimal).
src/ModelContextProtocol.Core/Protocol/McpHeaderEncoder.cs Enforces case-sensitive sentinel parsing and prevents sentinel-collision ambiguity.
src/ModelContextProtocol.Core/Client/McpHeaderExtractor.cs Adds nested property traversal and stricter schema validation for x-mcp-header.
src/ModelContextProtocol.Core/Client/McpClient.Methods.cs Updates inline comments around x-mcp-header validation behavior.
src/ModelContextProtocol.AspNetCore/StreamableHttpHandler.cs Adds recursive server-side validation for nested x-mcp-header properties.

Comment thread src/ModelContextProtocol.Core/Client/McpClient.Methods.cs Outdated
Comment thread src/ModelContextProtocol.Core/Client/McpHeaderExtractor.cs Outdated
Comment thread tests/ModelContextProtocol.Tests/Client/McpHeaderEncoderTests.cs
- Reject x-mcp-header parameters whose JSON Schema type is a disallowed
  or malformed value, including non-string/union types. A union array is
  accepted only when it contains at least one of string/integer/boolean
  (with optional "null"); an absent type is still treated as unknown and
  allowed to avoid excluding valid enum/const/$ref schemas.
- Reword the rejection message: "number" is a JSON primitive but is not a
  permitted header type, so report it as an unsupported type rather than
  non-primitive.
- Clarify the ListToolsAsync comment to note that the client validates
  x-mcp-header annotations on all transports, while only Streamable HTTP
  is required to by SEP-2243.
- Drop the unused parameter from EncodeValue_NonSentinelPattern_NotBase64Encoded.
- Add tests for nullable union, disallowed union, null-only union, and
  missing-type schemas.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants