Summary
Setting Connection overrides → Protocol version to a specific value (e.g. 2026 RC (2026-07-28)) on a remote HTTPS server makes the client send two values in one MCP-Protocol-Version header, comma-joined:
MCP-Protocol-Version: 2025-11-25, 2026-07-28
Spec-compliant servers match that header exactly, so they reject it as an unsupported version and return 400. The hosted app surfaces this as a Request failed (502) toast from its own proxy, which makes it look like a server outage rather than a malformed request. The pin feature is therefore unusable against
any server that validates the header.
Steps to reproduce
- Add a remote HTTPS MCP server (OAuth auth) in the hosted app.
- ⋮ → Configure → Connection overrides → Protocol version →
2026 RC (2026-07-28) → Save Changes.
- Toggle the server on.
Expected: the client sends MCP-Protocol-Version: 2026-07-28 and connects.
Actual: Request failed (502). Server-side, the request arrives with MCP-Protocol-Version: '2025-11-25, 2026-07-28' and is rejected as an unsupported version. A second connect attempt never reaches the server at all (client-side short-circuit).
Setting Protocol version back to Client default connects instantly against the same server, same credentials — so this is specific to the pin path, not the server or the OAuth session.
Root cause
StreamableHTTPClientTransport._commonHeaders (@modelcontextprotocol/client, observed on 2.0.0-beta.4) sets the header lowercase and then spreads the caller's connection-level requestInit.headers verbatim:
new Headers({ "mcp-protocol-version": negotiated, ...requestInit.headers })
Headers treats field names case-insensitively but an object literal does not de-duplicate across different casings, so a canonical-cased MCP-Protocol-Version supplied by the caller appends instead of replacing. Reproducible standalone on Node 24:
new Headers({ "mcp-protocol-version": "2025-11-25", "MCP-Protocol-Version": "2026-07-28" }).get("mcp-protocol-version")
// => "2025-11-25, 2026-07-28"
The SDK's RESERVED_REQUEST_HEADER_NAMES guard covers per-request options.headers only — not connection-level requestInit.headers — so nothing upstream catches it.
The app used to have its own case-insensitive de-dup that prevented this; it was removed in #3317 (merged 2026-07-20) and not replaced. The per-server pin UI then landed in #3365 (merged 2026-07-22), which is when the combination became reachable.
Summary
Setting Connection overrides → Protocol version to a specific value (e.g.
2026 RC (2026-07-28)) on a remote HTTPS server makes the client send two values in oneMCP-Protocol-Versionheader, comma-joined:MCP-Protocol-Version: 2025-11-25, 2026-07-28
Spec-compliant servers match that header exactly, so they reject it as an unsupported version and return 400. The hosted app surfaces this as a
Request failed (502)toast from its own proxy, which makes it look like a server outage rather than a malformed request. The pin feature is therefore unusable againstany server that validates the header.
Steps to reproduce
2026 RC (2026-07-28)→ Save Changes.Expected: the client sends
MCP-Protocol-Version: 2026-07-28and connects.Actual:
Request failed (502). Server-side, the request arrives withMCP-Protocol-Version: '2025-11-25, 2026-07-28'and is rejected as an unsupported version. A second connect attempt never reaches the server at all (client-side short-circuit).Setting Protocol version back to Client default connects instantly against the same server, same credentials — so this is specific to the pin path, not the server or the OAuth session.
Root cause
StreamableHTTPClientTransport._commonHeaders(@modelcontextprotocol/client, observed on2.0.0-beta.4) sets the header lowercase and then spreads the caller's connection-levelrequestInit.headersverbatim:The SDK's RESERVED_REQUEST_HEADER_NAMES guard covers per-request options.headers only — not connection-level requestInit.headers — so nothing upstream catches it.
The app used to have its own case-insensitive de-dup that prevented this; it was removed in #3317 (merged 2026-07-20) and not replaced. The per-server pin UI then landed in #3365 (merged 2026-07-22), which is when the combination became reachable.