diff --git a/docs/specification/draft/basic/patterns/cancellation.mdx b/docs/specification/draft/basic/patterns/cancellation.mdx index c1ee57cf2..a4ae7a6fe 100644 --- a/docs/specification/draft/basic/patterns/cancellation.mdx +++ b/docs/specification/draft/basic/patterns/cancellation.mdx @@ -5,12 +5,18 @@ title: Cancellation
The Model Context Protocol (MCP) supports optional cancellation of in-progress requests -through notification messages. Either side can send a cancellation notification to -indicate that a previously-issued request should be terminated. +through notification messages. Because all requests flow from client to server, +cancellation flows in one direction as well: the client sends a cancellation notification +to indicate that a request it previously issued should be terminated. + +There is one exception: on stdio, a server **MUST** send `notifications/cancelled` +referencing a `subscriptions/listen` request ID when it tears down that subscription +stream (see [Subscriptions][subscriptions]). Servers **MUST NOT** send +`notifications/cancelled` for any other purpose. ## Cancellation Flow -When a party wants to cancel an in-progress request, it sends a `notifications/cancelled` +When a client wants to cancel an in-progress request, it sends a `notifications/cancelled` notification containing: - The ID of the request to cancel @@ -40,18 +46,20 @@ How a client signals cancellation depends on the transport: ## Behavior Requirements 1. Cancellation notifications **MUST** only reference requests that: - - Were previously issued in the same direction + - Were previously issued by the client - Are believed to still be in-progress -1. Receivers of cancellation notifications **SHOULD**: +1. Server-sent cancellation notifications **MUST** only reference a + `subscriptions/listen` request, to terminate that subscription stream +1. Servers receiving cancellation notifications **SHOULD**: - Stop processing the cancelled request - Free associated resources - Not send a response for the cancelled request -1. Receivers **MAY** ignore cancellation notifications if: +1. Servers **MAY** ignore cancellation notifications if: - The referenced request is unknown - Processing has already completed - The request cannot be cancelled -1. The sender of the cancellation notification **SHOULD** ignore any response to the - request that arrives afterward +1. The client **SHOULD** ignore any response to the cancelled request that arrives + afterward ## Timing Considerations @@ -90,3 +98,5 @@ Invalid cancellation notifications **SHOULD** be ignored: This maintains the "fire and forget" nature of notifications while allowing for race conditions in asynchronous communication. + +[subscriptions]: /specification/draft/basic/patterns/subscriptions diff --git a/docs/specification/draft/basic/patterns/progress.mdx b/docs/specification/draft/basic/patterns/progress.mdx index e35f0b177..a52df885b 100644 --- a/docs/specification/draft/basic/patterns/progress.mdx +++ b/docs/specification/draft/basic/patterns/progress.mdx @@ -5,16 +5,17 @@ title: Progress
The Model Context Protocol (MCP) supports optional progress tracking for long-running -operations through notification messages. Either side can send progress notifications to -provide updates about operation status. +operations through notification messages. Because all requests flow from client to +server, progress flows in one direction as well: the server sends progress notifications +to report the status of requests the client has issued. ## Progress Flow -When a party wants to _receive_ progress updates for a request, it includes a +When a client wants to _receive_ progress updates for a request, it includes a `progressToken` in the request metadata. - Progress tokens **MUST** be a string or integer value -- Progress tokens can be chosen by the sender using any means, but **MUST** be unique +- Progress tokens can be chosen by the client using any means, but **MUST** be unique across all active requests. ```json @@ -30,7 +31,7 @@ When a party wants to _receive_ progress updates for a request, it includes a } ``` -The receiver **MAY** then send progress notifications containing: +The server **MAY** then send progress notifications containing: - The original progress token - The current progress value so far @@ -61,30 +62,30 @@ The receiver **MAY** then send progress notifications containing: - Were provided in an active request - Are associated with an in-progress operation -2. Receivers of progress requests **MAY**: +2. Servers receiving a request with a progress token **MAY**: - Choose not to send any progress notifications - Send notifications at whatever frequency they deem appropriate - Omit the total value if unknown ```mermaid sequenceDiagram - participant Sender - participant Receiver + participant Client + participant Server - Note over Sender,Receiver: Request with progress token - Sender->>Receiver: Method request with progressToken + Note over Client,Server: Request with progress token + Client->>Server: Method request with progressToken - Note over Sender,Receiver: Progress updates - Receiver-->>Sender: Progress notification (0.2/1.0) - Receiver-->>Sender: Progress notification (0.6/1.0) - Receiver-->>Sender: Progress notification (1.0/1.0) + Note over Client,Server: Progress updates + Server-->>Client: Progress notification (0.2/1.0) + Server-->>Client: Progress notification (0.6/1.0) + Server-->>Client: Progress notification (1.0/1.0) - Note over Sender,Receiver: Operation complete - Receiver->>Sender: Method response + Note over Client,Server: Operation complete + Server->>Client: Method response ``` ## Implementation Notes -- Senders and receivers **SHOULD** track active progress tokens +- Clients and servers **SHOULD** track active progress tokens - Both parties **SHOULD** implement rate limiting to prevent flooding - Progress notifications **MUST** stop after completion diff --git a/docs/specification/draft/basic/patterns/subscriptions.mdx b/docs/specification/draft/basic/patterns/subscriptions.mdx index e2a05bdce..1b97088dc 100644 --- a/docs/specification/draft/basic/patterns/subscriptions.mdx +++ b/docs/specification/draft/basic/patterns/subscriptions.mdx @@ -78,8 +78,12 @@ any unsupported types gracefully. ## Receiving Notifications All notifications delivered on the stream carry -`io.modelcontextprotocol/subscriptionId` in `_meta`, matching the ID of the -`subscriptions/listen` request that opened the stream. On stdio, where all messages +`io.modelcontextprotocol/subscriptionId` in `_meta`, identifying the +`subscriptions/listen` request that opened the stream. The value is always a string, +derived from the JSON-RPC ID of the `subscriptions/listen` request: the decimal string +representation of the ID if it is a number, or the ID verbatim if it is a string. In +the examples above, the request used `"id": 1`, so the acknowledgment and all +subsequent notifications carry the subscription ID `"1"`. On stdio, where all messages share a single channel, clients **MUST** use this field to correlate notifications with their originating subscription. @@ -102,8 +106,8 @@ A client **MAY** have multiple active subscriptions concurrently — for example one listening for tools-list changes and another for resource updates. Each subscription is identified by the JSON-RPC request ID of its `subscriptions/listen` request, and every notification on the stream carries -that ID in `io.modelcontextprotocol/subscriptionId` so clients can demultiplex -them. +that ID (converted to a string as described above) in +`io.modelcontextprotocol/subscriptionId` so clients can demultiplex them. ## Cancellation diff --git a/docs/specification/draft/schema.mdx b/docs/specification/draft/schema.mdx index d9ed12511..4d0891243 100644 --- a/docs/specification/draft/schema.mdx +++ b/docs/specification/draft/schema.mdx @@ -148,11 +148,23 @@ deprecated features registry.

+
+ +### `NotificationMetaObject` + +
interface NotificationMetaObject {
  "io.modelcontextprotocol/subscriptionId"?: string;
  [key: string]: unknown;
}

Extends MetaObject with additional notification-specific fields. All key naming rules from MetaObject apply.

Identifies the subscription stream a notification was delivered on. The +server MUST include this key on every notification delivered via a subscriptions/listen stream, so the +client can correlate the notification with the originating subscription.

The value is derived from the JSON-RPC ID of the subscriptions/listen +request that opened the stream: the decimal string representation of the +ID if it is a number, or the ID verbatim if it is a string.

+
+ +
### `NotificationParams` -
interface NotificationParams {
  _meta?: MetaObject;
}

Common params for any notification.

+
interface NotificationParams {
  _meta?: NotificationMetaObject;
}

Common params for any notification.

@@ -246,6 +258,27 @@ input_required - the request requires additional input and the result conta +
+ +### `HEADER_MISMATCH` + +
HEADER_MISMATCH: -32001

Error code returned when the HTTP headers of a request do not match the +corresponding values in the request body, or required headers are +missing or malformed.

+
+ + +
+ +### `HeaderMismatchError` + +
interface HeaderMismatchError {
  jsonrpc: "2.0";
  id?: RequestId;
  error: Error & { code: -32001 };
}

Returned when a server rejects a request because the values in the HTTP +headers do not match the corresponding values in the request body, or +because required headers are missing or malformed. For HTTP, the response +status code MUST be 400 Bad Request.

+
+ +
### `InternalError` @@ -604,7 +637,7 @@ without nested objects or arrays.

### `CancelledNotification` -
interface CancelledNotification {
  jsonrpc: "2.0";
  method: "notifications/cancelled";
  params: CancelledNotificationParams;
}

This notification can be sent by either side to indicate that it is cancelling a previously-issued request.

The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.

This notification indicates that the result will be unused, so any associated processing SHOULD cease.

Example: User-requested cancellation
{
"jsonrpc": "2.0",
"method": "notifications/cancelled",
"params": {
"requestId": "123",
"reason": "User requested cancellation"
}
}
+
interface CancelledNotification {
  jsonrpc: "2.0";
  method: "notifications/cancelled";
  params: CancelledNotificationParams;
}

This notification is sent by the client to indicate that it is cancelling a request it previously issued.

On stdio, the server also sends this notification, solely to terminate a subscriptions/listen stream: it references the ID of the subscriptions/listen request that opened the stream. Servers MUST NOT use this notification to cancel any other request.

The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.

This notification indicates that the result will be unused, so any associated processing SHOULD cease.

Example: User-requested cancellation
{
"jsonrpc": "2.0",
"method": "notifications/cancelled",
"params": {
"requestId": "123",
"reason": "User requested cancellation"
}
}
@@ -612,7 +645,7 @@ without nested objects or arrays.

### `CancelledNotificationParams` -
interface CancelledNotificationParams {
  _meta?: MetaObject;
  requestId?: RequestId;
  reason?: string;
}

Parameters for a notifications/cancelled notification.

Example: User-requested cancellation
{
"requestId": "123",
"reason": "User requested cancellation"
}

The ID of the request to cancel.

This MUST correspond to the ID of a request previously issued in the same direction.

An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.

+
interface CancelledNotificationParams {
  _meta?: NotificationMetaObject;
  requestId: RequestId;
  reason?: string;
}

Parameters for a notifications/cancelled notification.

Example: User-requested cancellation
{
"requestId": "123",
"reason": "User requested cancellation"
}

The ID of the request to cancel.

This MUST correspond to the ID of a request the client previously issued.

An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.

@@ -633,9 +666,9 @@ deprecated features registry.

interface LoggingMessageNotificationParams {
  _meta?: MetaObject;
  level: LoggingLevel;
  logger?: string;
  data: unknown;
}

Parameters for a notifications/message notification.

Deprecated as of protocol version 2026-07-28 (SEP-2577). +

interface LoggingMessageNotificationParams {
  _meta?: NotificationMetaObject;
  level: LoggingLevel;
  logger?: string;
  data: unknown;
}

Parameters for a notifications/message notification.

Deprecated as of protocol version 2026-07-28 (SEP-2577). Remains in the specification for at least twelve months; see the -deprecated features registry.

Example: Log database connection failed
{
"level": "error",
"logger": "database",
"data": {
"error": "Connection failed",
"details": {
"host": "localhost",
"port": 5432
}
}
}

The severity of this log message.

An optional name of the logger issuing this message.

The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here.

+deprecated features registry.

Example: Log database connection failed
{
"level": "error",
"logger": "database",
"data": {
"error": "Connection failed",
"details": {
"host": "localhost",
"port": 5432
}
}
}

The severity of this log message.

An optional name of the logger issuing this message.

The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here.

@@ -654,7 +687,7 @@ deprecated features registry.

interface ProgressNotificationParams {
  _meta?: MetaObject;
  progressToken: ProgressToken;
  progress: number;
  total?: number;
  message?: string;
}

Parameters for a notifications/progress notification.

Example: Progress message
{
"progressToken": "oivaizmir",
"progress": 50,
"total": 100,
"message": "Reticulating splines..."
}

The progress token which was given in the initial request, used to associate this notification with the request that is proceeding.

The progress thus far. This should increase every time progress is made, even if the total is unknown.

Total number of items to process (or total progress required), if known.

An optional message describing the current progress.

+
interface ProgressNotificationParams {
  _meta?: NotificationMetaObject;
  progressToken: ProgressToken;
  progress: number;
  total?: number;
  message?: string;
}

Parameters for a notifications/progress notification.

Example: Progress message
{
"progressToken": "oivaizmir",
"progress": 50,
"total": 100,
"message": "Reticulating splines..."
}

The progress token which was given in the initial request, used to associate this notification with the request that is proceeding.

The progress thus far. This should increase every time progress is made, even if the total is unknown.

Total number of items to process (or total progress required), if known.

An optional message describing the current progress.

@@ -665,7 +698,7 @@ deprecated features registry.

interface PromptListChangedNotification {
  jsonrpc: "2.0";
  method: "notifications/prompts/list_changed";
  params?: NotificationParams;
}

An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.

Example: Prompts list changed
{
"jsonrpc": "2.0",
"method": "notifications/prompts/list_changed"
}
+
interface PromptListChangedNotification {
  jsonrpc: "2.0";
  method: "notifications/prompts/list_changed";
  params?: NotificationParams;
}

An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This is only delivered on a subscriptions/listen stream when the client requested it via the promptsListChanged filter field.

Example: Prompts list changed
{
"jsonrpc": "2.0",
"method": "notifications/prompts/list_changed"
}
@@ -676,7 +709,7 @@ deprecated features registry.

interface ResourceListChangedNotification {
  jsonrpc: "2.0";
  method: "notifications/resources/list_changed";
  params?: NotificationParams;
}

An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.

Example: Resources list changed
{
"jsonrpc": "2.0",
"method": "notifications/resources/list_changed"
}
+
interface ResourceListChangedNotification {
  jsonrpc: "2.0";
  method: "notifications/resources/list_changed";
  params?: NotificationParams;
}

An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This is only delivered on a subscriptions/listen stream when the client requested it via the resourcesListChanged filter field.

Example: Resources list changed
{
"jsonrpc": "2.0",
"method": "notifications/resources/list_changed"
}
@@ -695,7 +728,7 @@ deprecated features registry.

interface ResourceUpdatedNotificationParams {
  _meta?: MetaObject;
  uri: string;
}

Parameters for a notifications/resources/updated notification.

Example: File resource updated
{
"uri": "file:///project/src/main.rs"
}

The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.

+
interface ResourceUpdatedNotificationParams {
  _meta?: NotificationMetaObject;
  uri: string;
}

Parameters for a notifications/resources/updated notification.

Example: File resource updated
{
"uri": "file:///project/src/main.rs"
}

The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.

@@ -716,7 +749,7 @@ types it agreed to honor.

interface SubscriptionsAcknowledgedNotificationParams {
  _meta?: MetaObject;
  notifications: SubscriptionFilter;
}

Parameters for a notifications/subscriptions/acknowledged notification.

The subset of requested notification types the server agreed to honor. +

interface SubscriptionsAcknowledgedNotificationParams {
  _meta?: NotificationMetaObject;
  notifications: SubscriptionFilter;
}

Parameters for a notifications/subscriptions/acknowledged notification.

The subset of requested notification types the server agreed to honor. Only includes notification types the server actually supports; if the client requested an unsupported type (e.g., promptsListChanged when the server has no prompts), it is omitted from this set.

@@ -730,7 +763,7 @@ the server has no prompts), it is omitted from this set.

### `ToolListChangedNotification` -
interface ToolListChangedNotification {
  jsonrpc: "2.0";
  method: "notifications/tools/list_changed";
  params?: NotificationParams;
}

An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.

Example: Tools list changed
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed"
}
+
interface ToolListChangedNotification {
  jsonrpc: "2.0";
  method: "notifications/tools/list_changed";
  params?: NotificationParams;
}

An optional notification from the server to the client, informing it that the list of tools it offers has changed. This is only delivered on a subscriptions/listen stream when the client requested it via the toolsListChanged filter field.

Example: Tools list changed
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed"
}
@@ -749,7 +782,7 @@ the server has no prompts), it is omitted from this set.

### `ElicitationCompleteNotificationParams` -
interface ElicitationCompleteNotificationParams {
  _meta?: MetaObject;
  elicitationId: string;
}

Parameters for a notifications/elicitation/complete notification.

The ID of the elicitation that completed.

+
interface ElicitationCompleteNotificationParams {
  _meta?: NotificationMetaObject;
  elicitationId: string;
}

Parameters for a notifications/elicitation/complete notification.

The ID of the elicitation that completed.

@@ -865,10 +898,12 @@ If present, there may be more results available.

Indicates the intended scope of the cached response, analogous to HTTP Cache-Control: public vs Cache-Control: private.

  • "public": Any client or intermediary (e.g., shared gateway, proxy) -MAY cache the response and serve it to any user.
  • "private": Only the requesting user's client MAY cache the response. -Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached -copy to a different user.
+milliseconds after receiving the response.

Indicates the intended scope of the cached response, analogous to HTTP Cache-Control: public vs Cache-Control: private.

  • "public": The response does not contain user-specific data. Any +client or intermediary (e.g., shared gateway, caching proxy) MAY cache +the response and serve it across authorization contexts.
  • "private": The response MAY be cached and reused only within the +same authorization context. Caches MUST NOT be shared across +authorization contexts (e.g., a different access token requires a +different cache).
@@ -925,10 +960,12 @@ If present, there may be more results available.

Indicates the intended scope of the cached response, analogous to HTTP Cache-Control: public vs Cache-Control: private.

  • "public": Any client or intermediary (e.g., shared gateway, proxy) -MAY cache the response and serve it to any user.
  • "private": Only the requesting user's client MAY cache the response. -Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached -copy to a different user.
+milliseconds after receiving the response.

Indicates the intended scope of the cached response, analogous to HTTP Cache-Control: public vs Cache-Control: private.

  • "public": The response does not contain user-specific data. Any +client or intermediary (e.g., shared gateway, caching proxy) MAY cache +the response and serve it across authorization contexts.
  • "private": The response MAY be cached and reused only within the +same authorization context. Caches MUST NOT be shared across +authorization contexts (e.g., a different access token requires a +different cache).
@@ -981,10 +1018,12 @@ server implementing an earlier protocol version (which does not include re client MAY cache this response before re-fetching. Semantics are analogous to HTTP Cache-Control max-age.

  • If 0, The response SHOULD be considered immediately stale, The client MAY re-fetch every time the result is needed.
  • If positive, the client SHOULD consider the result fresh for this many -milliseconds after receiving the response.

Indicates the intended scope of the cached response, analogous to HTTP Cache-Control: public vs Cache-Control: private.

  • "public": Any client or intermediary (e.g., shared gateway, proxy) -MAY cache the response and serve it to any user.
  • "private": Only the requesting user's client MAY cache the response. -Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached -copy to a different user.
+milliseconds after receiving the response.

Indicates the intended scope of the cached response, analogous to HTTP Cache-Control: public vs Cache-Control: private.

  • "public": The response does not contain user-specific data. Any +client or intermediary (e.g., shared gateway, caching proxy) MAY cache +the response and serve it across authorization contexts.
  • "private": The response MAY be cached and reused only within the +same authorization context. Caches MUST NOT be shared across +authorization contexts (e.g., a different access token requires a +different cache).
@@ -1019,10 +1058,12 @@ If present, there may be more results available.

Indicates the intended scope of the cached response, analogous to HTTP Cache-Control: public vs Cache-Control: private.

  • "public": Any client or intermediary (e.g., shared gateway, proxy) -MAY cache the response and serve it to any user.
  • "private": Only the requesting user's client MAY cache the response. -Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached -copy to a different user.
+milliseconds after receiving the response.

Indicates the intended scope of the cached response, analogous to HTTP Cache-Control: public vs Cache-Control: private.

  • "public": The response does not contain user-specific data. Any +client or intermediary (e.g., shared gateway, caching proxy) MAY cache +the response and serve it across authorization contexts.
  • "private": The response MAY be cached and reused only within the +same authorization context. Caches MUST NOT be shared across +authorization contexts (e.g., a different access token requires a +different cache).
@@ -1044,13 +1085,13 @@ if present).