Deprecated features
The 2026-07-28 spec retires five things. The SDK still implements every one of them, and every one of them now carries a deprecation warning.
The table below names each deprecated feature, why it is going away, and the replacement to build on.
What is deprecated
| Deprecated | Why | What you do instead |
|---|---|---|
Roots: ctx.session.list_roots(), client.send_roots_list_changed(), the list_roots_callback= you pass to Client(...) |
SEP-2577 retires the capability. | Take the paths as ordinary tool arguments or resource URIs, or embed a ListRootsRequest in an InputRequiredResult (see Multi-round-trip requests). |
Server-initiated sampling: ctx.session.create_message(), the sampling_callback= you pass to Client(...) |
SEP-2577 retires the capability. | Return InputRequiredResult and let the client retry the call (see Multi-round-trip requests). |
Protocol logging: ctx.log(), ctx.debug(), ctx.info(), ctx.warning(), ctx.error(), ctx.session.send_log_message(), client.set_logging_level() |
SEP-2577 retires the capability. Nothing in-protocol replaces it. | Ordinary import logging to stderr (see Logging). |
ping: client.send_ping() |
Removed from the protocol, not merely deprecated. There is no ping method in 2026-07-28. |
Nothing. It only works against a mode="legacy" connection. |
Client->server progress: client.send_progress_notification() |
2026-07-28 makes progress server->client only. | Nothing to send. Your server reports progress with ctx.report_progress() (see Progress). |
Three things fall out of that table:
- Roots, sampling, and logging go together. One proposal, SEP-2577, deprecates all three capabilities at once.
- Sampling and roots share a deeper problem: they are places a server sends a request to the client. That whole direction is what 2026-07-28 replaces with Multi-round-trip requests. It is the standalone RPC methods (
sampling/createMessage,roots/list, and push-styleelicitation/create) that are gone; theCreateMessageRequest/ListRootsRequest/ElicitRequestpayload types survive, embedded inInputRequiredResult.input_requests, and on the client they hit the same callbacks. pingis the odd one out. The protocol does not deprecate it, it removes it. The SDK method still warns (its message says removed, not deprecated) and calling it on a modern connection answers with "Method not found".
Deprecated is advisory
Nothing breaks today.
Every method above keeps working against any session that negotiated 2025-11-25 or earlier. Pin mode="legacy" on the client and you get exactly the pre-2026 behaviour. There are no wire changes and capability negotiation is unchanged.
What changes is that you get a visible warning the first time each one runs:
MCPDeprecationWarning: The logging capability is deprecated as of 2026-07-28 (SEP-2577).
MCPDeprecationWarning subclasses UserWarning, not DeprecationWarning. That is deliberate: Python's default filter only shows DeprecationWarning in code run directly as __main__, which is how libraries deprecate things and nobody notices for two years. This one shows up everywhere, with no -W flag.
Warning
"Advisory" stops at the wire. Sampling and roots are server-to-client requests, and a
2026-07-28 session has no channel to carry one. Call ctx.session.create_message()
inside a tool on a modern connection and the warning still fires, and then the send
fails with an error:
Cannot send 'sampling/createMessage': this transport context has no back-channel
for server-initiated requests.
Two signals, in that order. The MCPDeprecationWarning fires the moment you call the
method, on any connection. The error is what comes back when the SDK then tries to
send. These two only work end-to-end on a mode="legacy" connection whose client
registered the matching callback.
Silencing the warning
Don't, in new code.
But a server you maintain that genuinely serves pre-2026 clients has every right to a quiet log. Filter the category before the first deprecated call runs:
import warnings
from mcp import MCPDeprecationWarning
warnings.filterwarnings("ignore", category=MCPDeprecationWarning)
That is the whole API. There is no per-method switch, and you don't want one: the point of one category is that one line silences it and one line brings it back.
Check
Run the filter the other way and you get a free regression test. Add
"error::mcp.MCPDeprecationWarning" to the filterwarnings setting in your pytest
configuration and the deprecated call raises instead of warning. A tool named
old_log that still calls ctx.info() stops passing and starts reporting:
Error executing tool old_log: The logging capability is deprecated as of 2026-07-28 (SEP-2577).
One line of pytest configuration, and a deprecated call can never sneak back into your codebase without failing a test.
Recap
- The 2026-07-28 spec deprecates roots, server-initiated sampling, and protocol logging (all SEP-2577), restricts progress to server-to-client, and removes
ping. - The replacement column points you onward: Multi-round-trip requests for sampling and roots, Logging for logging, Progress for progress.
pingneeds nothing at all. - Deprecated is advisory: no wire changes, everything keeps working against pre-2026 sessions, and you get a visible
MCPDeprecationWarning(aUserWarning, so it is on by default). - Sampling and roots additionally need a back-channel that a 2026-07-28 session does not have. On a modern connection they warn and then they raise.
warnings.filterwarnings("ignore", category=MCPDeprecationWarning)silences the whole category;"error::mcp.MCPDeprecationWarning"in pytest turns it into a test failure.- New code should not be built on any of these.
Every other page in these docs teaches the current API.