Three MCP message patterns
MCP supports three message patterns: (1) Request and Response — a client sends a request and the server responds with a result or error; (2) Multi Round-Trip Requests (MRTR) — a server requires additional client input (sampling, elicitation, or roots) to complete a request; (3) Subscribe and Notify — a client subscribes to a stream of notifications from the server sent as they occur.
Cancellation logging and UI expectations
Both parties SHOULD log cancellation reasons for debugging, and application UIs SHOULD indicate when cancellation is requested.
notifications/cancelled message shape
Cancellation in MCP uses a JSON-RPC notification with method `notifications/cancelled`. Its params contain `requestId` (the ID of the request to cancel) and an optional `reason` string that can be logged or displayed. Example: {"jsonrpc": "2.0", "method": "notifications/cancelled", "params": {"requestId": "123", "reason": "User requested cancellation"}}. Being a notification, it carries no `id` and expects no response.
Client SHOULD send cancellation notification
MCP supports optional cancellation of in-progress requests through notification messages. A client SHOULD send a cancellation notification to indicate that a request it previously issued should be terminated.
Request timeouts SHOULD be established and configurable
Implementations SHOULD establish timeouts for all sent requests to prevent hung connections and resource exhaustion. When no success or error response arrives within the timeout period, the sender SHOULD cancel the request and stop waiting: on Streamable HTTP by closing the response stream, on stdio by sending `notifications/cancelled` with the request ID. SDKs and middleware SHOULD allow these timeouts to be configured on a per-request basis.
Progress notifications MAY reset the timeout clock, but a maximum timeout SHOULD be enforced
Implementations MAY choose to reset the timeout clock when receiving a progress notification corresponding to a request, since it implies work is happening. However, implementations SHOULD always enforce a maximum timeout regardless of progress notifications, to limit the impact of a misbehaving client or server.
Cancellation behaviour requirements (MUST vs SHOULD vs MAY)
Cancellation notifications MUST only reference requests that were previously issued by the client and are believed to still be in progress. Servers receiving cancellation notifications SHOULD stop processing the cancelled request, free associated resources, and not send a response for it. Servers MAY ignore cancellation notifications when the referenced request is unknown, processing has already completed, or the request cannot be cancelled. The client SHOULD ignore any response to a cancelled request that arrives afterward.
Cancellation race conditions MUST be handled gracefully
Due to network latency, cancellation notifications may arrive after request processing has completed and potentially after a response has already been sent. Both parties MUST handle these race conditions gracefully; the server may have completed processing before the cancellation arrives, otherwise it stops processing.
Server MAY send notifications scoped to an in-flight request
While a client request is in flight, the server MAY send notifications scoped to that request, such as `notifications/progress` and `notifications/message` (logging), before delivering the final response.
progressToken in request _meta enables progress notifications
To receive progress updates for a request, the client includes a `progressToken` inside the request's `params._meta` object. Example request: {"jsonrpc":"2.0","id":1,"method":"some_method","params":{"_meta":{"progressToken":"abc123"}}}. Progress tracking is optional; the server MAY send progress notifications to report the status of requests the client has issued.
Progress notifications MUST reference only active tokens
Progress notifications MUST only reference tokens that were provided in an active request and that are associated with an in-progress operation. Progress notifications MUST stop after the operation completes.
Server discretion on progress notifications (MAY)
Servers receiving a request containing a progress token MAY choose not to send any progress notifications, MAY send notifications at whatever frequency they deem appropriate, and MAY omit the `total` value if it is unknown.
Progress implementation SHOULDs: token tracking and rate limiting
Clients and servers SHOULD track active progress tokens, and both parties SHOULD implement rate limiting on progress notifications to prevent flooding.
Progress sequence: notifications precede the method response
The typical progress flow is: the client sends a method request carrying a progressToken; the server sends zero or more progress notifications (for example 0.2/1.0, then 0.6/1.0, then 1.0/1.0); the server then sends the normal method response when the operation completes.
Progress token type and uniqueness MUST rules
Progress tokens MUST be a string or an integer value. They can be chosen by the client using any means, but MUST be unique across all active requests.
notifications/progress message shape
Progress notifications use method `notifications/progress` with params containing: `progressToken` (the original token), `progress` (current progress value), optional `total`, and optional `message`. Example: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":"abc123","progress":50,"total":100,"message":"Reticulating splines..."}}. As a notification it carries no `id`.
progress value MUST increase; progress/total MAY be floats
The `progress` value MUST increase with each progress notification, even if the total is unknown. Both `progress` and `total` MAY be floating point numbers. The `message` field SHOULD provide relevant human readable progress information.
Cancellation differs per binding: notifications/cancelled on stdio, stream close on HTTP
Each binding defines how a client abandons an in-flight request: on stdio the client sends a `notifications/cancelled` notification; on Streamable HTTP the client closes the request's response stream. The protocol-level cancellation rules are otherwise identical on all transports.
Unexpected server termination: restart and lost requests
If the stdio server process exits unexpectedly the client SHOULD restart it. Because the protocol is stateless, in-flight requests are simply lost and the client can retry them against the fresh process. Active subscriptions/listen streams must be re-established after restart.
stdio shutdown sequence
The client SHOULD initiate stdio shutdown by (1) closing the input stream to the child process, (2) waiting for the server to exit, and (3) forcibly terminating the process if it does not exit within a reasonable time. On POSIX forced termination typically escalates from SIGTERM to SIGKILL; on Windows clients can use TerminateProcess or Job Objects. Servers SHOULD exit promptly when stdin is closed or reads return EOF, this being the primary and only portable graceful-shutdown signal. The server MAY initiate shutdown by closing its output stream and exiting.
stdio cancellation MUST use notifications/cancelled
To cancel an in-flight request over stdio the client MUST send a `notifications/cancelled` notification referencing the request's ID; because stdio is a single shared bidirectional channel there is no per-request stream to close. Servers SHOULD stop work on a cancelled request as soon as practical and MUST NOT send any further messages for it.
Request-scoped notifications stay on the originating request stream
Request-scoped notifications such as `notifications/progress` and `notifications/message` continue to flow on the response stream of the request they relate to, not on the `subscriptions/listen` stream.
ping, logging/setLevel and roots/list_changed removed
Revision 2026-07-28 removes the `ping` method, the `logging/setLevel` method, and the `notifications/roots/list_changed` notification. Log level is instead set per-request via the `_meta` key `io.modelcontextprotocol/logLevel`, and servers MUST NOT emit `notifications/message` for requests that did not include this field.
No MCP features removed yet under the deprecation policy
As of revision 2026-07-28, no features have been removed under the feature lifecycle and deprecation policy. When a Deprecated feature is removed, its registry row moves to a 'Removed' section with a link to the changelog entry recording the removal.
Deprecated features registry in MCP 2026-07-28
The MCP specification revision 2026-07-28 maintains a registry of Deprecated features. A Deprecated feature remains part of the specification but is scheduled for removal: new implementations SHOULD NOT adopt it, and existing implementations SHOULD migrate before the feature's earliest removal. The 'earliest removal' date marks when a feature becomes eligible for removal; actual removal is a Core Maintainer decision taken during release preparation and may happen later. The registry is a derived view; the normative records are the per-feature deprecation notices and changelog entries.
SEP-2596 transition provisions for pre-policy deprecations
The HTTP+SSE transport and the sampling includeContext values "thisServer"/"allServers" were already described as deprecated before the MCP feature lifecycle policy existed; SEP-2596 reclassifies them as formally Deprecated under its transition provisions.
MCP additional utilities list
Beyond core features, MCP defines additional utilities: configuration, progress tracking, cancellation, and error reporting.
Logging feature deprecated in 2026-07-28
The Logging feature is deprecated as of MCP protocol version 2026-07-28 (SEP-2577). Under the feature lifecycle policy it remains in the specification for at least twelve months after that revision's release before becoming eligible for removal. New implementations SHOULD NOT adopt it; existing implementations SHOULD migrate to logging to `stderr` for stdio transports, or to OpenTelemetry for structured observability.
MCP log levels (RFC 5424 syslog severities)
MCP log levels follow RFC 5424 syslog severities, in increasing severity order: debug, info, notice, warning, error, critical, alert, emergency. Typical uses: debug = detailed debugging info (function entry/exit), info = general informational messages (operation progress), notice = normal but significant events (configuration changes), warning = warning conditions (deprecated feature usage), error = error conditions (operation failures), critical = critical conditions (system component failures), alert = action must be taken immediately (data corruption), emergency = system unusable (complete system failure).
Per-request log level via _meta io.modelcontextprotocol/logLevel
To receive log messages for a specific request, the client includes the key `io.modelcontextprotocol/logLevel` in that request's `_meta` object. The server MUST NOT emit `notifications/message` for a request that does not include this field. When present, the server MAY send `notifications/message` notifications at or above the requested level on the response stream of that request, before the final response.
Logging implementation SHOULD/MAY guidance
Servers SHOULD rate limit log messages, include relevant context in the data field, use consistent logger names, and remove sensitive information. Clients MAY present log messages in the UI, implement log filtering/search, display severity visually, and persist log messages. The protocol does not mandate any specific user interaction model for logging.
No client-to-server notifications over Streamable HTTP in 2026-07-28
The 2026-07-28 core protocol defines no client-to-server notifications over Streamable HTTP. The only client-sent core notification, notifications/cancelled, is used only on the stdio transport; on Streamable HTTP, closing the SSE response stream is itself the cancellation signal and no notifications/cancelled message is expected.
Cancellation by closing the SSE response stream (MUST)
Closing the SSE response stream MUST be treated by the server as cancellation of that request. Because each request has its own response stream, the transport-level disconnect is unambiguous. The server SHOULD stop work on the cancelled request as soon as practical and MUST NOT send any further messages for it.
progressToken in request _meta
`progressToken?: ProgressToken` (a `string | number`) in a request's `_meta` requests out-of-band progress notifications (`notifications/progress`) for that request. The token is opaque and is attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
logLevel per-request replaces logging/setLevel (deprecated)
The request `_meta` key `io.modelcontextprotocol/logLevel` sets the desired log level for that request and replaces the former `logging/setLevel` RPC. If absent, the server MUST NOT send any `notifications/message` notifications for that request; the client opts in by explicitly setting a level. Both this key and the `LoggingLevel` type are deprecated as of protocol version 2026-07-28 (SEP-2577) and remain in the specification for at least twelve months.
LoggingLevel enum values
`LoggingLevel` is one of "debug", "info", "notice", "warning", "error", "critical", "alert", "emergency", mapping to syslog severities from RFC-5424 section 6.2.1. It is deprecated as of protocol version 2026-07-28 (SEP-2577).
notifications/cancelled shape and params
CancelledNotification is a JSON-RPC notification: {"jsonrpc": "2.0", "method": "notifications/cancelled", "params": CancelledNotificationParams}. CancelledNotificationParams has required `requestId: RequestId`, optional `reason?: string`, and optional `_meta?: NotificationMetaObject`. Example: {"jsonrpc":"2.0","method":"notifications/cancelled","params":{"requestId":"123","reason":"User requested cancellation"}}.
Cancellation requestId MUST match a previously issued request
In notifications/cancelled, the `requestId` MUST correspond to the ID of a request the client previously issued. The request SHOULD still be in-flight, but due to latency the notification MAY arrive after the request has already finished. The notification indicates the result will be unused, so associated processing SHOULD cease. The optional `reason` string MAY be logged or presented to the user.
Servers MUST NOT use notifications/cancelled except to end subscriptions/listen on stdio
On stdio, the server also sends notifications/cancelled solely to terminate a subscriptions/listen stream, referencing the ID of the subscriptions/listen request that opened the stream. Servers MUST NOT use this notification to cancel any other request.
notifications/message (logging) shape and deprecation
LoggingMessageNotification is {"jsonrpc": "2.0", "method": "notifications/message", "params": LoggingMessageNotificationParams} sent server->client. Params: required `level: LoggingLevel`, optional `logger?: string`, required `data: unknown` (any JSON-serializable value), optional `_meta?: NotificationMetaObject`. The client opts in by setting "io.modelcontextprotocol/logLevel" in a request's `_meta`. This notification is deprecated as of protocol version 2026-07-28 (SEP-2577) and remains in the specification for at least twelve months.
notifications/progress shape and params
ProgressNotification is {"jsonrpc": "2.0", "method": "notifications/progress", "params": ProgressNotificationParams}, an out-of-band notification for progress updates on a long-running request. Params: required `progressToken: ProgressToken` (the token given in the initial request), required `progress: number` (should increase each time progress is made, even when total is unknown), optional `total?: number`, optional `message?: string`, optional `_meta?: NotificationMetaObject`. Example params: {"progressToken":"oivaizmir","progress":50,"total":100,"message":"Reticulating splines..."}.
roots and sampling deprecated in 2026-07-28 (SEP-2577)
ListRootsRequest, ListRootsResult, Root, CreateMessageRequest and CreateMessageRequestParams are all marked Deprecated as of protocol version 2026-07-28 (SEP-2577). They remain in the specification for at least twelve months; see the deprecated features registry.