# Support Both MCP Specs? A Q4 2026 Dual-Protocol Checklist

> Should your MCP server still speak 2025-11-25 alongside the stateless 2026-07-28 spec? Who breaks if you drop it, how to serve both, and when to stop.

**Source:** https://mcpplaygroundonline.com/blog/mcp-dual-protocol-support  
**Author:** Nikhil Tiwari  
**Published:** 2026-10-04  
**Category:** Development  
**Reading time:** 11 min read  
**Topics:** MCP dual protocol support, support both MCP specs, MCP 2025-11-25 vs 2026-07-28, MCP backward compatibility, MCP legacy clients, stateless MCP migration, MCP version detection, server/discover, createMcpHandler legacy, isLegacyRequest, UnsupportedProtocolVersion -32022, MCP deprecation policy, when to drop MCP 2025-11-25, how to serve both MCP versions

---

📖 TL;DR

-   **Public MCP server? Keep serving both specs through Q4 2026.** Old clients still send the 2025 `initialize` handshake.
-   A **modern-only server rejects them** with `-32022 UnsupportedProtocolVersion`. They simply can't connect.
-   New v2 SDK clients are fine either way. **They try `server/discover` and fall back to the handshake.**
-   In the v2 TypeScript SDK, dual support is the **default**: `createMcpHandler(factory, { legacy: 'stateless' })`.
-   **Drop legacy when your logs say so**, not on a date. Count requests per era first.
-   Deprecated _features_ (Roots, Sampling, Logging) keep working until at least **July 28, 2027**.

Table of Contents

1.  [The Two MCP Specs in One Table](#two-specs)
2.  [Who Breaks If You Drop 2025-11-25?](#who-breaks)
3.  [Should Your Server Support Both?](#should-you)
4.  [How Version Detection Works](#detect)
5.  [How to Serve Both Specs](#serve-both)
6.  [What the Deprecation Policy Covers](#deprecation)
7.  [The Q4 2026 Checklist](#checklist)
8.  [How to Test Both Versions](#test)
9.  [When to Drop the Old Spec](#drop)
10.  [FAQ](#faq)

The stateless MCP spec shipped on July 28, 2026. Two months later, I'm still getting the same question.

**"Can I drop the old 2025-11-25 handshake yet?"**

It's a fair question. Serving one spec is simpler. Dual code paths feel like debt you want gone.

But get it wrong and **some of your users stop connecting overnight**. They won't get a helpful message either. They'll get an error code and give up.

This post is my answer to _MCP dual protocol support_ in Q4 2026. Who breaks if you drop the old spec, how detection works, and how to serve both from one URL.

There's also a checklist, and a simple rule for when it's safe to stop. **It's based on your traffic, not the calendar.**

If you haven't migrated at all yet, start with my [2026-07-28 migration guide](/blog/migrate-mcp-server-2026-07-28-stateless). This post assumes you're past that.

## MCP 2025-11-25 vs 2026-07-28: The Two Specs in One Table

The official v2 SDK splits MCP into two _eras_. Every revision up to 2025-11-25 is **legacy**. 2026-07-28 and later is **modern**.

Aspect

Legacy (≤ 2025-11-25)

Modern (2026-07-28)

Connection start

`initialize` handshake

None. Optional `server/discover`

Sessions

`Mcp-Session-Id` header

Removed

Protocol version

Negotiated once

In `_meta` on every request

HTTP routing headers

—

`Mcp-Method`, `Mcp-Name` required

Resource not found

`-32002`

`-32602`

Scaling

Sticky sessions or shared store

Any instance, any request

For the full list of changes, see [what the stateless MCP spec changes](/blog/mcp-stateless-2026-release-candidate).

## Who Breaks If You Drop MCP 2025-11-25?

This is the part people get backwards. **Dropping legacy support doesn't hurt new clients. It hurts old ones.**

Client

Dual server

Modern-only server

New (v2 SDK)

✅ Modern

✅ Modern

Old (2025-era SDK)

✅ Legacy

❌ `-32022`

A new client asks `server/discover` first. If the server is legacy, **it falls back to the `initialize` handshake**. So new clients cope with old servers.

The reverse isn't true. **An old client only knows the handshake.** A modern-only server answers it with `-32022 UnsupportedProtocolVersion`, and the connection ends.

Who still runs old clients? Pinned SDK versions in production agents. Internal tools nobody has touched since spring. **Desktop apps whose users never update.**

## Should Your MCP Server Support Both Specs?

It depends who connects to you. Here's how I'd decide.

-   **Public server, unknown clients:** yes. Keep both through Q4 2026 at minimum.
-   **Internal server, clients you control:** upgrade the clients, then go modern-only.
-   **Brand-new server:** build for 2026-07-28. Leave the SDK's default fallback on, since it costs you nothing.
-   **Sessionful legacy deployment:** keep it running beside a new modern handler, and route between them.

The cost of keeping legacy is small in the v2 SDK. **The cost of dropping it too early is lost users.** That trade is easy.

## How MCP Version Detection Works

A dual server has to sort each request into an era. **The request itself tells you.** No extra header or URL is needed.

-   **Legacy signals:** an `initialize` request body, or an `Mcp-Session-Id` header on later calls.
-   **Modern signals:** a protocol version in `_meta`, under the key `io.modelcontextprotocol/protocolVersion`.

On the client side, it's the mirror image. **Call `server/discover`. If that fails, fall back to `initialize`.** The v2 client SDK does this for you.

One more client-side detail. The newest revision the v2 client uses for its handshake is 2025-11-25, not 2026-07-28. **That's the fallback version, not a bug.**

## How to Serve Both MCP Specs From One Endpoint

In the v2 TypeScript SDK, `createMcpHandler` serves both eras by default. You pass a factory that builds one server per request.

```
import { createMcpHandler } from '@modelcontextprotocol/server';

// One factory backs both eras, so they can't drift apart.
const handler = createMcpHandler(
  ({ era }) => {
    metrics.increment('mcp.requests', { era }); // 'legacy' | 'modern'
    return buildServer();
  },
  { legacy: 'stateless' } // the default; 'reject' = modern-only
);

export default { fetch: (req: Request) => handler.fetch(req) };
```

Two things to notice. **The `era` argument is your migration metric.** Count it, and you'll know exactly when legacy traffic dies.

And `legacy: 'stateless'` serves 2025 traffic without sessions. **That's fine for most tool servers**, because each call stands alone.

### Already Running a Sessionful Legacy Server?

Don't rewrite it. Put a modern-only handler in front, and **route legacy requests to your existing code** with `isLegacyRequest`.

```
import { createMcpHandler, isLegacyRequest } from '@modelcontextprotocol/server';

const modern = createMcpHandler(factory, { legacy: 'reject' });

export default {
  async fetch(request: Request) {
    if (await isLegacyRequest(request)) {
      return existingLegacyHandler(request); // your current sessionful setup
    }
    return modern.fetch(request);
  },
};
```

This is the pattern the SDK docs recommend. **Your proven legacy path stays untouched** while new traffic moves to stateless.

### Watch Your Gateway

If a proxy sits in front, check two things. **It must forward `Mcp-Method` and `Mcp-Name`** for modern traffic.

And it must keep sticky routing for sessionful legacy traffic. **Mixing those rules up is the most common dual-stack bug I see.** More in my [MCP gateway guide](/blog/mcp-gateway-guide).

## What the MCP Deprecation Policy Actually Covers

I see the 12-month rule misread a lot. **It's about deprecated features, not old spec versions.**

The 2026-07-28 release deprecated three features:

-   **Roots** → use tool parameters, resource URIs or server config
-   **Sampling** → call your LLM provider's API directly
-   **Logging** → use stderr or OpenTelemetry

The policy says these keep working in this release and **in every spec version published within a year of it**. So the earliest removal is July 28, 2027.

That gives you room, not a free pass. **Start moving off Roots, Sampling and Logging now**, while you're touching this code anyway.

## The Q4 2026 MCP Dual-Protocol Checklist

Run through this before the end of the year.

1.  **Serve both eras** from one URL, unless every client is under your control.
2.  **Log the era of every request.** You need this number to ever drop legacy.
3.  **Return era-correct error codes.** Resource-not-found is `-32002` for legacy and `-32602` for modern.
4.  **Forward `Mcp-Method` and `Mcp-Name`** through every proxy and gateway.
5.  **Remove session assumptions** from tool code. State goes in explicit handles, like a `basket_id` argument.
6.  **Add cache hints.** Set `ttlMs` and `cacheScope` on list results so modern clients stop refetching.
7.  **Plan off Roots, Sampling and Logging** before July 2027.
8.  **Test both eras on every release.** A green modern test says nothing about legacy.

Item 3 trips people up. [Here's what `-32602` means](/blog/mcp-error-32602) and why the code moved.

## How to Test Both MCP Versions Against Your Server

Point 8 is where most teams slip. **They test with the newest client and assume old ones still work.**

MCP Playground has an **MCP version switch** on the server tester for exactly this:

-   **Auto detect** tries `server/discover`, then falls back to the handshake, like a real v2 client.
-   **Stateless 2026-07-28** forces the modern path.
-   **Stateful 2025-11-25** forces the legacy handshake, like an old client.

After connecting, a badge shows what actually answered: the revision, stateless or stateful, and the session ID if there is one.

So the test is simple. **Connect once on Stateless, once on Stateful.** Both should list the same tools. [Test any MCP server free →](/mcp-test-server)

Want to see a correct dual server first? Point the tester at the [mock MCP servers](/mock-mcp-servers). The stateless mock accepts `?rev=2026-07-28` or `?rev=2025-11-25` to pin one era, so you can watch the `-32022` rejection happen.

Writing a client instead? [Build against the 2026 spec](/blog/build-mcp-server-2026-spec) and test it on the pinned mocks.

## When Should You Drop MCP 2025-11-25?

Not on a date. **Drop it when your era metric says legacy traffic is near zero**, and has stayed there for a few weeks.

When you get there, do it in two steps:

1.  **Announce it.** Put a date in your docs and changelog. Give old clients time to upgrade.
2.  **Flip to `legacy: 'reject'`.** Keep watching your error logs for `-32022` spikes.

For most public servers, I don't expect that before 2027. **Until then, dual support is the cheap insurance.**

## How MCP Playground Can Help

The MCP Playground server tester connects to any remote MCP server in either spec, shows which era answered, and lets you call every tool. **You can share a link that opens the tester with your server and MCP version already selected**, so a teammate can reproduce a legacy-only failure in one click.

## The Bottom Line

**Keep serving both MCP specs through Q4 2026 if strangers connect to your server.** New clients cope with old servers, but old clients can't reach new-only ones.

The v2 SDK makes dual support the default. Log the era, test both paths each release, and **drop legacy when your data says so.**

Does your server answer both specs?

Connect on Stateless, then on Stateful, and compare. Free, in the browser.

[Test any MCP server free →](/mcp-test-server) [Try the mock servers →](/mock-mcp-servers)

**Sources:** [MCP 2026-07-28 changelog](https://modelcontextprotocol.io/specification/2026-07-28/changelog) · [MCP release candidate notes](https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/) · [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) · [AAIF migration overview](https://aaif.io/blog/mcp-2026-07-28-whats-changing-and-how-to-migrate) · [W3C Trace Context](https://www.w3.org/TR/trace-context/)

## FAQ

**Should my MCP server support both 2025-11-25 and 2026-07-28?+**

If it is public, yes, at least through Q4 2026. Clients built on 2025-era SDKs only know the initialize handshake, and a modern-only server rejects them with -32022. Internal servers whose clients you control can go modern-only once those clients are upgraded.

**Can a new MCP client connect to an old MCP server?+**

Yes. The v2 client SDK calls server/discover first and falls back to the initialize handshake if the server is legacy. The reverse does not work: an old client cannot connect to a modern-only server.

**How does a server tell which MCP version a request uses?+**

From the request. An initialize body or an Mcp-Session-Id header means legacy. A protocol version in \_meta under io.modelcontextprotocol/protocolVersion means modern. The v2 SDK exposes this as isLegacyRequest and passes the era to your server factory.

**Does the 12-month deprecation policy mean 2025-11-25 is supported until 2027?+**

Not exactly. The policy covers deprecated features (Roots, Sampling and Logging), which keep working in every spec version published within a year of 2026-07-28. Whether your server still accepts 2025-era clients is your decision, based on who connects to you.

**How do I test my MCP server on both specs?+**

Use the MCP version switch in the MCP Playground server tester. Connect once with Stateless 2026-07-28 and once with Stateful 2025-11-25, and check that both list the same tools and return the same results.

## Frequently asked questions

### Should my MCP server support both 2025-11-25 and 2026-07-28?

If it is public, yes, at least through Q4 2026. Clients built on 2025-era SDKs only know the initialize handshake, and a modern-only server rejects them with -32022. Internal servers whose clients you control can go modern-only once those clients are upgraded.

### Can a new MCP client connect to an old MCP server?

Yes. The v2 client SDK calls server/discover first and falls back to the initialize handshake if the server is legacy. The reverse does not work: an old client cannot connect to a modern-only server.

### How does a server tell which MCP version a request uses?

From the request. An initialize body or an Mcp-Session-Id header means legacy. A protocol version in _meta under io.modelcontextprotocol/protocolVersion means modern. The v2 SDK exposes this as isLegacyRequest and passes the era to your server factory.

### Does the 12-month deprecation policy mean 2025-11-25 is supported until 2027?

Not exactly. The policy covers deprecated features (Roots, Sampling and Logging), which keep working in every spec version published within a year of 2026-07-28. Whether your server still accepts 2025-era clients is your decision, based on who connects to you.

### How do I test my MCP server on both specs?

Use the MCP version switch in the MCP Playground server tester. Connect once with Stateless 2026-07-28 and once with Stateful 2025-11-25, and check that both list the same tools and return the same results.


---

_Canonical page: https://mcpplaygroundonline.com/blog/mcp-dual-protocol-support — MCP Playground (mcpplaygroundonline.com), the free browser-based tool for testing MCP servers and building AI agents._
