diff --git a/.github/ISSUE_TEMPLATE/v2-feedback.yaml b/.github/ISSUE_TEMPLATE/v2-feedback.yaml
index 35ed633d5d..cfa6996989 100644
--- a/.github/ISSUE_TEMPLATE/v2-feedback.yaml
+++ b/.github/ISSUE_TEMPLATE/v2-feedback.yaml
@@ -1,15 +1,15 @@
name: v2 feedback
description: Bugs, API friction, or docs gaps in v2 of the SDK
title: "[v2] "
-labels: ["v2-alpha"]
+labels: ["v2"]
body:
- type: markdown
attributes:
value: |
- Thanks for trying v2. Anything that broke, surprised you, or slowed you down is useful — API feedback is explicitly welcome while v2 is in pre-release.
+ Anything in v2 that broke, surprised you, or slowed you down is useful, including API friction and docs gaps.
- Docs: https://py.sdk.modelcontextprotocol.io/v2/ · Migration from v1: https://py.sdk.modelcontextprotocol.io/v2/migration/
+ Docs: https://py.sdk.modelcontextprotocol.io/ · Migration from v1: https://py.sdk.modelcontextprotocol.io/migration/
- type: textarea
id: what
diff --git a/AGENTS.md b/AGENTS.md
index 43fbb887d4..2812ed6d17 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -2,16 +2,16 @@
## Branching Model
-
-
-- `main` is currently the V2 rework.
-- Breaking changes are expected here — removing or replacing an API must be
- intentional. Adding a replacement API or `@deprecated` shim must likewise be
- a deliberate design choice, not bolted on for free.
-- Breaking changes (including those softened by a backwards-compatibility
- shim) must be documented in `docs/migration.md`.
-- `v1.x` is the release branch for the current stable line. Backport PRs target
- this branch and use a `[v1.x]` title prefix.
+- `main` is the current stable line (v2); releases are cut from it (see
+ `RELEASE.md`).
+- Removing or replacing an API must be intentional, and what shipped in 2.x
+ is public surface. Adding a replacement API or `@deprecated` shim is
+ likewise a deliberate design choice, not bolted on for free.
+- Changes that break code written against v1 (including those softened by a
+ backwards-compatibility shim) must be documented in `docs/migration.md`.
+- `v1.x` is the maintenance branch for the previous major. Backport PRs
+ target it and use a `[v1.x]` title prefix; only critical bug fixes and
+ security fixes land there.
- `README.md` documents v2. The v1 README lives on the `v1.x` branch.
## Package Management
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a36dedd8da..b0fb9fa57b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -76,11 +76,11 @@ uv tool install pre-commit --with pre-commit-uv --force-reinstall
| Change Type | Target Branch | Example |
|-------------|---------------|---------|
- | New features, breaking changes | `main` | New APIs, refactors |
+ | New features and fixes for v2 | `main` | New APIs, refactors |
| Security fixes for v1 | `v1.x` | Critical patches |
- | Bug fixes for v1 | `v1.x` | Non-breaking fixes |
+ | Critical bug fixes for v1 | `v1.x` | Backports of severe bugs |
- > **Note:** `main` is the v2 development branch. Breaking changes are welcome on `main`. The `v1.x` branch receives only security and critical bug fixes.
+ > **Note:** `main` is the current stable line (v2). The `v1.x` branch is the previous major's maintenance line and receives only security and critical bug fixes.
2. Create a new branch from your chosen base branch
diff --git a/README.md b/README.md
index 7224bb65d3..b14a8e1209 100644
--- a/README.md
+++ b/README.md
@@ -13,18 +13,18 @@
-> [!CAUTION]
-> **This README documents v2 of the MCP Python SDK — a pre-release (alpha/beta) line under active development. Do not use v2 in production.** Pre-releases are published to PyPI as `2.0.0aN` / `2.0.0bN`, and **each pre-release may contain breaking changes from the previous one**. Pin an exact version and expect to update your code when you bump the pin.
+> [!NOTE]
+> **This is v2 of the MCP Python SDK, the current stable release line.** It is a major rework of the SDK, both to support the [2026-07-28 MCP specification](https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/) (and every earlier revision) and to fix long-standing architectural issues. Coming from v1? See [What's new in v2](https://py.sdk.modelcontextprotocol.io/whats-new/) for the tour of what changed and the [migration guide](https://py.sdk.modelcontextprotocol.io/migration/) for every breaking change.
>
-> **v1.x is the only stable release line and remains recommended for production.** It lives on the [`v1.x` branch](https://github.com/modelcontextprotocol/python-sdk/tree/v1.x) and continues to receive critical bug fixes and security patches; see [the v1.x README](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/README.md) for its documentation. `pip` and `uv` don't select a pre-release unless you explicitly request one, so existing installs are unaffected. **If your package depends on `mcp`, add a `<2` upper bound to your version constraint (for example `mcp>=1.27,<2`) before the stable release lands.**
+> **Not ready to migrate?** v1.x lives on the [`v1.x` branch](https://github.com/modelcontextprotocol/python-sdk/tree/v1.x), continues to receive critical bug fixes and security patches, and is documented at . Since `pip install mcp` now installs 2.x, keep a `<2` upper bound on your requirement (for example `mcp>=1.28,<2`) until you've migrated.
>
-> v2 is a major rework of the SDK, both to support the [2026-07-28 MCP specification release](https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/) and to fix long-standing architectural issues. See [What's new in v2](https://py.sdk.modelcontextprotocol.io/v2/whats-new/) for the tour of what changed, and the [migration guide](https://py.sdk.modelcontextprotocol.io/v2/migration/) for every breaking change. Stable v2 is targeted for 2026-07-28, alongside the spec release. Try the pre-releases and [tell us what breaks](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=v2-feedback.yaml), or discuss in [#python-sdk-dev on the MCP Contributors Discord](https://discord.gg/6CSzBmMkjX).
+> Something rough, confusing, or broken? [Open an issue](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=v2-feedback.yaml) or find us in [#python-sdk-dev on the MCP Contributors Discord](https://discord.gg/6CSzBmMkjX).
## Documentation
-**The documentation lives at .**
+**The documentation lives at .**
-It has a [Get started guide](https://py.sdk.modelcontextprotocol.io/v2/get-started/), [What's new in v2](https://py.sdk.modelcontextprotocol.io/v2/whats-new/), the [API reference](https://py.sdk.modelcontextprotocol.io/v2/api/mcp/), and the [migration guide](https://py.sdk.modelcontextprotocol.io/v2/migration/).
+It has a [Get started guide](https://py.sdk.modelcontextprotocol.io/get-started/), [What's new in v2](https://py.sdk.modelcontextprotocol.io/whats-new/), the [API reference](https://py.sdk.modelcontextprotocol.io/api/mcp/), and the [migration guide](https://py.sdk.modelcontextprotocol.io/migration/).
## What is MCP?
@@ -41,10 +41,10 @@ Python 3.10+.
## Installation
```bash
-uv add "mcp[cli]==2.0.0b1" # or: pip install "mcp[cli]==2.0.0b1"
+uv add "mcp[cli]" # or: pip install "mcp[cli]"
```
-The pin matters while v2 is in pre-release: an unpinned install resolves to the latest stable v1.x, which this README does not describe. Check [PyPI](https://pypi.org/project/mcp/#history) for the newest pre-release, and use `uv run --with "mcp==2.0.0b1"` for one-off commands.
+The `cli` extra adds the `mcp` command-line tool (`mcp dev`, `mcp run`, `mcp install`) on top of the SDK; install plain `mcp` if you don't need it. For one-off commands, `uv run --with "mcp[cli]" mcp ...` works without a project.
## A server in 15 lines
@@ -82,7 +82,7 @@ Call `add` with `a=1`, `b=2` and you get `3` back.
Notice what you did **not** write: no JSON Schema (`a: int, b: int` _is_ the schema), no request parsing, no validation code, no protocol handling. Two type-hinted Python functions and a docstring.
-[Get started](https://py.sdk.modelcontextprotocol.io/v2/get-started/) takes it from here.
+[Get started](https://py.sdk.modelcontextprotocol.io/get-started/) takes it from here.
## A client in 10 lines
@@ -122,7 +122,7 @@ This project is licensed under the MIT License. See the [LICENSE](https://github
[python-badge]: https://img.shields.io/pypi/pyversions/mcp.svg
[python-url]: https://www.python.org/downloads/
[docs-badge]: https://img.shields.io/badge/docs-python--sdk-blue.svg
-[docs-url]: https://py.sdk.modelcontextprotocol.io/v2/
+[docs-url]: https://py.sdk.modelcontextprotocol.io/
[protocol-badge]: https://img.shields.io/badge/protocol-modelcontextprotocol.io-blue.svg
[protocol-url]: https://modelcontextprotocol.io
[spec-badge]: https://img.shields.io/badge/spec-spec.modelcontextprotocol.io-blue.svg
diff --git a/SECURITY.md b/SECURITY.md
index e8b51cc08d..8bcb1d4028 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -4,12 +4,17 @@ Thank you for helping keep the Model Context Protocol and its ecosystem secure.
## Supported Versions
-Security fixes are released for the most recent stable (v1.x) release line.
-
-v2 pre-releases (`2.0.0aN`, …) are development snapshots: fixes land only in
-the newest pre-release, and already-published pre-releases are not patched. If
-you are testing the v2 line, track the latest pre-release; for production use,
-stay on the latest stable release.
+| Version | Line | Support |
+| ------------------------------------ | ----------------------- | ---------------------------------------- |
+| 2.x (newest release) | current stable (`main`) | bug fixes, security fixes, new features |
+| 1.28.x (`v1.x` branch) | maintenance | critical bug fixes and security fixes |
+| < 1.28, and all pre-release versions | unsupported | upgrade to the newest 1.28.x or to 2.x |
+
+Only the newest release of a supported line receives fixes, so reproduce against
+it before reporting. If your project depends on `mcp` and is not yet ready for
+2.x, constrain to `mcp>=1.28,<2` and follow the
+[migration guide](https://py.sdk.modelcontextprotocol.io/migration/) when you
+migrate.
## Reporting Security Issues
diff --git a/docs/get-started/installation.md b/docs/get-started/installation.md
index d39c12e391..aebd18fb9b 100644
--- a/docs/get-started/installation.md
+++ b/docs/get-started/installation.md
@@ -2,30 +2,24 @@
The Python SDK is on PyPI as [`mcp`](https://pypi.org/project/mcp/). It requires **Python 3.10+**.
-These docs describe **v2**, which is in beta, so the version pin is not optional yet:
+These docs describe **v2**, the current stable release line:
=== "uv"
```bash
- uv add "mcp[cli]==2.0.0b1"
+ uv add "mcp[cli]"
```
=== "pip"
```bash
- pip install "mcp[cli]==2.0.0b1"
+ pip install "mcp[cli]"
```
-!!! warning "Why the pin"
- Installers never select a pre-release unless you name one, so an unpinned `uv add "mcp[cli]"`
- gives you the latest **v1.x** release, which these docs do not describe. Check the
- [release history](https://pypi.org/project/mcp/#history) for the newest beta before you copy
- the line above.
-
- The same applies to one-off commands: `uv run --with "mcp==2.0.0b1" ...`, not `uv run --with mcp ...`.
-
- If your *package* depends on `mcp`, add a `<2` upper bound (for example `mcp>=1.27,<2`) before
- the stable v2 lands so the major version bump doesn't surprise you.
+!!! note "Coming from v1?"
+ v2 is a major version with breaking changes; the **[Migration Guide](../migration.md)**
+ covers every one. If your *package* depends on `mcp` and isn't ready to migrate, keep a
+ `<2` upper bound (for example `mcp>=1.28,<2`) so an unpinned resolve stays on the 1.x line.
## What gets installed
diff --git a/docs/get-started/real-host.md b/docs/get-started/real-host.md
index 4292d9b2ed..237ed07c56 100644
--- a/docs/get-started/real-host.md
+++ b/docs/get-started/real-host.md
@@ -23,17 +23,12 @@ That is the last line of Python on this page. From here down it is all host conf
Every host below gets the same command:
```bash
-uv run --with "mcp[cli]==2.0.0b1" mcp run /absolute/path/to/server.py
+uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py
```
-One command for all of them because `uv run --with` resolves the pinned SDK into a fresh environment on the spot: it works from any directory, needs no project and no virtual environment to activate, and always gets the exact `mcp` version these docs describe. That matters here more than anywhere else, because a host launches your server from *its* working directory with a near-empty environment, not from your shell.
+One command for all of them because `uv run --with` resolves the SDK into a fresh environment on the spot: it works from any directory and needs no project and no virtual environment to activate. That matters here more than anywhere else, because a host launches your server from *its* working directory with a near-empty environment, not from your shell.
-It is also the command `mcp install` writes into Claude Desktop's config for you (below), so what you type by hand and what the tool generates agree.
-
-!!! warning "The version pin is not optional"
- v2 of this SDK is in beta, and installers never select a pre-release unless you name one. An
- unpinned `--with "mcp[cli]"` gives you the latest **v1.x**, which these docs do not describe.
- Use the exact pin from **[Installation](installation.md)**.
+It is also the command `mcp install` writes into Claude Desktop's config for you (below), so what you type by hand and what the tool generates agree, apart from the exact version pin the tool adds.
!!! tip "If a host can't find `uv`"
A host spawns your server with a minimal `PATH`, and `uv` may not be on it. Replace the bare
@@ -74,7 +69,7 @@ There is nothing to be mystified by. This is the entry it writes:
"run",
"--frozen",
"--with",
- "mcp[cli]==2.0.0b1",
+ "mcp[cli]==2.0.0",
"mcp",
"run",
"/absolute/path/to/server.py"
@@ -84,12 +79,12 @@ There is nothing to be mystified by. This is the entry it writes:
}
```
-That's the launch command from the section above with two additions: the absolute path to `uv`, and `--frozen` so `uv` never rewrites a lockfile it happens to be near. It lands in `claude_desktop_config.json`, which lives at:
+That's the launch command from the section above with three additions: the absolute path to `uv`, `--frozen` so `uv` never rewrites a lockfile it happens to be near, and an exact pin to the `mcp` version you have installed. It lands in `claude_desktop_config.json`, which lives at:
* **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
* **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
-You can write that file by hand. `mcp install` exists so you don't make the two classic mistakes (a relative path, a missing version pin) while doing it.
+You can write that file by hand. `mcp install` exists so you don't make the classic mistake (a relative path) while doing it.
Fully quit Claude Desktop (not just its window) and reopen it.
@@ -107,7 +102,7 @@ Fully quit Claude Desktop (not just its window) and reopen it.
There is no file to edit. Register the server with the `claude` CLI; everything after `--` is the launch command.
```bash
-claude mcp add bookshop -- uv run --with "mcp[cli]==2.0.0b1" mcp run /absolute/path/to/server.py
+claude mcp add bookshop -- uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py
```
Run `/mcp` inside a Claude Code session to confirm `bookshop` is connected and its tools are listed.
@@ -121,7 +116,7 @@ Create `.cursor/mcp.json` in your project root.
"mcpServers": {
"bookshop": {
"command": "uv",
- "args": ["run", "--with", "mcp[cli]==2.0.0b1", "mcp", "run", "/absolute/path/to/server.py"]
+ "args": ["run", "--with", "mcp[cli]", "mcp", "run", "/absolute/path/to/server.py"]
}
}
}
@@ -139,7 +134,7 @@ Create `.vscode/mcp.json` in your project root.
"bookshop": {
"type": "stdio",
"command": "uv",
- "args": ["run", "--with", "mcp[cli]==2.0.0b1", "mcp", "run", "/absolute/path/to/server.py"]
+ "args": ["run", "--with", "mcp[cli]", "mcp", "run", "/absolute/path/to/server.py"]
}
}
}
@@ -156,7 +151,7 @@ Two differences from Cursor's file, and they are the only two: the wrapper key i
Before you touch any host config, run the launch command yourself:
```bash
-uv run --with "mcp[cli]==2.0.0b1" mcp run /absolute/path/to/server.py
+uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py
```
Nothing prints, and it doesn't return. That silence is correct: a stdio server is waiting for a host to speak first on stdin (`Ctrl-C` to stop it). A traceback or an immediate exit is the real bug, and now you can read it instead of guessing at it through a host.
@@ -174,7 +169,7 @@ For anything past those three, **[Troubleshooting](../troubleshooting.md)** is t
## Recap
* A **host** (Claude Desktop, an IDE) runs an MCP client that launches your server as a child process over stdio. Connecting means giving it one launch command.
-* That command is `uv run --with "mcp[cli]==2.0.0b1" mcp run /absolute/path/to/server.py`: version-pinned, no venv to activate, works from any directory. The pin is mandatory while v2 is in beta.
+* That command is `uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py`: no venv to activate, works from any directory.
* **Claude Desktop** is the one host `mcp install` configures for you. It writes that same command (plus the absolute path to `uv`) into `claude_desktop_config.json`, so you never have to.
* **Claude Code** is `claude mcp add bookshop -- `. **Cursor** is `.cursor/mcp.json` under `mcpServers`. **VS Code** is `.vscode/mcp.json` under `servers`, each entry with a `type`.
* Absolute paths everywhere, restart the host after editing its config, and never let anything but the SDK write to stdout.
diff --git a/docs/index.md b/docs/index.md
index 8aa1a5b671..3d10fc9bca 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,9 +1,9 @@
# MCP Python SDK
-!!! info "You are viewing the in-development v2 documentation"
- For the current stable release, see the [v1.x documentation](https://py.sdk.modelcontextprotocol.io/).
- New to v2, or coming from v1? **[What's new in v2](whats-new.md)** is the five-minute tour of what changed.
- Trying v2? [Tell us what you find](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=v2-feedback.yaml) — it is the most useful thing you can do for the SDK right now.
+!!! info "This documents v2, the current stable release line"
+ New to v2, or coming from v1? **[What's new in v2](whats-new.md)** is the five-minute tour of what changed, and the **[Migration Guide](migration.md)** covers every breaking change.
+ Still on v1.x? Its documentation lives at the [v1.x docs](https://py.sdk.modelcontextprotocol.io/v1/).
+ Something rough or confusing? [Tell us](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=v2-feedback.yaml).
The **Model Context Protocol (MCP)** lets applications provide context to LLMs in a standardized way, separating the concern of *providing* context from the LLM interaction itself.
@@ -22,22 +22,17 @@ Python 3.10+.
=== "uv"
```bash
- uv add "mcp[cli]==2.0.0b1"
+ uv add "mcp[cli]"
```
=== "pip"
```bash
- pip install "mcp[cli]==2.0.0b1"
+ pip install "mcp[cli]"
```
The `[cli]` extra gives you the `mcp` command; you'll want it for development.
-
-!!! warning "Pin the version while v2 is in beta"
- Installers never select a pre-release unless you name one, so an unpinned `uv add "mcp[cli]"`
- gives you the latest **v1.x** release, which this documentation does not describe. Check
- [PyPI](https://pypi.org/project/mcp/#history) for the newest beta before you copy the line
- above. See [Installation](get-started/installation.md) for the details.
+See [Installation](get-started/installation.md) for what each dependency is for.
## Example
@@ -98,5 +93,5 @@ You wrote two Python functions with type hints and a docstring. The SDK does the
* Migrating from v1? Start with the **[Migration Guide](migration.md)**.
* Hunting for an exact signature? The **[API Reference](api/mcp/index.md)** is generated from the source.
* Reading with an LLM? This documentation is also published in the [llms.txt](https://llmstxt.org/) format:
- [llms.txt](https://py.sdk.modelcontextprotocol.io/v2/llms.txt) is an index of the pages, and
- [llms-full.txt](https://py.sdk.modelcontextprotocol.io/v2/llms-full.txt) contains every page in a single file.
+ [llms.txt](https://py.sdk.modelcontextprotocol.io/llms.txt) is an index of the pages, and
+ [llms-full.txt](https://py.sdk.modelcontextprotocol.io/llms-full.txt) contains every page in a single file.
diff --git a/docs/migration.md b/docs/migration.md
index 5eb7659c23..836be4ee9c 100644
--- a/docs/migration.md
+++ b/docs/migration.md
@@ -158,8 +158,8 @@ in `httpx2`; build an `ssl.SSLContext` and configure it instead.
Both commands run your server through a fresh `uv run --with ...` environment. In v1 the
`mcp` requirement in that command was unpinned, so the spawned environment resolved to the
-newest stable release rather than the version you had installed; with a v2 pre-release
-installed, `mcp dev server.py` built a v1 environment that could not import a v2 server.
+newest stable release rather than the version you had installed; while v2 was in
+pre-release, `mcp dev server.py` built a v1 environment that could not import a v2 server.
Both commands now pin the requirement to the version you are running
(`mcp==`). Source builds and other unpublished versions, which have
nothing on PyPI to pin to, keep the unpinned form.
diff --git a/docs/whats-new.md b/docs/whats-new.md
index 4ae0de2bcb..3b9e981178 100644
--- a/docs/whats-new.md
+++ b/docs/whats-new.md
@@ -4,13 +4,10 @@ Two things happened at once in v2. The **SDK was rebuilt**: a new engine under b
This page is the tour of both halves, one section per headline, each ending in the page that owns the topic. It is not the porting manual. That is the **[Migration Guide](migration.md)**: every breaking change, with before and after code.
-!!! note "v2 is a beta"
- `pip install mcp` still installs v1.x: you opt into v2 with an exact version pin, and the
- API can still move before the stable release, which lands alongside the spec release.
- **[Installation](get-started/installation.md)** has the copy-paste install line and the
- pinning rules. And if anything in v2 breaks, surprises, or slows you down,
- [tell us](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=v2-feedback.yaml):
- while v2 is in beta, that is the most useful thing you can send us.
+!!! note "v2 is the stable line"
+ `pip install mcp` installs 2.x, and **[Installation](get-started/installation.md)** has the
+ copy-paste install line. If anything in v2 breaks, surprises, or slows you down,
+ [tell us](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=v2-feedback.yaml).
## The SDK: v1 to v2
@@ -191,13 +188,13 @@ That file is the pitch in one place: one server, one `Resolve`-backed tool, and
### Change notifications become one stream
-At 2026-07-28 the standalone HTTP GET stream and `resources/subscribe` are replaced by `subscriptions/listen`: the client opens one long-lived stream and names the notification kinds it wants. `MCPServer` serves it out of the box; you publish with `await ctx.notify_resource_updated(uri)` (and `notify_tools_changed()`, and so on), and multi-replica deployments plug in a shared `SubscriptionBus`. On the client (since `2.0.0b2`), `async with client.listen(...)` opens the stream: the filter goes in as keyword arguments, typed change events come back, and `sub.honored` is the subset the server agreed to deliver.
+At 2026-07-28 the standalone HTTP GET stream and `resources/subscribe` are replaced by `subscriptions/listen`: the client opens one long-lived stream and names the notification kinds it wants. `MCPServer` serves it out of the box; you publish with `await ctx.notify_resource_updated(uri)` (and `notify_tools_changed()`, and so on), and multi-replica deployments plug in a shared `SubscriptionBus`. On the client, `async with client.listen(...)` opens the stream: the filter goes in as keyword arguments, typed change events come back, and `sub.honored` is the subset the server agreed to deliver.
**[Subscriptions](handlers/subscriptions.md)** covers publishing and serving, **[its Clients twin](client/subscriptions.md)** the watching end, and **[Deploy & scale](run/deploy.md)** the bus.
### The rest, quickly
-* **Identity is optional, per-message metadata.** The request-side `clientInfo` `_meta` key is optional (the required pair is `protocolVersion` + `clientCapabilities`), and `serverInfo` moved out of the `server/discover` result body: servers stamp it into every 2026-era result's `_meta` instead (since `2.0.0b3`; [spec #3002](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/3002)). The SDK always stamps; `client.server_info` is `None` when a server does not identify itself (for example, a middleware stripped the key). **[The low-level Server](advanced/low-level-server.md)** shows the stamp on the wire.
+* **Identity is optional, per-message metadata.** The request-side `clientInfo` `_meta` key is optional (the required pair is `protocolVersion` + `clientCapabilities`), and `serverInfo` moved out of the `server/discover` result body: servers stamp it into every 2026-era result's `_meta` instead ([spec #3002](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/3002)). The SDK always stamps; `client.server_info` is `None` when a server does not identify itself (for example, a middleware stripped the key). **[The low-level Server](advanced/low-level-server.md)** shows the stamp on the wire.
* **Requests are routable without parsing bodies.** Modern HTTP requests carry `Mcp-Method` (and, for the three tool-ish calls, `Mcp-Name`); a tool input-schema property annotated with `x-mcp-header` is mirrored into an `Mcp-Param-*` header and cross-checked by the server ([SEP-2243](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2243)). Gateways and rate limiters can route on headers alone; the **[Migration Guide](migration.md#servers-validate-mcp-param-headers-against-the-request-body-sep-2243)** has the rules.
* **Results carry cache hints.** List and read results declare `ttlMs` and `cacheScope` ([SEP-2549](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2549)); you set them per method with `cache_hints=`, and `Client` honors them with a built-in response cache. A server that sends no hints (every pre-2026 server) sees identical, uncached traffic. **[Caching hints](client/caching.md)**.
* **Extensions are first class.** Servers and clients declare optional capability bundles under reverse-DNS identifiers ([SEP-2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)); the built-in `Apps` extension (MCP Apps) is the reference. **[Extensions](advanced/extensions.md)** and **[MCP Apps](advanced/apps.md)**.
@@ -208,5 +205,5 @@ At 2026-07-28 the standalone HTTP GET stream and `resources/subscribe` are repla
## Upgrading from v1?
* The **[Migration Guide](migration.md)** is the complete, exact list of what to change; this page was the why.
-* **v1.x is not going anywhere.** It stays the stable line, with critical fixes and security patches, and nothing about the 2026-07-28 spec release breaks it. If you publish a library that depends on `mcp`, add an upper bound (for example `mcp>=1.27,<2`) so stable v2 does not surprise your users.
+* **v1.x is not going anywhere.** It moves to maintenance, keeps getting critical fixes and security patches, and nothing about the 2026-07-28 spec release breaks it; its docs live at [/v1/](https://py.sdk.modelcontextprotocol.io/v1/). If you publish a library that depends on `mcp` and are not ready to migrate, keep an upper bound (for example `mcp>=1.28,<2`) so an unpinned resolve stays on 1.x.
* Something rough, confusing, or broken? **[File v2 feedback](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=v2-feedback.yaml)**; it all gets read.