diff --git a/docs/specification/draft/basic/patterns/cancellation.mdx b/docs/specification/draft/basic/patterns/cancellation.mdx
index c1ee57cf2..249404d30 100644
--- a/docs/specification/draft/basic/patterns/cancellation.mdx
+++ b/docs/specification/draft/basic/patterns/cancellation.mdx
@@ -37,6 +37,27 @@ How a client signals cancellation depends on the transport:
- **stdio**: There is no per-request stream to close. The client **MUST** send a
`notifications/cancelled` notification referencing the request ID.
+## Timeouts
+
+Implementations **SHOULD** establish timeouts for all sent requests, to prevent hung
+connections and resource exhaustion. When the request has not received a success or error
+response within the timeout period, the sender **SHOULD** cancel the request and stop
+waiting for a response. As described in
+[Transport-Specific Cancellation](#transport-specific-cancellation), this means:
+
+- **Streamable HTTP**: closing the response stream for the request, which constitutes
+ cancellation.
+- **stdio**: sending a `notifications/cancelled` notification referencing the request ID.
+
+SDKs and other middleware **SHOULD** allow these timeouts to be configured on a
+per-request basis.
+
+Implementations **MAY** choose to reset the timeout clock when receiving a
+[progress notification](/specification/draft/basic/patterns/progress) corresponding to
+the request, as this implies that work is actually happening. However, implementations
+**SHOULD** always enforce a maximum timeout, regardless of progress notifications, to
+limit the impact of a misbehaving client or server.
+
## Behavior Requirements
1. Cancellation notifications **MUST** only reference requests that:
diff --git a/docs/specification/draft/changelog.mdx b/docs/specification/draft/changelog.mdx
index 477839d8a..aa2445d3c 100644
--- a/docs/specification/draft/changelog.mdx
+++ b/docs/specification/draft/changelog.mdx
@@ -21,7 +21,11 @@ the previous revision, [2025-11-25](/specification/2025-11-25).
6. Move experimental tasks out of the core protocol and into an official extension (`io.modelcontextprotocol/tasks`). The redesigned extension replaces the blocking `tasks/result` method with polling via `tasks/get` and a new `tasks/update` for client-to-server input, removes `tasks/list`, and allows servers to return task handles unsolicited without per-request opt-in ([SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2663)).
-7. Multi Round-Trip Requests (MRTR) pattern introduced which replaces the previous approach of sending server-initiated requests, such as `roots/list`, `sampling/createMessage`, or `elicitation/create`. Servers return `inputRequests`, a new resultType containing the additional information needed to process the request. Clients respond with `inputResponses` on the next request providing the requested information. ([SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)).
+7. Multi Round-Trip Requests (MRTR) pattern introduced which replaces the previous approach of sending server-initiated requests, such as `roots/list`, `sampling/createMessage`, or `elicitation/create`. Servers return an `InputRequiredResult` (`resultType: "input_required"`) whose `inputRequests` field carries the requests for the additional information needed to process the request. Clients respond with `inputResponses` on a retry of the original request providing the requested information. ([SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)).
+
+8. All results now carry a required `resultType` field: `"complete"` for ordinary results and `"input_required"` for [multi round-trip request](/specification/draft/basic/patterns/mrtr) interim results. Clients **MUST** treat results from earlier-protocol servers that omit the field as `"complete"` ([SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)).
+
+9. Remove SSE stream resumability and message redelivery (the `Last-Event-ID` header and SSE event IDs) from the Streamable HTTP transport. A broken response stream loses the in-flight request; clients **MUST** re-issue it as a new request with a new request ID ([SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575)).
## Minor changes
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 6100aabf4..3164f456d 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -53,10 +53,12 @@ Clients that support elicitation **MUST** declare the `elicitation` capability i
```json
{
- "capabilities": {
- "elicitation": {
- "form": {},
- "url": {}
+ "_meta": {
+ "io.modelcontextprotocol/clientCapabilities": {
+ "elicitation": {
+ "form": {},
+ "url": {}
+ }
}
}
}
@@ -66,8 +68,10 @@ For backwards compatibility, an empty capabilities object is equivalent to decla
```jsonc
{
- "capabilities": {
- "elicitation": {}, // Equivalent to { "form": {} }
+ "_meta": {
+ "io.modelcontextprotocol/clientCapabilities": {
+ "elicitation": {}, // Equivalent to { "form": {} }
+ },
},
}
```
@@ -126,7 +130,6 @@ The schema is restricted to these primitive types:
"description": "Description text",
"minLength": 3,
"maxLength": 50,
- "pattern": "^[A-Za-z]+$",
"format": "email",
"default": "user@example.com"
}
@@ -237,7 +240,7 @@ Note that complex nested structures, arrays of objects (beyond enums), and other
#### Example: Simple Text Request
-**Request:**
+**Input request (delivered inside [`InputRequiredResult.inputRequests`](/specification/draft/basic/patterns/mrtr#inputrequests)):**
```json
{
@@ -258,22 +261,20 @@ Note that complex nested structures, arrays of objects (beyond enums), and other
}
```
-**Response:**
+**Client result (returned inside `inputResponses` on the retried request):**
```json
{
- "result": {
- "action": "accept",
- "content": {
- "name": "octocat"
- }
+ "action": "accept",
+ "content": {
+ "name": "octocat"
}
}
```
#### Example: Structured Data Request
-**Request:**
+**Input request (delivered inside `InputRequiredResult.inputRequests`):**
```json
{
@@ -305,17 +306,15 @@ Note that complex nested structures, arrays of objects (beyond enums), and other
}
```
-**Response:**
+**Client result (returned inside `inputResponses` on the retried request):**
```json
{
- "result": {
- "action": "accept",
- "content": {
- "name": "Monalisa Octocat",
- "email": "octocat@github.com",
- "age": 30
- }
+ "action": "accept",
+ "content": {
+ "name": "Monalisa Octocat",
+ "email": "octocat@github.com",
+ "age": 30
}
}
```
@@ -354,7 +353,7 @@ The `url` parameter **MUST** contain a valid URL.
This example shows a URL mode elicitation request directing the user to a secure URL where they can provide sensitive information (an API key, for example).
The same request could direct the user into an OAuth authorization flow, or a payment flow. The only difference is the URL and the message.
-**Request:**
+**Input request (delivered inside `InputRequiredResult.inputRequests`):**
```json
{
@@ -368,13 +367,11 @@ The same request could direct the user into an OAuth authorization flow, or a pa
}
```
-**Response:**
+**Client result (returned inside `inputResponses` on the retried request):**
```json
{
- "result": {
- "action": "accept"
- }
+ "action": "accept"
}
```
@@ -395,7 +392,7 @@ Servers sending notifications:
Clients:
- **MUST** ignore notifications referencing unknown or already-completed IDs.
-- **MAY** wait for this notification to automatically retry requests that received a [URLElicitationRequiredError](#error-handling), update the user interface, or otherwise continue an interaction.
+- **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
@@ -465,7 +462,7 @@ sequenceDiagram
Elicitation responses use a three-action model to clearly distinguish between different user actions. These actions apply to both form and URL elicitation modes.
```json
-"result": {
+{
"action": "accept", // or "decline" or "cancel"
"content": {
"propertyName": "value",
diff --git a/docs/specification/draft/client/roots.mdx b/docs/specification/draft/client/roots.mdx
index 8adff3f5f..f3afe71ff 100644
--- a/docs/specification/draft/client/roots.mdx
+++ b/docs/specification/draft/client/roots.mdx
@@ -42,8 +42,10 @@ Clients that support roots **MUST** declare the `roots` capability in
```json
{
- "capabilities": {
- "roots": {}
+ "_meta": {
+ "io.modelcontextprotocol/clientCapabilities": {
+ "roots": {}
+ }
}
}
```
@@ -55,7 +57,7 @@ Clients that support roots **MUST** declare the `roots` capability in
To retrieve roots during the processing of a client request, servers send an `InputRequiredResult`
containing a `roots/list` request:
-**Request:**
+**Input request (delivered inside [`InputRequiredResult.inputRequests`](/specification/draft/basic/patterns/mrtr#inputrequests)):**
```json
{
@@ -63,18 +65,16 @@ containing a `roots/list` request:
}
```
-**Response:**
+**Client result (returned inside `inputResponses` on the retried request):**
```json
{
- "result": {
- "roots": [
- {
- "uri": "file:///home/user/projects/myproject",
- "name": "My Project"
- }
- ]
- }
+ "roots": [
+ {
+ "uri": "file:///home/user/projects/myproject",
+ "name": "My Project"
+ }
+ ]
}
```
diff --git a/docs/specification/draft/client/sampling.mdx b/docs/specification/draft/client/sampling.mdx
index bdb3e1ea8..e923b9c07 100644
--- a/docs/specification/draft/client/sampling.mdx
+++ b/docs/specification/draft/client/sampling.mdx
@@ -60,8 +60,10 @@ Clients that support sampling **MUST** declare the `sampling` capability in
```json
{
- "capabilities": {
- "sampling": {}
+ "_meta": {
+ "io.modelcontextprotocol/clientCapabilities": {
+ "sampling": {}
+ }
}
}
```
@@ -70,9 +72,11 @@ Clients that support sampling **MUST** declare the `sampling` capability in
```json
{
- "capabilities": {
- "sampling": {
- "tools": {}
+ "_meta": {
+ "io.modelcontextprotocol/clientCapabilities": {
+ "sampling": {
+ "tools": {}
+ }
}
}
}
@@ -82,9 +86,11 @@ Clients that support sampling **MUST** declare the `sampling` capability in
```json
{
- "capabilities": {
- "sampling": {
- "context": {}
+ "_meta": {
+ "io.modelcontextprotocol/clientCapabilities": {
+ "sampling": {
+ "context": {}
+ }
}
}
}
@@ -108,7 +114,7 @@ Clients that support sampling **MUST** declare the `sampling` capability in
To request a language model generation during the processing of a client request, servers send an `InputRequiredResult` containing a `sampling/createMessage` request:
-**Request:**
+**Input request (delivered inside [`InputRequiredResult.inputRequests`](/specification/draft/basic/patterns/mrtr#inputrequests)):**
```json
{
@@ -141,19 +147,17 @@ To request a language model generation during the processing of a client request
}
```
-**Response:**
+**Client result (returned inside `inputResponses` on the retried request):**
```json
{
- "result": {
- "role": "assistant",
- "content": {
- "type": "text",
- "text": "The capital of France is Paris."
- },
- "model": "claude-3-sonnet-20240307",
- "stopReason": "endTurn"
- }
+ "role": "assistant",
+ "content": {
+ "type": "text",
+ "text": "The capital of France is Paris."
+ },
+ "model": "claude-3-sonnet-20240307",
+ "stopReason": "endTurn"
}
```
@@ -204,7 +208,7 @@ sequenceDiagram
To request LLM generation with tool use capabilities, servers include `tools` and optionally `toolChoice` in the request:
-**Request (Server -> Client):**
+**Input request (Server -> Client, delivered inside `InputRequiredResult.inputRequests`):**
```json
{
@@ -243,33 +247,31 @@ To request LLM generation with tool use capabilities, servers include `tools` an
}
```
-**Response (Client -> Server):**
+**Client result (Client -> Server, returned inside `inputResponses` on the retried request):**
```json
{
- "result": {
- "role": "assistant",
- "content": [
- {
- "type": "tool_use",
- "id": "call_abc123",
- "name": "get_weather",
- "input": {
- "city": "Paris"
- }
- },
- {
- "type": "tool_use",
- "id": "call_def456",
- "name": "get_weather",
- "input": {
- "city": "London"
- }
+ "role": "assistant",
+ "content": [
+ {
+ "type": "tool_use",
+ "id": "call_abc123",
+ "name": "get_weather",
+ "input": {
+ "city": "Paris"
}
- ],
- "model": "claude-3-sonnet-20240307",
- "stopReason": "toolUse"
- }
+ },
+ {
+ "type": "tool_use",
+ "id": "call_def456",
+ "name": "get_weather",
+ "input": {
+ "city": "London"
+ }
+ }
+ ],
+ "model": "claude-3-sonnet-20240307",
+ "stopReason": "toolUse"
}
```
@@ -282,7 +284,7 @@ After receiving tool use requests from the LLM, the server typically:
3. Receives the LLM's response (which might contain new tool uses)
4. Repeats as many times as needed (server might cap the maximum number of iterations, and e.g. pass `toolChoice: {mode: "none"}` on the last iteration to force a final result)
-**Follow-up request (Server -> Client) with tool results:**
+**Follow-up input request (Server -> Client, delivered inside `InputRequiredResult.inputRequests`) with tool results:**
```json
{
@@ -357,19 +359,17 @@ After receiving tool use requests from the LLM, the server typically:
}
```
-**Final response (Client -> Server):**
+**Final client result (Client -> Server, returned inside `inputResponses` on the retried request):**
```json
{
- "result": {
- "role": "assistant",
- "content": {
- "type": "text",
- "text": "Based on the current weather data:\n\n- **Paris**: 18°C and partly cloudy - quite pleasant!\n- **London**: 15°C and rainy - you'll want an umbrella.\n\nParis has slightly warmer and drier conditions today."
- },
- "model": "claude-3-sonnet-20240307",
- "stopReason": "endTurn"
- }
+ "role": "assistant",
+ "content": {
+ "type": "text",
+ "text": "Based on the current weather data:\n\n- **Paris**: 18°C and partly cloudy - quite pleasant!\n- **London**: 15°C and rainy - you'll want an umbrella.\n\nParis has slightly warmer and drier conditions today."
+ },
+ "model": "claude-3-sonnet-20240307",
+ "stopReason": "endTurn"
}
```
diff --git a/docs/specification/draft/server/discover.mdx b/docs/specification/draft/server/discover.mdx
index a7f7a8cba..e6755442b 100644
--- a/docs/specification/draft/server/discover.mdx
+++ b/docs/specification/draft/server/discover.mdx
@@ -59,12 +59,15 @@ identity. This operation supports [caching](/specification/draft/server/utilitie
### Response Fields
-| Field | Type | Required | Description |
-| ------------------- | -------------------- | -------- | -------------------------------------------------------------------------------------------- |
-| `supportedVersions` | `string[]` | yes | Protocol versions the server supports. The client should choose one for subsequent requests. |
-| `capabilities` | `ServerCapabilities` | yes | Capabilities the server supports (tools, resources, prompts, etc.). |
-| `serverInfo` | `Implementation` | yes | Name and version of the server software. |
-| `instructions` | `string` | no | Natural-language guidance for LLMs on how to use this server effectively. |
+| Field | Type | Required | Description |
+| ------------------- | ----------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
+| `resultType` | `"complete"` | yes | Indicates an ordinary, complete result. |
+| `supportedVersions` | `string[]` | yes | Protocol versions the server supports. The client should choose one for subsequent requests. |
+| `capabilities` | `ServerCapabilities` | yes | Capabilities the server supports (tools, resources, prompts, etc.). |
+| `serverInfo` | `Implementation` | yes | Name and version of the server software. |
+| `instructions` | `string` | no | Natural-language guidance for LLMs on how to use this server effectively. |
+| `ttlMs` | `integer` | yes | How long the client may consider the result fresh, in milliseconds. See [Caching](/specification/draft/server/utilities/caching). |
+| `cacheScope` | `"public" \| "private"` | yes | Who may cache the response. See [Caching](/specification/draft/server/utilities/caching). |
## When to Call
diff --git a/docs/specification/draft/server/prompts.mdx b/docs/specification/draft/server/prompts.mdx
index 768346226..959cdeec3 100644
--- a/docs/specification/draft/server/prompts.mdx
+++ b/docs/specification/draft/server/prompts.mdx
@@ -9,6 +9,14 @@ templates to clients. Prompts allow servers to provide structured messages and
instructions for interacting with language models. Clients can discover available
prompts, retrieve their contents, and provide arguments to customize them.
+
+ For brevity, the request examples on this page omit the required `_meta`
+ request metadata (`io.modelcontextprotocol/protocolVersion`,
+ `io.modelcontextprotocol/clientInfo`, and
+ `io.modelcontextprotocol/clientCapabilities`). Every request **MUST** include
+ these fields; see [`_meta`](/specification/draft/basic/index#meta).
+
+
## User Interaction Model
Prompts are designed to be **user-controlled**, meaning they are exposed from servers to
diff --git a/docs/specification/draft/server/resources.mdx b/docs/specification/draft/server/resources.mdx
index a211876e9..ea45953d1 100644
--- a/docs/specification/draft/server/resources.mdx
+++ b/docs/specification/draft/server/resources.mdx
@@ -10,6 +10,14 @@ language models, such as files, database schemas, or application-specific inform
Each resource is uniquely identified by a
[URI](https://datatracker.ietf.org/doc/html/rfc3986).
+
+ For brevity, the request examples on this page omit the required `_meta`
+ request metadata (`io.modelcontextprotocol/protocolVersion`,
+ `io.modelcontextprotocol/clientInfo`, and
+ `io.modelcontextprotocol/clientCapabilities`). Every request **MUST** include
+ these fields; see [`_meta`](/specification/draft/basic/index#meta).
+
+
## User Interaction Model
Resources in MCP are designed to be **application-driven**, with host applications
diff --git a/docs/specification/draft/server/tools.mdx b/docs/specification/draft/server/tools.mdx
index a7b5a2579..9b9d1668d 100644
--- a/docs/specification/draft/server/tools.mdx
+++ b/docs/specification/draft/server/tools.mdx
@@ -9,6 +9,14 @@ language models. Tools enable models to interact with external systems, such as
databases, calling APIs, or performing computations. Each tool is uniquely identified by
a name and includes metadata describing its schema.
+
+ For brevity, the request examples on this page omit the required `_meta`
+ request metadata (`io.modelcontextprotocol/protocolVersion`,
+ `io.modelcontextprotocol/clientInfo`, and
+ `io.modelcontextprotocol/clientCapabilities`). Every request **MUST** include
+ these fields; see [`_meta`](/specification/draft/basic/index#meta).
+
+
## User Interaction Model
Tools in MCP are designed to be **model-controlled**, meaning that the language model can
@@ -541,6 +549,7 @@ Example valid response for this tool:
"jsonrpc": "2.0",
"id": 5,
"result": {
+ "resultType": "complete",
"content": [
{
"type": "text",
@@ -589,6 +598,7 @@ Example valid response for a tool with array output:
"jsonrpc": "2.0",
"id": 6,
"result": {
+ "resultType": "complete",
"content": [
{
"type": "text",
@@ -749,6 +759,7 @@ Tools use two error reporting mechanisms:
"jsonrpc": "2.0",
"id": 4,
"result": {
+ "resultType": "complete",
"content": [
{
"type": "text",
diff --git a/docs/specification/draft/server/utilities/caching.mdx b/docs/specification/draft/server/utilities/caching.mdx
index 07bcdff34..546aa51b7 100644
--- a/docs/specification/draft/server/utilities/caching.mdx
+++ b/docs/specification/draft/server/utilities/caching.mdx
@@ -10,7 +10,8 @@ mechanisms can coexist.
## Cacheable Results
-Servers MUST include caching hints on results returned by the following operations:
+Servers MUST include caching hints on results with `resultType: "complete"` returned by
+the following operations:
- `server/discover`
- `tools/list`
@@ -19,6 +20,22 @@ Servers MUST include caching hints on results returned by the following operatio
- `resources/templates/list`
- `resources/read`
+Interim results with `resultType: "input_required"` (see
+[multi round-trip requests](/specification/draft/basic/patterns/mrtr)) are not cacheable
+and carry no caching hints.
+
+## Cache Key
+
+A cached response is identified by the request method together with the request
+parameters that affect the result (for example, the `uri` for `resources/read`, or the
+`cursor` for paginated list requests). Clients **MUST NOT** serve a cached response for
+a request whose method or parameters differ from the request that produced it.
+
+Results produced by retrying a request through the
+[multi round-trip requests](/specification/draft/basic/patterns/mrtr) mechanism—that
+is, requests carrying `inputResponses` or `requestState`—**MUST NOT** be cached,
+as they depend on inputs that are not part of the cache key.
+
## Cacheable Model
Cacheable Results in MCP use two fields to provide caching hints to clients:
diff --git a/docs/specification/draft/server/utilities/completion.mdx b/docs/specification/draft/server/utilities/completion.mdx
index 0a4f691f8..067a97760 100644
--- a/docs/specification/draft/server/utilities/completion.mdx
+++ b/docs/specification/draft/server/utilities/completion.mdx
@@ -9,6 +9,14 @@ autocompletion suggestions for the arguments of prompts and resource templates.
users are filling in argument values for a specific prompt (identified by name) or
resource template (identified by URI), servers can provide contextual suggestions.
+
+ For brevity, the request examples on this page omit the required `_meta`
+ request metadata (`io.modelcontextprotocol/protocolVersion`,
+ `io.modelcontextprotocol/clientInfo`, and
+ `io.modelcontextprotocol/clientCapabilities`). Every request **MUST** include
+ these fields; see [`_meta`](/specification/draft/basic/index#meta).
+
+
## User Interaction Model
Completion in MCP is designed to support interactive user experiences similar to IDE code
@@ -46,7 +54,6 @@ what is being completed through a reference type:
{
"jsonrpc": "2.0",
"id": 1,
- "resultType": "complete",
"method": "completion/complete",
"params": {
"ref": {
@@ -68,6 +75,7 @@ what is being completed through a reference type:
"jsonrpc": "2.0",
"id": 1,
"result": {
+ "resultType": "complete",
"completion": {
"values": ["python", "pytorch", "pyside"],
"total": 10,
@@ -111,6 +119,7 @@ For prompts or URI templates with multiple arguments, clients should include pre
"jsonrpc": "2.0",
"id": 1,
"result": {
+ "resultType": "complete",
"completion": {
"values": ["flask"],
"total": 1,
diff --git a/docs/specification/draft/server/utilities/pagination.mdx b/docs/specification/draft/server/utilities/pagination.mdx
index 9cf537c74..a4f2fe0e5 100644
--- a/docs/specification/draft/server/utilities/pagination.mdx
+++ b/docs/specification/draft/server/utilities/pagination.mdx
@@ -12,6 +12,14 @@ Pagination is especially important when connecting to external services over the
internet, but also useful for local integrations to avoid performance issues with large
data sets.
+
+ For brevity, the request examples on this page omit the required `_meta`
+ request metadata (`io.modelcontextprotocol/protocolVersion`,
+ `io.modelcontextprotocol/clientInfo`, and
+ `io.modelcontextprotocol/clientCapabilities`). Every request **MUST** include
+ these fields; see [`_meta`](/specification/draft/basic/index#meta).
+
+
## Pagination Model
Pagination in MCP uses an opaque cursor-based approach, instead of numbered pages.
@@ -32,8 +40,11 @@ Pagination starts when the server sends a **response** that includes:
"jsonrpc": "2.0",
"id": "123",
"result": {
+ "resultType": "complete",
"resources": [...],
- "nextCursor": "eyJwYWdlIjogM30="
+ "nextCursor": "eyJwYWdlIjogM30=",
+ "ttlMs": 300000,
+ "cacheScope": "public"
}
}
```