Skip to content

SEP-2243: safe-integer-range MUST is untested, and SDKs disagree on what it requires #445

Description

@halter73

The requirement

Released 2026-07-28 server/tools.mdx, in the x-mcp-header constraint list:

Integer values MUST be within the safe range for integers represented using IEEE754 double-precision floating point numbers (−253+1 to 253−1)

Nothing in the harness covers it: no row in src/seps/sep-2243.yaml (the primitive-only text stops at "not permitted"), no check ID emitted, and grep -iE 'safe range|MAX_SAFE_INTEGER|9007199254740991|2\*\*53' over src/ returns zero matches. An SDK that mirrors 9007199254740993 into a header passes the suite today.

It binds at call time, on argument values

Settled by the discussion on PR #2772, which introduced the sentence (@mikekistler, merged 2026-05-29):

As discussed in the Transports WG, I think we aligned on something like: only integer arguments from -2^53 to 2^53 (inclusive) can be mirrored to a header. Any other numeric values produce an error.
@pja-ant

and the WG meeting notes @mikekistler pasted into the review:

Consensus: Custom numeric headers are strictly restricted to integers. Clients must reject tool inputs containing non-integer numbers in custom headers.

So this is a runtime constraint on arguments, not a schema-shape constraint.

The actual gap: SDKs disagree on the consequence

The spec states the constraint but never says what the client does when an argument violates it. Two SDKs read it two ways:

SDK Behavior on an out-of-range integer
csharp-sdk throws McpException — the call fails (McpHeaderExtractor.cs#L116-L121)
typescript-sdk mcpParamPrimitiveToString returns undefined, and buildMcpParamHeaders does continue — the header is silently omitted and the call proceeds (mcpParamHeaders.ts#L211, L311)

typescript-sdk is internally consistent — its server-side validateMcpParamHeaders skips the comparison for exactly the same values — so nothing errors end to end. But that silence is the failure mode the WG was trying to prevent: an intermediary routing on Mcp-Param-UserId simply doesn't receive the header, with no signal to anyone. Against the consensus quoted above, the C# behavior looks like the intended one.

Worth confirming which is normative before writing a check, since whichever we assert will make the other SDK fail.

Shape of the check

Belongs in the existing http-custom-headers positive scenario rather than a new one, per the fewer-scenarios-more-checks rule:

  • add an integer param carrying x-mcp-header to a tool the scenario already exercises
  • have the scenario ask the client to call it with an out-of-range value (e.g. 2**53)
  • emit sep-2243-x-mcp-header-integer-safe-range asserting the agreed behavior
  • add the matching sep-2243.yaml row and a negative fixture proving the check can fail

Note for whoever writes it: C# accepts 42.0 and 4.2e1 as canonical 42, and TS compares integer-typed declarations numerically, so the fixture should use a genuinely out-of-range value rather than a differently-spelled in-range one.

Aside: the released spec contradicts itself here

Same bound, two different justifications, both shipped in 2026-07-28:

  • server/tools.mdx — "safe range for integers represented using IEEE754 double-precision floating point numbers"
  • basic/transports/streamable-http.mdx (line 386) — "safe range for JavaScript"

@pja-ant flagged the JavaScript phrasing as imprecise ("Even in languages that have native integers, sometimes JSON parsing libraries will parse to double by default"), @mikekistler replied "Fair point. I will revise." — but the revision only landed in tools.mdx. Probably a one-line upstream fix.

Filed while verifying spec wording for #344 / #444; unrelated to those changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions