Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 50 additions & 5 deletions docs/specification/draft/basic/transports/streamable-http.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ request to the MCP endpoint.
`Content-Type: text/event-stream` (an SSE response stream). The client
**MUST** support both.

<Note>

This revision of the core protocol defines no client-to-server
_notifications_ over Streamable HTTP. The only client-sent notification in
the core protocol, `notifications/cancelled`, is used only on the
[stdio](/specification/draft/basic/transports/stdio) transport; on
Streamable HTTP, closing the SSE response stream is itself the cancellation
signal and no `notifications/cancelled` message is expected (see
[Cancellation][cancellation]). The notification rules above describe the
transport mechanics for a notification POST; header requirements for
notification POSTs are not defined by this revision.

</Note>

## Receiving Messages

When the server returns an SSE response stream
Expand Down Expand Up @@ -260,11 +274,15 @@ the header per [Server Validation](#server-validation).

| Header Name | Source Field | Required For |
| ------------ | ----------------------------- | ------------------------------------------------------ |
| `Mcp-Method` | `method` | All requests and notifications |
| `Mcp-Method` | `method` | All requests |
| `Mcp-Name` | `params.name` or `params.uri` | `tools/call`, `resources/read`, `prompts/get` requests |

These headers are **REQUIRED** for compliance.

If the `Mcp-Name` source value cannot be safely represented as a plain ASCII
header value, clients **MUST** encode it using the Base64 sentinel format
described in [Value Encoding](#value-encoding).

**`tools/call` request:**

```http
Expand Down Expand Up @@ -354,8 +372,19 @@ the header name `Mcp-Param-{name}`.
string, boolean). Parameters with type `number` are not permitted.
Integer values **MUST** be within the safe range for JavaScript
(−2<sup>53</sup>+1 to 2<sup>53</sup>−1)
- **MAY** be applied to properties at any nesting depth within the
`inputSchema`, not only top-level properties
- **MUST** only be applied to properties that are _statically reachable_
from the schema root: reachable via a chain consisting solely of
`properties` keys. The chain **MUST NOT** pass through `items` (or any
other array keyword), composition keywords (`oneOf`, `anyOf`, `allOf`,
`not`), conditional keywords (`if`/`then`/`else`), or `$ref`. Nested
object properties are permitted as long as every step in the chain is a
`properties` key. An `x-mcp-header` annotation anywhere else makes the
annotation — and thus the tool definition — invalid.

Header extraction is defined as reading the instance value at the exact
property path of the annotated property (the chain of `properties` keys
leading to it). If no value is present at that path in the call arguments,
the header is omitted.

Clients using the Streamable HTTP transport **MUST** reject tool definitions
where any `x-mcp-header` value violates these constraints. Rejection means
Expand Down Expand Up @@ -445,10 +474,21 @@ representation with the following format:
Mcp-Param-{Name}: =?base64?{Base64EncodedValue}?=
```

The same encoding rule applies to the `Mcp-Name` header value. Tool and
prompt names are only **SHOULD**-constrained to header-safe characters, so a
name (or resource URI) outside the safe set is carried as:

```text
Mcp-Name: =?base64?{Base64EncodedValue}?=
```

The prefix `=?base64?` and suffix `?=` indicate that the value is
Base64-encoded. These markers are case-sensitive and **MUST** appear exactly
as shown (lowercase). Servers and intermediaries that need to inspect these
values **MUST** decode them accordingly.
values **MUST** decode them accordingly. In particular, servers **MUST**
decode an encoded `Mcp-Name` or `Mcp-Param-{Name}` value before comparing it
to the corresponding request body value during
[Server Validation](#server-validation).

To avoid ambiguity, clients **MUST** also Base64-encode any plain-ASCII
value that matches the sentinel pattern (i.e., starts with `=?base64?`
Expand Down Expand Up @@ -476,7 +516,9 @@ When constructing a `tools/call` request via HTTP transport, the client
2. Append the `Mcp-Method` header and, if applicable, `Mcp-Name` header to
the request.
3. Inspect the tool's `inputSchema` for properties marked with
`x-mcp-header` and extract the value for each parameter.
`x-mcp-header` and extract the value at each annotated property's exact
property path, omitting the header when no value is present (see
[Schema Extension](#schema-extension)).
4. Encode the values according to the [Value Encoding](#value-encoding)
rules.
5. Append a `Mcp-Param-{Name}: {Value}` header to the request.
Expand Down Expand Up @@ -575,6 +617,9 @@ Validation failure conditions include:
- A required standard header (`MCP-Protocol-Version`, `Mcp-Method`,
`Mcp-Name`) is missing.
- A header value does not match the corresponding request body value.
For headers that permit the Base64 sentinel encoding (`Mcp-Name` and
`Mcp-Param-{Name}`), servers **MUST** decode encoded values (see
[Value Encoding](#value-encoding)) before comparing them to the body value.
- A header value contains invalid characters.

<Note>
Expand Down
8 changes: 8 additions & 0 deletions docs/specification/draft/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ the previous revision, [2025-11-25](/specification/2025-11-25).
`structuredContent` to allow any JSON value. Add `$ref` resolution requirements and
composition-keyword resource bounds
([SEP-2106](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2106)).
11. Remove the `notifications/elicitation/complete` notification and the
`elicitationId` field of URL mode elicitation requests, both introduced in
`2025-11-25`. Under the
[Multi Round-Trip Requests](/specification/draft/basic/patterns/mrtr) pattern, the
client learns the outcome of an out-of-band interaction by retrying the original
request, so a server-initiated completion signal — and the identifier used to
correlate it — no longer fit the protocol. Servers needing to correlate an
elicitation across retries encode their own identifier in `requestState`.

## Deprecated

Expand Down
46 changes: 10 additions & 36 deletions docs/specification/draft/client/elicitation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,9 @@ URL mode elicitation enables servers to direct users to external URLs for out-of

URL mode elicitation requests **MUST** specify `mode: "url"`, a `message`, and include these additional parameters:

| Name | Type | Description |
| --------------- | ------ | ----------------------------------------- |
| `url` | string | The URL that the user should navigate to. |
| `elicitationId` | string | A unique identifier for the elicitation. |
| Name | Type | Description |
| ----- | ------ | ----------------------------------------- |
| `url` | string | The URL that the user should navigate to. |

The `url` parameter **MUST** contain a valid URL.

Expand All @@ -360,7 +359,6 @@ The same request could direct the user into an OAuth authorization flow, or a pa
"method": "elicitation/create",
"params": {
"mode": "url",
"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://mcp.example.com/ui/set_api_key",
"message": "Please provide your API key to continue."
}
Expand All @@ -377,35 +375,12 @@ The same request could direct the user into an OAuth authorization flow, or a pa

The response with `action: "accept"` indicates that the user has consented to the
interaction. It does not mean that the interaction is complete. The interaction occurs out
of band and the client is not aware of the outcome until and unless the server sends a notification indicating completion.

### Completion Notifications for URL Mode Elicitation

Servers **MAY** send a `notifications/elicitation/complete` notification when an
out-of-band interaction started by URL mode elicitation is completed. This allows clients to react programmatically if appropriate.

Servers sending notifications:

- **MUST** only send the notification to the client that initiated the elicitation request.
- **MUST** include the `elicitationId` established in the original `elicitation/create` request.

Clients:

- **MUST** ignore notifications referencing unknown or already-completed IDs.
- **MAY** wait for this notification to automatically retry requests that received an [`InputRequiredResult`](/specification/draft/basic/patterns/mrtr#inputrequiredresult) (echoing back its `requestState`), update the user interface, or otherwise continue an interaction.
- **SHOULD** still provide manual controls that let the user retry or cancel the original request (or otherwise resume interacting with the client) if the notification never arrives.

#### Example

```json
{
"jsonrpc": "2.0",
"method": "notifications/elicitation/complete",
"params": {
"elicitationId": "550e8400-e29b-41d4-a716-446655440000"
}
}
```
of band and the client is not directly informed of the outcome. When the client retries
the original request, the server determines from the echoed `requestState` (or its own
stored state) whether the out-of-band interaction has completed, and either returns the
final result or responds with another `InputRequiredResult`. Clients **SHOULD** provide
manual controls that let the user retry or cancel the original request (or otherwise
resume interacting with the client).

## Message Flow

Expand Down Expand Up @@ -451,7 +426,6 @@ sequenceDiagram

Note over User,UserAgent: User interaction
UserAgent-->>Server: Interaction complete
Server-->>Client: notifications/elicitation/complete (optional)

Note over Server: Continue processing with new information
Server-->Client: Result(id: 2, result)
Expand Down Expand Up @@ -685,7 +659,7 @@ To prevent this attack, the server **MUST** ensure that the user who started the
There are many ways to achieve this and the best way will depend on the specific implementation.

As a common, non-normative example, consider a case where the MCP server is accessible via the web and desires to perform a third-party authorization code flow.
To prevent the phishing attack, the server would create a URL mode elicitation to `https://mcp.example.com/connect?elicitationId=...` rather than the third-party authorization endpoint.
To prevent the phishing attack, the server would create a URL mode elicitation to `https://mcp.example.com/connect?...` rather than the third-party authorization endpoint.
This "connect URL" must ensure the user who opened the page is the same user for whom the elicitation was generated.
It would, for example, check that the user has a valid session cookie and that the session cookie is for the same user who was using the MCP client to generate the URL mode elicitation.
This could be done by comparing the authoritative subject (`sub` claim) from the MCP server's authorization server to the subject from the session cookie.
Expand Down
Loading
Loading