MCP HTTP headers reference
Every HTTP header a remote MCP server and client exchange over Streamable HTTP, with direction, versions, example values, failure symptoms and the mcptest diagnostic that fires.
On this page
Streamable HTTP is the remote transport in every revision since 2025-03-26. Header names are case-insensitive. The examples below use the spelling in the current specification. For how versions differ overall, see MCP protocol versions explained.
Summary table
| Header | Direction | Versions | Required |
|---|---|---|---|
MCP-Protocol-Version | Client to server | 2025-06-18 and later | After initialize (2025); every POST (2026) |
Mcp-Session-Id | Both | 2025-03-26 to 2025-11-25 | When the server issued one |
Mcp-Method | Client to server | 2026-07-28 | Every POST |
Mcp-Name | Client to server | 2026-07-28 | tools/call, resources/read, prompts/get |
Accept | Client to server | All Streamable HTTP | Every POST and GET |
Content-Type | Both | All | Request bodies and responses with a body |
Last-Event-ID | Client to server | 2025-03-26 to 2025-11-25 | Only when resuming |
Retry-After | Server to client | Not MCP-specific | With 429 or 503 |
Authorization | Client to server | Servers using OAuth or tokens | Every request once authorized |
WWW-Authenticate | Server to client | Authorization spec | With 401, and 403 for scope |
Origin | Client to server (set by browsers) | All | Servers MUST validate it |
Access-Control-* | Server to client | Browser clients only | For cross-origin browser access |
MCP-Protocol-Version
- Direction: client to server.
- Versions: introduced in 2025-06-18. In 2025-06-18 and 2025-11-25 the client sends the negotiated version on every request after
initialize. In 2026-07-28 every POST carries it, and it MUST equalparams._meta["io.modelcontextprotocol/protocolVersion"]. - Example:
MCP-Protocol-Version: 2026-07-28 - When missing: a 2025 server with no other signal SHOULD assume
2025-03-26. A 2026 server that supports clients older than 2025-06-18 MAY assume the same; otherwise it MUST reject the request. - When wrong: an invalid or unsupported value gets
400 Bad Request. In 2026, a value that differs from_metagets400with-32020HeaderMismatch, and an unsupported version gets400with-32022and asupportedlist. - Browser note: the server must allow this header in
Access-Control-Allow-Headers, or the preflight fails before the request is sent. - mcptest: the SDK sets it from the negotiated version, or from the request's
_metaon 2026 requests. When aninitializeresponse does not expose it to the browser, thetransport.cors-expose-headers-missingevidence says so.
Mcp-Session-Id
- Direction: server to client on the
initializeresponse, then client to server on every later request, including GET and DELETE. - Versions: 2025-03-26 to 2025-11-25 (written
MCP-Session-Idin 2025-11-25). Removed in 2026-07-28; a 2026 server SHOULD ignore it. - Example:
Mcp-Session-Id: 1868a90c-6b4e-4b0e-9b2f-3c1d0e4c7a51 - Rules: visible ASCII only (0x21 to 0x7E), and SHOULD be globally unique and cryptographically secure. The client sends DELETE with the header to end the session; the server MAY answer
405. - When missing: a server that requires a session SHOULD answer
400. An expired or unknown ID MUST get404, and the client MUST start again withinitializeand no session ID. - mcptest: the TypeScript SDK reads the header from a successful
initializeresponse and attaches it afterwards. If a cross-origin browser cannot read it, the next request goes out without it.transport.cors-expose-headers-missingfires when that request is rejected with a session error.
HTTP/1.1 200 OK
Content-Type: application/json
Mcp-Session-Id: 1868a90c-6b4e-4b0e-9b2f-3c1d0e4c7a51
Access-Control-Expose-Headers: Mcp-Session-Id, MCP-Protocol-VersionMcp-Method
- Direction: client to server.
- Versions: 2026-07-28.
- Required: on every request, with the value of the JSON-RPC
method. - Example:
Mcp-Method: tools/call - Purpose: lets gateways, load balancers and WAFs route without parsing the body.
- When missing or different from the body:
400with-32020HeaderMismatch from a server that reads the body. An intermediary MUST return an HTTP error but need not send a JSON-RPC body. - mcptest: the SDK sets it on every request that carries a 2026
_metaenvelope (_applyBodyDerivedHeadersin@modelcontextprotocol/client). There is no dedicated diagnostic; the400body is shown in the log.
Mcp-Name
- Direction: client to server.
- Versions: 2026-07-28.
- Required: on
tools/callandprompts/get(value ofparams.name) and onresources/read(value ofparams.uri). - Example:
Mcp-Name: get_weather - Encoding: a value with non-ASCII characters, control characters, or leading or trailing whitespace MUST be sent as
=?base64?<Base64 of UTF-8>?=. Servers decode it before comparing it with the body. - When missing or different:
400with-32020HeaderMismatch. - Related:
Mcp-Param-<name>headers mirror tool arguments whose input schema declaresx-mcp-header. A client MUST omit the header when the value is null or absent.
Accept
- Direction: client to server.
- Versions: all Streamable HTTP revisions.
- POST: MUST list both
application/jsonandtext/event-stream, because the server may answer with either. - GET (2025 only): MUST list
text/event-stream. - Example:
Accept: application/json, text/event-stream - When missing or partial: servers built on the TypeScript SDK answer
406with "Not Acceptable: Client must accept both application/json and text/event-stream". - mcptest: the SDK always sends both types on POST. A
406from the target therefore points at an over-strict server check and firestransport.accept-header-406.
Content-Type
- Request: JSON-RPC bodies are sent as
Content-Type: application/json. The specification shows this in examples rather than as a normative rule. - Response to a POST that carried a request:
application/jsonfor a single JSON response, ortext/event-streamfor a stream. Clients MUST support both. - Response to GET (2025):
text/event-stream, or405. - Notifications and client responses:
202 Acceptedwith no body. - When wrong: a server that rejects
application/json, for example over a charset parameter or letter case, answers415. A successful response with another type is refused by the client ("Unexpected content type"). - mcptest:
transport.unsupported-media-type-415for a415, andtransport.sse-content-type-mismatchfor a2xxwith the wrong type.
Last-Event-ID
- Direction: client to server, on GET.
- Versions: 2025-03-26 to 2025-11-25. Removed in 2026-07-28; servers ignore it.
- Purpose: resumes an SSE stream after a disconnect. The server MAY tag events with
id. The client reconnects with the last ID it saw, and the server MUST NOT replay messages from a different stream. In 2025-11-25, resumption is always a GET. - Example:
Last-Event-ID: stream-3:42 - Related: in 2025-11-25 a server may close the stream after sending an SSE
retryfield, and the client MUST wait that many milliseconds before reconnecting. - Browser note: list it in
Access-Control-Allow-Headersif browsers resume streams.
Retry-After
- Direction: server to client.
- Versions: not defined by MCP. It is an HTTP header (RFC 9110) that RFC 6585 allows on
429 Too Many Requests. - Values: delay in seconds (
Retry-After: 30) or an HTTP date (Retry-After: Wed, 21 Oct 2026 07:28:00 GMT). - When missing: clients guess. mcptest waits one second.
- Browser note:
Retry-Afteris not a CORS-safelisted response header. A cross-origin browser can read it only when the server lists it inAccess-Control-Expose-Headers. - mcptest: a target
429firestransport.target-rate-limited-429. mcptest retries at most once per candidate endpoint, and only when the wait is 2 seconds or less (MAX_AUTOMATIC_RATE_LIMIT_WAIT_MSinsrc/utils/transportDetection.ts). Longer waits are shown as a countdown.
Authorization
- Direction: client to server.
- Format:
Authorization: Bearer <access token>on every HTTP request. Tokens MUST NOT be sent in the query string. - When missing or invalid:
401withWWW-Authenticate. - Browser note:
Authorizationis never CORS-safelisted, so it must appear inAccess-Control-Allow-Headers. - mcptest: when you connect through the optional CORS proxy, the target's
Authorizationvalue travels asX-MCP-Authorization. The proxy's own sign-in usesAuthorization(getRequestHeadersForCandidateinsrc/utils/transportDetection.ts). The proxy marks whether it or the target produced a response withX-MCP-Proxy-Response-Source.
WWW-Authenticate
- Direction: server to client.
- On
401: carriesresource_metadata, the URL of the RFC 9728 protected resource metadata, and SHOULD carryscope. If it is absent, clients fall back to/.well-known/oauth-protected-resource. - On
403:error="insufficient_scope"with the neededscopeasks the client to step up (RFC 6750 section 3.1). - Example:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp", scope="files:read"- Browser note: browsers hide this header from cross-origin scripts unless it appears in
Access-Control-Expose-Headers. A browser client then falls back to well-known discovery. - mcptest: challenges are recorded with credential-like values redacted and start the OAuth flow. See the OAuth 2.1 reference.
Origin
- Direction: client to server. Browsers set it and scripts cannot change it.
- Rule: servers MUST validate
Originon all incoming connections to prevent DNS rebinding. From 2025-11-25, a present but invalidOriginMUST get403 Forbidden. - Example:
Origin: https://mcptest.io - mcptest: there is no dedicated transport diagnostic. The connection error card classifies
401and403as authentication failures (src/utils/connectionDiagnostics.ts).
Access-Control-Allow-Origin
Sent on the preflight and the actual response. It must be the requesting origin (or * when no credentials are involved). Keep the list narrow; CORS is not a replacement for Origin validation or authorization.
Access-Control-Allow-Methods
POST for 2026-only servers. For 2025 servers, POST, GET, DELETE, covering the optional GET stream and session termination.
Access-Control-Allow-Headers
List every non-safelisted request header the client sends:
Access-Control-Allow-Headers: Content-Type, Accept, Authorization, MCP-Protocol-Version, Mcp-Session-Id, Mcp-Method, Mcp-Name, Last-Event-IDContent-Type: application/json is not a safelisted value, so every MCP POST triggers a preflight. Add any Mcp-Param-* names your tools declare.
Access-Control-Expose-Headers
Response headers a cross-origin script may read, beyond the safelisted ones:
Access-Control-Expose-Headers: Mcp-Session-Id, MCP-Protocol-Version, WWW-Authenticate, Retry-AfterWithout Mcp-Session-Id here, a 2025 stateful server appears to initialize and then rejects every request.
Access-Control-Max-Age
Optional. Caches the preflight result so that every MCP POST does not pay for an extra OPTIONS round trip.
Try it
Open Context7 in the playground, a public catalog server that negotiated 2026-07-28 at its last validation. Each request it sends carries MCP-Protocol-Version and Mcp-Method, and tool calls add Mcp-Name. If a header problem stops a connection, the diagnostic and the headers sent and seen appear on the connection error card.