Skip to content

http-custom-headers requires a SEP-2243/SEP-2549 interpretation that is not implied by either SEP #354

@guglielmo-san

Description

@guglielmo-san

Issue

The http-custom-headers scenario serves tools/list with "ttlMs": 0 (immediately stale per SEP-2549) and then asserts the very next tools/call carries Mcp-Param-* headers derived from the just-returned schema. SEP-2243 explicitly tells the client to omit Mcp-Param-* "if the cached schema is stale (e.g., its TTL has expired)", so a strict reading of the two SEPs together makes this scenario unpassable.

Spec text

SEP-2243 (docs/specification/draft/basic/transports.mdx, "Custom headers from tool parameters"):

If the client does not have the tool's inputSchema (e.g., tools/list has not yet been called) or the cached schema is stale (e.g., its TTL has expired), the client SHOULD send the request without custom Mcp-Param-* headers. If the server rejects the request because required custom headers are missing, the client SHOULD call tools/list to obtain the current inputSchema, then retry the original request with the appropriate headers.

SEP-2549 (docs/specification/draft/server/utilities/caching.mdx):

ttlMs value Client behavior
0 "The response SHOULD be considered immediately stale, The Client MAY re-fetch every time the result is needed."
missing "clients SHOULD assume a default ttlMs of 0 (immediately stale)"

Composing the two: a server that publishes tools/list with ttlMs: 0 is telling the client "my schema is stale the moment you receive it," and SEP-2243 then tells the client to omit Mcp-Param-* until either a fresh refetch arrives or the server rejects with -32001 HeaderMismatch and the client retries.

What the scenario does

@modelcontextprotocol/conformance@0.2.0-alpha.4, scenario http-custom-headers:

  1. Serves tools/list{ resultType:"complete", ttlMs:0, cacheScope:"private", tools:[…test_custom_headers…] }.
  2. Has the harness immediately call tools/call test_custom_headers with a fixed argument set seeded via configCtx.toolCalls.
  3. Asserts (via ClientSupportsCustomHeaders etc.) that the call carried Mcp-Param-Region, Mcp-Param-Verbose, …

Step 1 declares the schema immediately stale; step 3 requires headers derived from that same stale schema. No -32001 HeaderMismatch rejection path is exercised — the harness's handleToolsCall always returns success regardless of headers, so a SEP-2243-compliant "retry on -32001" loop never fires either.

(Note: there is a separate issue, #344, where the same scenario's test_custom_headers.priority and .float_val declare x-mcp-header on type:"number", which SEP-2243 forbids. A SEP-2243-conformant client correctly excludes the whole tool from tools/list, which produces the same observable failure for an additional reason. Even after #344 is fixed, the SEP-2243/SEP-2549 stale-schema interaction reported here remains and continues to fail the scenario for SDKs that take both SEPs strictly.)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions