From d6a15f6d5262e3697b6c10f259dd0690ac895e0b Mon Sep 17 00:00:00 2001
From: Max Isbey <224885523+maxisbey@users.noreply.github.com>
Date: Sat, 25 Jul 2026 23:49:57 +0000
Subject: [PATCH] [v1.x] Move the v1.x docs to /v1/ and mark v1.x as the
maintenance line
With v2 becoming the stable release, v1.x moves from the site root to
/v1/ and stops deploying the site itself: the combined site is built and
deployed from main, which builds this branch's docs into /v1/ via the
new scripts/docs/build.sh. A `docs` CI job runs that same script, so a
change that breaks the v1 docs fails on this branch rather than at
main's next deploy. site_url and the package's Documentation URL move to
/v1/ so canonical links, the sitemap, and llms.txt point at where these
pages are actually served.
The README and landing page now describe v1.x as the maintenance line
and send new users to the v2 docs, and every install line pins `mcp<2`
so a reader following these docs stays on the 1.x line now that an
unpinned install selects 2.x.
---
.github/workflows/deploy-docs.yml | 57 -----------------------
.github/workflows/shared.yml | 17 +++++++
README.md | 18 ++++----
docs/index.md | 12 +++--
docs/installation.md | 8 ++--
mkdocs.yml | 2 +-
pyproject.toml | 2 +-
scripts/build-docs.sh | 76 -------------------------------
scripts/docs/build.sh | 19 ++++++++
9 files changed, 58 insertions(+), 153 deletions(-)
delete mode 100644 .github/workflows/deploy-docs.yml
delete mode 100755 scripts/build-docs.sh
create mode 100755 scripts/docs/build.sh
diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml
deleted file mode 100644
index d9362afd57..0000000000
--- a/.github/workflows/deploy-docs.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-name: Deploy Docs
-
-on:
- push:
- branches:
- - main
- - v1.x
- paths:
- - docs/**
- - mkdocs.yml
- - src/mcp/**
- - scripts/build-docs.sh
- - pyproject.toml
- - uv.lock
- - .github/workflows/deploy-docs.yml
- workflow_dispatch:
-
-concurrency:
- group: deploy-docs
- cancel-in-progress: false
-
-jobs:
- deploy-docs:
- runs-on: ubuntu-latest
-
- permissions:
- contents: read
- pages: write
- id-token: write
-
- environment:
- name: github-pages
- url: ${{ steps.deployment.outputs.page_url }}
-
- steps:
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
-
- - name: Install uv
- uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
- with:
- enable-cache: true
- version: 0.9.5
-
- - name: Build combined docs (v1.x at /, main at /v2/)
- run: bash scripts/build-docs.sh site
-
- - name: Configure Pages
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
-
- - name: Upload Pages artifact
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
- with:
- path: site
-
- - name: Deploy to GitHub Pages
- id: deployment
- uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
diff --git a/.github/workflows/shared.yml b/.github/workflows/shared.yml
index 16ba250cde..468359fef4 100644
--- a/.github/workflows/shared.yml
+++ b/.github/workflows/shared.yml
@@ -76,3 +76,20 @@ jobs:
- name: Check doc snippets are up to date
run: uv run --frozen scripts/update_doc_snippets.py --check
+
+ # The published site is built and deployed from main, which builds this
+ # branch's docs (via scripts/docs/build.sh) under /v1/; this branch has no
+ # deploy workflow of its own. This job runs that same script so a change
+ # that breaks the v1 docs fails here rather than at main's next deploy.
+ docs:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
+
+ - uses: astral-sh/setup-uv@v7
+ with:
+ enable-cache: true
+ version: 0.9.5
+
+ - name: Build docs
+ run: bash scripts/docs/build.sh
diff --git a/README.md b/README.md
index 9eaef01af8..325060dfb1 100644
--- a/README.md
+++ b/README.md
@@ -13,11 +13,9 @@
-> **This documents v1.x, the stable release line of the MCP Python SDK. v2 is in alpha.**
+> **This documents v1.x, the maintenance line of the MCP Python SDK.** v2 is the current stable release: `pip install mcp` now installs 2.x. See the [v2 documentation](https://py.sdk.modelcontextprotocol.io/) and the [migration guide](https://py.sdk.modelcontextprotocol.io/migration/) for what changed and how to upgrade.
>
-> v2 pre-releases are published to PyPI as `2.0.0aN`. Installers never select a pre-release unless you opt in (for example `pip install mcp==2.0.0a1`), so v1.x users 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 v2 release lands.** See the [v2 documentation](https://github.com/modelcontextprotocol/python-sdk/blob/main/README.v2.md) and the [migration guide](https://github.com/modelcontextprotocol/python-sdk/blob/main/docs/migration.md) for what's changing.
->
-> v1.x remains recommended for production use. It is in maintenance mode and continues to receive critical bug fixes and security patches.
+> **Staying on v1.x?** Keep a `<2` upper bound on your requirement (for example `mcp>=1.28,<2`) so an unpinned resolve stays on the 1.x line. v1.x remains supported for existing deployments and continues to receive critical bug fixes and security patches; its documentation is at .
## Table of Contents
@@ -38,7 +36,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://modelcontextprotocol.github.io/python-sdk/
+[docs-url]: https://py.sdk.modelcontextprotocol.io/v1/
[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
@@ -69,13 +67,13 @@ If you haven't created a uv-managed project yet, create one:
Then add MCP to your project dependencies:
```bash
- uv add "mcp[cli]"
+ uv add "mcp[cli]<2"
```
Alternatively, for projects using pip for dependencies:
```bash
-pip install "mcp[cli]"
+pip install "mcp[cli]<2"
```
### Running the standalone MCP development tools
@@ -143,7 +141,7 @@ _Full example: [examples/snippets/servers/fastmcp_quickstart.py](https://github.
You can install this server in [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp) and interact with it right away. First, run the server:
```bash
-uv run --with mcp examples/snippets/servers/fastmcp_quickstart.py
+uv run --with "mcp<2" examples/snippets/servers/fastmcp_quickstart.py
```
Then add it to Claude Code:
@@ -177,8 +175,8 @@ The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you bui
- [Low-Level Server](docs/low-level-server.md) -- direct handler registration for advanced use cases
- [Protocol Features](docs/protocol.md) -- MCP primitives, server capabilities
- [Testing](docs/testing.md) -- in-memory transport testing with pytest
-- [API Reference](https://modelcontextprotocol.github.io/python-sdk/api/)
-- [Experimental Features (Tasks)](https://modelcontextprotocol.github.io/python-sdk/experimental/tasks/)
+- [API Reference](https://py.sdk.modelcontextprotocol.io/v1/api/)
+- [Experimental Features (Tasks)](https://py.sdk.modelcontextprotocol.io/v1/experimental/tasks/)
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
- [Model Context Protocol specification](https://modelcontextprotocol.io/specification/latest)
- [Officially supported servers](https://github.com/modelcontextprotocol/servers)
diff --git a/docs/index.md b/docs/index.md
index 8462445a60..c44891c137 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,7 +1,9 @@
# MCP Python SDK
-!!! tip "Looking for the upcoming v2?"
- See the [v2 development documentation](https://py.sdk.modelcontextprotocol.io/v2/).
+!!! tip "You are viewing the v1.x maintenance-line documentation"
+ v2 is the current stable release: its documentation is at
+ . Staying on v1.x for now? Pin `mcp<2`
+ (for example `mcp>=1.28,<2`) so an unpinned install doesn't move you to 2.x.
The **Model Context Protocol (MCP)** allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction.
@@ -48,7 +50,7 @@ if __name__ == "__main__":
Run the server:
```bash
-uv run --with mcp server.py
+uv run --with "mcp<2" server.py
```
Then open the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) and connect to `http://localhost:8000/mcp`:
@@ -74,5 +76,5 @@ Full API documentation is available in the [API Reference](api.md).
## llms.txt
Reading with an LLM? This documentation is also published in the [llms.txt](https://llmstxt.org/) format:
-[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.
+[llms.txt](https://py.sdk.modelcontextprotocol.io/v1/llms.txt) is an index of the pages, and
+[llms-full.txt](https://py.sdk.modelcontextprotocol.io/v1/llms-full.txt) contains every page in a single file.
diff --git a/docs/installation.md b/docs/installation.md
index 6e20706a84..2352a1132f 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -1,16 +1,18 @@
# Installation
-The Python SDK is available on PyPI as [`mcp`](https://pypi.org/project/mcp/) so installation is as simple as:
+The Python SDK is available on PyPI as [`mcp`](https://pypi.org/project/mcp/). These docs describe the **v1.x maintenance line**;
+the `<2` bound keeps you on it now that `pip install mcp` selects the 2.x stable release by default (the
+[v2 documentation](https://py.sdk.modelcontextprotocol.io/) covers that line):
=== "pip"
```bash
- pip install mcp
+ pip install "mcp<2"
```
=== "uv"
```bash
- uv add mcp
+ uv add "mcp<2"
```
The following dependencies are automatically installed:
diff --git a/mkdocs.yml b/mkdocs.yml
index f19a0ee3ee..684c4a1232 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -5,7 +5,7 @@ strict: true
repo_name: modelcontextprotocol/python-sdk
repo_url: https://github.com/modelcontextprotocol/python-sdk
edit_uri: edit/v1.x/docs/
-site_url: https://py.sdk.modelcontextprotocol.io/
+site_url: https://py.sdk.modelcontextprotocol.io/v1/
# TODO(Marcelo): Add Anthropic copyright?
# copyright: © Model Context Protocol 2025 to present
diff --git a/pyproject.toml b/pyproject.toml
index 9a4cf051ef..6bee7f4923 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -91,7 +91,7 @@ bump = true
[project.urls]
Homepage = "https://modelcontextprotocol.io"
-Documentation = "https://py.sdk.modelcontextprotocol.io/"
+Documentation = "https://py.sdk.modelcontextprotocol.io/v1/"
Repository = "https://github.com/modelcontextprotocol/python-sdk"
Issues = "https://github.com/modelcontextprotocol/python-sdk/issues"
diff --git a/scripts/build-docs.sh b/scripts/build-docs.sh
deleted file mode 100755
index 8286786091..0000000000
--- a/scripts/build-docs.sh
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env bash
-#
-# Build combined v1 + v2 documentation for GitHub Pages.
-#
-# v1 docs (from the v1.x branch) are placed at the site root.
-# v2 docs (from main) are placed under /v2/.
-#
-# The two lines use different toolchains: v1.x still builds with MkDocs, while
-# main builds with Zensical (which needs a pre-build step to materialise the API
-# reference and a post-build step for llms.txt — see scripts/docs/). Each branch
-# is fetched fresh from origin and built with its own synced `docs` group, so
-# the output is identical regardless of which branch triggered the workflow.
-# This script is intended to run in CI; for a local v2 preview use
-# `scripts/serve-docs.sh`.
-#
-# Usage:
-# scripts/build-docs.sh [output-dir]
-#
-# Default output directory: site
-#
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
-OUTPUT_DIR="$(cd "$REPO_ROOT" && mkdir -p "${1:-site}" && cd "${1:-site}" && pwd)"
-V1_WORKTREE="$REPO_ROOT/.worktrees/v1-docs"
-V2_WORKTREE="$REPO_ROOT/.worktrees/v2-docs"
-
-cleanup() {
- cd "$REPO_ROOT"
- git worktree remove --force "$V1_WORKTREE" 2>/dev/null || true
- git worktree remove --force "$V2_WORKTREE" 2>/dev/null || true
- rmdir "$REPO_ROOT/.worktrees" 2>/dev/null || true
-}
-trap cleanup EXIT
-
-# Build the checked-out worktree into its local `site/`, picking the toolchain
-# from the branch's own files rather than hard-coding it here: a branch that
-# ships the Zensical build recipe (scripts/docs/build.sh) builds with it,
-# otherwise it falls back to MkDocs. This keeps the combined build correct
-# regardless of which branch triggered it. Zensical requires site_dir to live
-# within the project root, so both paths build to the local `site/` and let
-# the caller copy it to its destination.
-build_site() {
- if [[ -f scripts/docs/build.sh ]]; then
- bash scripts/docs/build.sh
- else
- uv sync --frozen --group docs
- NO_MKDOCS_2_WARNING=1 uv run --frozen --no-sync mkdocs build --site-dir site
- fi
-}
-
-build_branch() {
- local branch="$1" worktree="$2" dest="$3"
-
- echo "=== Building docs for ${branch} ==="
- git fetch origin "$branch"
- git worktree remove --force "$worktree" 2>/dev/null || true
- rm -rf "$worktree"
- git worktree add --detach "$worktree" "origin/${branch}"
-
- (
- cd "$worktree"
- rm -rf site
- build_site
- mkdir -p "$dest"
- cp -a site/. "$dest/"
- )
-}
-
-rm -rf "${OUTPUT_DIR:?}"/*
-
-build_branch v1.x "$V1_WORKTREE" "$OUTPUT_DIR"
-build_branch main "$V2_WORKTREE" "$OUTPUT_DIR/v2"
-
-echo "=== Combined docs built at $OUTPUT_DIR ==="
diff --git a/scripts/docs/build.sh b/scripts/docs/build.sh
new file mode 100755
index 0000000000..6c5ab88f62
--- /dev/null
+++ b/scripts/docs/build.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+#
+# Build the v1.x documentation into ./site.
+#
+# This is the single build recipe for this branch's docs. The combined site
+# is assembled and deployed from main, which fetches this branch and runs this
+# script to build it under /v1/ (main's scripts/build-docs.sh picks
+# scripts/docs/build.sh from each branch it builds). The `docs` CI job on
+# this branch runs the same script, so what CI checks is what gets published.
+#
+# Usage:
+# scripts/docs/build.sh
+#
+set -euo pipefail
+
+cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+
+uv sync --frozen --group docs
+NO_MKDOCS_2_WARNING=1 uv run --frozen --no-sync mkdocs build --site-dir site