-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Present v2 as the stable release across the README, docs, and policies #3178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,18 +13,18 @@ | |
|
|
||
| </div> | ||
|
|
||
| > [!CAUTION] | ||
| > **This README documents v2 of the MCP Python SDK, currently a release candidate (`2.0.0rc1`); the stable v2 release is planned for 2026-07-28.** Do not use v2 in production yet. Pre-releases are published to PyPI as `2.0.0aN` / `2.0.0bN` / `2.0.0rcN`, and **a pre-release may still 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 <https://py.sdk.modelcontextprotocol.io/v1/>. 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). | ||
|
Check warning on line 21 in README.md
|
||
|
|
||
| ## Documentation | ||
|
|
||
| **The documentation lives at <https://py.sdk.modelcontextprotocol.io/v2/>.** | ||
| **The documentation lives at <https://py.sdk.modelcontextprotocol.io/>.** | ||
|
|
||
| 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/). | ||
|
Comment on lines
+25
to
+27
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 The /v2/ → root URL sweep missed three non-Markdown files: Extended reasoning...What was missed. This PR's stated purpose is that root doc links become the canonical v2 docs at the stable release, and it flips every
Why the pyproject entries are in scope for this PR. The PR description explains that it must merge last, right before the Concrete walk-through. (1) This PR merges as-is and Why nothing else catches it. The pre-commit README-snippets check and the strict docs build that the PR cites as testing only cover Markdown and docs sources — neither inspects Impact and fix. Nothing breaks functionally — the most likely outcome is a redirect or a merely inconsistent link — which is why this is a nit rather than blocking. But because the metadata is frozen at the tag, the fix is only cheap before tagging: update the two |
||
|
|
||
| ## What is MCP? | ||
|
|
||
|
|
@@ -41,10 +41,10 @@ | |
| ## Installation | ||
|
|
||
| ```bash | ||
| uv add "mcp[cli]==2.0.0rc1" # or: pip install "mcp[cli]==2.0.0rc1" | ||
| 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.0rc1"` 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 @@ | |
|
|
||
| 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 @@ | |
| [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 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,17 +23,12 @@ | |
| Every host below gets the same command: | ||
|
|
||
| ```bash | ||
| uv run --with "mcp[cli]==2.0.0rc1" 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 a release candidate, 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 @@ | |
| "run", | ||
| "--frozen", | ||
| "--with", | ||
| "mcp[cli]==2.0.0rc1", | ||
| "mcp[cli]==2.0.0", | ||
| "mcp", | ||
| "run", | ||
| "/absolute/path/to/server.py" | ||
|
|
@@ -84,12 +79,12 @@ | |
| } | ||
| ``` | ||
|
|
||
| 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 @@ | |
| 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.0rc1" 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 @@ | |
| "mcpServers": { | ||
| "bookshop": { | ||
| "command": "uv", | ||
| "args": ["run", "--with", "mcp[cli]==2.0.0rc1", "mcp", "run", "/absolute/path/to/server.py"] | ||
| "args": ["run", "--with", "mcp[cli]", "mcp", "run", "/absolute/path/to/server.py"] | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -139,7 +134,7 @@ | |
| "bookshop": { | ||
| "type": "stdio", | ||
| "command": "uv", | ||
| "args": ["run", "--with", "mcp[cli]==2.0.0rc1", "mcp", "run", "/absolute/path/to/server.py"] | ||
| "args": ["run", "--with", "mcp[cli]", "mcp", "run", "/absolute/path/to/server.py"] | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -156,7 +151,7 @@ | |
| Before you touch any host config, run the launch command yourself: | ||
|
|
||
| ```bash | ||
| uv run --with "mcp[cli]==2.0.0rc1" 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,8 +169,8 @@ | |
| ## 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.0rc1" mcp run /absolute/path/to/server.py`: version-pinned, no venv to activate, works from any directory. The pin is mandatory while v2 is pre-release. | ||
| * 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. | ||
|
Check warning on line 173 in docs/get-started/real-host.md
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 The Recap bullet still says Extended reasoning...What the bug is. The Recap bullet at Why this is PR-introduced, not pre-existing. Before this PR, "that same command" was the pinned command ( Why it contradicts the page's own body. The PR demonstrably swept this exact sentence pattern in the two parallel body sentences: "The launch command" section now ends "...so what you type by hand and what the tool generates agree, apart from the exact version pin the tool adds", and the Claude Desktop section was changed from "two additions" to "three additions: the absolute path to Step-by-step proof.
One refutation angle considered: the Recap already omitted How to fix. One-clause edit mirroring the body's caveat, e.g.: "It writes that same command (plus the absolute path to Severity. Nit: prose-only docs inconsistency, nothing breaks, and the docs site rebuilds from |
||
| * **Claude Code** is `claude mcp add bookshop -- <launch command>`. **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. | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 The rewritten admonition uses GitHub alert syntax (
> [!NOTE]), which PyPI's renderer (readme_renderer, which does not enable the alerts extension) doesn't support — the 2.0.0 PyPI long description will open with the literal text "[!NOTE]" as the first visible line of the blockquote. Since this PR merges last precisely because README.md at the tag becomes the immutable PyPI long description, this is the last cheap moment to fix it: drop the[!NOTE]marker line (a plain blockquote renders fine on both GitHub and PyPI) or switch to a construct PyPI renders.Extended reasoning...
What the bug is. The rewritten top admonition (README.md lines 16–21) is a GitHub alert: a blockquote whose first line is
> [!NOTE]. Alert syntax ([!NOTE],[!CAUTION], …) is a GitHub-app-layer extension, not part of the GFM spec, and PyPI's renderer does not implement it. Becausepyproject.tomlsetsreadme = "README.md"(content typetext/markdown), PyPI renders the long description viareadme_renderer— and that pipeline passes the marker through as literal text.Verified empirically, not from documentation. Rendering this PR's README with the workspace's readme_renderer 45.0 wheel via
readme_renderer.markdown.render(text, variant='GFM')— the exact code path warehouse uses — produces output that begins:The root cause is a renderer-config fact: readme_renderer 45.0 configures its comrak backend with
autolink/footnotes/header_ids/strikethrough/table/tagfilter/tasklist, but never enables comrak'salertsextension (which exists — so this is definitively a disabled feature, not an unsupported one that might quietly work). The marker line therefore survives as visible junk text at the top of the rendered page.Why this is in scope for this PR, not merely pre-existing. The old README used
> [!CAUTION]through the same mechanism, so pre-release PyPI pages (2.0.0rc1 etc.) already show a literal marker — but those pages are throwaway. This PR rewrites these exact lines, and its entire stated reason for merging last, right before thev2.0.0tag, is that "README.md at the tagged commit is the PyPI long description." That makes this PR the artifact whose output becomes the permanent front page of the stable 2.0.0 release — and the last cheap moment to fix it, by the PR's own tagged-artifact reasoning (the same reasoning already applied to the /v2/ sidebar-URL finding).Why existing checks don't catch it. The pre-commit README check only syncs
docs_src/snippets; the strict mkdocs build doesn't render README.md at all (it isn't a docs page); andtwine check-style validation only requires the markdown to render without error — literal[!NOTE]text renders fine, it just looks wrong.Step-by-step proof of the trigger.
v2.0.0is tagged at that commit.text/markdownlong description.[!NOTE]line survives as text inside a plain<blockquote>.How to fix. One line, pre-tag: delete the
> [!NOTE]marker line so the block is a plain blockquote — it renders acceptably on both GitHub and PyPI, losing only GitHub's colored NOTE styling. (Alternatively, keep the alert on GitHub and strip it at build time, but that machinery isn't worth it for one admonition.)Severity. Nit: purely cosmetic, nothing breaks, twine check and the docs build both pass — but the blemish is permanent on the release's highest-visibility artifact, and only this PR can still fix it cheaply.