Skip to content

Mcp-Param-* projection is enforced regardless of negotiated protocol version, breaking 2025-11-25 clients since v1.12.0 #3311

Description

@iyoubee

Summary

Since the v1.12.0 rollout (2026-09-03), repo-scoped tools on the hosted remote server
(https://api.githubcopilot.com/mcp/...) reject calls from clients that negotiated 2025-11-25:

Negotiated protocol version: 2025-11-25

HTTP 400: header mismatch: missing Mcp-Param-owner header for parameter "owner" (code -32020)
HTTP 400: header mismatch: missing Mcp-Param-repo  header for parameter "repo"  (code -32020)

Mcp-Param-* projection is a 2026-07-28 feature. A client that negotiated 2025-11-25 sends owner
and repo in the tools/call params, as that version specifies, and has no mechanism to emit projected
headers. Enforcing the header check against such a session makes -32020 reachable on a protocol
version where it should not exist.

The underlying issue: the check is not version-scoped

Version negotiation during initialize exists so that one deployment can serve clients across protocol
versions, applying each version's semantics per session. A version-correct implementation would branch:

Negotiated version owner / repo read from Header validation
2026-07-28 projected Mcp-Param-* headers applies
2025-11-25 tools/call params must not apply

PR #3167 states the projection mechanism is
"not gated on protocol version negotiation" — consistent with validation living in the HTTP layer,
which sits outside per-session version state and so cannot see what was negotiated. The result is that
2026-07-28 semantics are applied to every session regardless of what the client agreed to.

This makes adopting any server ≥ v1.12.0 conditional on the client adopting 2026-07-28, which inverts
the compatibility guarantee that negotiation is meant to provide.

Impact

A previously working integration broke with no client-side change, in a minor release. Clients pinned to
2025-11-25 cannot call any repo-scoped tool, and there is no client-side remedy — emitting projected
headers is not something a 2025-11-25 client can do. Our only options are pinning a pre-v1.12.0
self-hosted build or writing a proxy that converts arguments into headers.

Steps to reproduce

  1. Connect to https://api.githubcopilot.com/mcp/x/all/readonly with a client supporting only MCP 2025-11-25.
  2. Confirm the negotiated version is 2025-11-25.
  3. Call any repo-scoped tool (e.g. get_file_contents) with owner and repo as ordinary arguments.
  4. Server returns HTTP 400 / -32020 header mismatch.

Expected

On a session negotiated at 2025-11-25, owner/repo are read from the tools/call arguments and the
call succeeds. Projected-header validation applies only to sessions negotiated at 2026-07-28 or later.

Actual

-32020 header mismatch on every repo-scoped tool call, irrespective of negotiated version.

Version information

  • Last working: v1.11.0 (2026-08-25) — no projection present; owner/repo accepted as arguments.
  • First broken: the v1.12.0 rollout (2026-09-03).
  • #3147 is CORS-only and not implicated;
    #3167 allowlists the projections in preflight
    and describes the ungated behaviour.
  • Comparable failure mode under the previous SDK:
    mark3labs/mcp-go#986.

Questions

  1. Can projected-header validation be gated on the negotiated protocol version, so 2025-11-25 sessions
    fall back to reading the parameters from tools/call?
  2. In the interim, is there a supported opt-out — a request header or endpoint path — to disable
    parameter projection for clients still on 2025-11-25?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions