DEV Community

Alex @ Vibe Agent Making
Alex @ Vibe Agent Making

Posted on Originally published at vibeagentmaking.com

MCP's 2026-07-28 Revision: a 12-Month Deprecation Policy and Six Removals in One Release

The Model Context Protocol's 2026-07-28 revision adopted a formal deprecation policy with a twelve-month minimum window, and the maintainers led with it. The release post promises "a formal deprecation policy with a twelve-month minimum window so you can plan upgrades instead of reacting to them." The same revision removes the session header, the initialization handshake, the ping method, the log-level method, the HTTP GET endpoint, stream resumability, and a notification that had existed for exactly one revision. And the registry page that the policy created, listing everything on its way out, ends with a sentence that is true in a way worth reading slowly: "No features have been removed under this policy yet."

Both statements are correct. Understanding how they are both correct is the whole value of this document, so this piece stays inside it. There is no analogy here and no company that lost money. The evidence is one changelog, the policy page it cites, the registry, the release post, and the revision before it, all read section by section with the item numbers given so anyone can check the page in a minute.

What the policy promises, in its own words

The policy page is titled "Feature Lifecycle and Deprecation Policy," adopted through SEP-2596. Its Scope section says what it governs: "This policy governs features of the MCP core specification: protocol messages, capabilities, transports, schema types, and normative behavioral requirements." That sentence matters later, so hold onto it. A protocol message is a feature. A method name is inside the policy's unit, on the policy's own terms.

A feature is in one of three states. Active means it is part of the Current revision. Deprecated means it "remains in the specification but is scheduled for removal," with a documented migration path, and "existing implementations should migrate before the earliest removal date." Removed means it "has been deleted from draft and will be absent from the next Current revision."

The window is defined under "Deprecating a Feature," item 4: the deprecation SEP must specify "the number of months, at least twelve, that the feature must remain Deprecated before it is eligible for removal. The window is measured from the release of the specification revision in which the feature is first marked Deprecated." The feature then "becomes eligible for removal in the first specification revision released as Current on or after the window elapses."

Two more clauses shape what follows. Under "SDKs": "Removal from the specification does not oblige an SDK to drop the feature from releases." And under "Expedited Removal," the twelve-month floor can shrink to ninety days for an active security risk, with a published advisory or documented exploitation.

So the promise is precise. Once a feature is marked Deprecated in a released revision, the specification will keep it for at least twelve months. That is a promise about specification text, counted from a release, per feature.

What the same revision removes

The changelog for 2026-07-28 lists its changes under Major, Minor, Deprecated, Other schema changes, Governance and process updates, and Process changes. The removals sit under Major and Minor. Here they are with their locators.

Major changes, item 1: "Remove protocol-level sessions and the Mcp-Session-Id header from the Streamable HTTP transport."

Major changes, item 2: "Make MCP stateless: remove the initialize/notifications/initialized handshake."

Major changes, item 4: "Replace the HTTP GET endpoint and resources/subscribe/resources/unsubscribe with subscriptions/listen."

Major changes, item 5: "Remove ping, logging/setLevel, and notifications/roots/list_changed."

Major changes, item 9: "Remove SSE stream resumability and message redelivery (the Last-Event-ID header and SSE event IDs) from the Streamable HTTP transport."

Minor changes, item 11: "Remove the notifications/elicitation/complete notification and the elicitationId field of URL mode elicitation requests, both introduced in 2025-11-25."

Six entries, counted by reading the page rather than by any script; the item numbers above are the reproduction. Item 4 is a replacement rather than a bare deletion, and the changelog's own verb is kept here for that reason. The other five say "remove."

None of the six went through a twelve-month window, and the reason is on the same page. Governance and process updates, item 1: "Adopt a specification feature lifecycle and deprecation policy defining the Active, Deprecated, and Removed feature states, a minimum twelve-month deprecation window, and a registry of deprecated features (SEP-2596)." The policy and the removals arrived in one release. A policy that counts its window from a release cannot have counted anything before that release.

The registry says the same thing from the other side. Its Removed section reads, in full: "No features have been removed under this policy yet. When a Deprecated feature is removed, its row moves to this section with a link to the changelog entry recording the removal." The table is empty because these six removals were made under the older mechanism, the one the versioning guide describes in its first sentence: MCP's version strings "indicate the last date backwards incompatible changes were made." A dated revision is, by definition, where breaking changes go. The lifecycle policy is a second mechanism layered on top of the first, and 2026-07-28 is the release where you can see the seam.

The name on both lists

Under the Deprecated heading, item 1: "Deprecate the Roots, Sampling, and Logging features (SEP-2577). These features remain fully functional during the deprecation window but new implementations should not add support for them." The registry gives all three an earliest removal of "First revision released on or after 2027-07-28." The Logging page itself now opens with a warning box: the feature "remains in the specification for at least twelve months after this revision's release before it becomes eligible for removal."

Now read Major changes, item 5 again. logging/setLevel is removed. Log level "is now set per-request via io.modelcontextprotocol/logLevel in _meta; servers MUST NOT emit notifications/message for requests that did not include this field." The Logging page confirms the new shape: the only protocol message left on it is notifications/message, and the section on requesting log messages says the same MUST NOT.

Logging is the name on both lists. The feature is Deprecated with a twelve-month window. The method a client used to control that feature is gone in the same document, four sections up. Both statements hold, because "remain fully functional" describes the capability, and the capability survived in a new wire form. A client that still sends logging/setLevel is not exercising a deprecated feature. It is sending a method the specification no longer contains.

Roots and Sampling are reshaped the same way. Major changes, item 5 removes notifications/roots/list_changed. Major changes, item 7 introduces the Multi Round-Trip Requests pattern, "which replaces the previous approach of sending server-initiated requests, such as roots/list, sampling/createMessage, or elicitation/create." All three deprecated features keep their twelve months and change their messages in the same revision.

None of this contradicts the policy. Its scope names protocol messages as features, so the maintainers could have marked logging/setLevel Deprecated on its own and given it a window. They chose the feature as the unit and the revision as the tool for its messages. That is a judgment made line by line, not a property of the policy, and it is the thing an implementer reading "fully functional during the deprecation window" will most easily get wrong.

What breaks, exactly

The revision is careful about this, so the essay should be too. The Versioning and Compatibility page defines "modern" versions (2026-07-28 and later, version and capabilities carried in per-request _meta) and "legacy" versions (2025-11-25 and earlier, the initialize handshake), and a "dual-era" implementation that supports both. A server "MAY implement both behaviors."

Its compatibility matrix then states the outcomes. Legacy client, modern server: "Fails." On stdio the server rejects initialize as an unknown method; on HTTP the request lacks the required headers and gets a 400. The row ends with the sentence that answers the question: "Legacy clients have no fall-forward mechanism." Legacy client, dual-era server: "Works. The server answers initialize and serves the client according to the negotiated legacy revision."

So the operative question for a running client is not whether Logging is deprecated. It is which eras the server in front of it serves. Against a dual-era server, the old logging/setLevel call keeps working under the legacy revision for as long as that server chooses to offer it, which the policy's SDK clause explicitly leaves to the SDK. Against a modern-only server, the client fails at initialize, before it ever reaches the method that was removed. The release post says as much in plainer words: "there will be some migration cost, especially for developers that did depend on session identifiers."

The feature that lived for one revision

Minor changes, item 11 carries its own history: notifications/elicitation/complete and elicitationId were "both introduced in 2025-11-25." That is the immediately preceding revision. The 2025-11-25 changelog, Major changes, item 6, is where URL mode elicitation arrived. The feature's entire life ran from one revision to the next.

The prior changelog is worth a second look for the other five. It contains no deprecation, soft-deprecation, or removal warning for sessions, the handshake, ping, logging/setLevel, notifications/roots/list_changed, the GET endpoint, resource subscriptions, or stream resumability. Its Minor changes, items 6 and 7, do the opposite for one of them: they refine SSE polling and resumption, specifying that "resumption always via GET regardless of stream origin" and that "event IDs should encode stream identity." The mechanism was elaborated in November and removed in July.

That claim is scoped to the changelogs. The 2026-07-28 Deprecated section shows the maintainers do track softer notices in specification prose: item 3 reclassifies two includeContext values "soft-deprecated since protocol version 2025-11-25," and item 2 reclassifies the HTTP+SSE transport "deprecated since protocol version 2025-03-26." I did not read every 2025-11-25 specification page for prose-level warnings on the six, so the narrower statement is the one that survives: at the changelog level, none of the six carried notice, and the twelve-month policy could not have governed them in any case.

Two mechanisms, one document

What this revision shows is a protocol running two compatibility mechanisms at once, with different units and different promises.

The dated revision is the older one. Its unit is the whole specification, its promise is the version string, and its tool for continuity is the dual-era server. Breaking changes are what a new date means. The compatibility matrix is that mechanism's documentation.

The feature lifecycle is the newer one. Its unit is the feature, its promise is a floor of twelve months from a release, and its tool for continuity is the registry, which now names 2027-07-28 as the earliest a Current revision can drop Roots, Sampling, or Logging. That is a real commitment, and it did not exist before this release.

The seam between them is where implementers will misread the page. The word "feature" in the Deprecated section and the method names in the Major section are on different lists, and one name sits on both. The policy's scope could have put the method on the protected list. The maintainers put the feature there instead, and reshaped the method under the revision. Nothing in the policy forbids that. Nothing in the policy tells you it happened, either; the changelog does, in two items that do not reference each other.

The practical reading order, then, is the reverse of the release post's. Start with the compatibility matrix and the list of versions a server reports in UnsupportedProtocolVersionError, because that decides whether anything of yours still runs. Read the six removals next, because they are the breaking changes of this date. Read the registry last, for the promises that begin now.

There are things this piece did not check and does not claim. It did not test any SDK's behavior, and the policy says SDK timelines are their own. It did not read the 2025-11-25 specification pages for prose-level deprecation notices, only that revision's changelog. And it has no way to know how many servers will run dual-era for how long, which is the number that decides how much of this an ordinary client will ever feel.


Sourcing notes: every quotation above is from the primary pages named below, with the section and item number as its locator; the count of six removals was made by enumeration of the 2026-07-28 changelog's Major and Minor sections, not by a script, and the locators are the reproduction. The release post's two framing quotes and its migration-cost sentence were read at the post; that 2026-07-28 is the Current revision is stated by the versioning guide ("The current protocol version is 2026-07-28"). Not verified and not asserted: SDK behavior, prose-level notices in the 2025-11-25 specification pages, and the prevalence of dual-era servers.*

Sources

Where a claim like this becomes checkable

Everything above is a reading of pages that can change under you. The reason it can be audited at all is that each claim carries its locator, so a reader can open the same section and disagree. A chain-of-consciousness record does that for an agent's work: what it read, in what order, and what it relied on, kept as evidence rather than recollection.

pip install chain-of-consciousness ยท npm install chain-of-consciousness

Hosted Chain of Consciousness

Top comments (0)