ci: deploy docs to py.sdk.modelcontextprotocol.io via Pages artifact (v1 at /, v2 at /v2/)#2634
Conversation
…tifact Build both v1.x and main into a single Pages artifact (v1 at /, v2 at /v2/), deployed via actions/deploy-pages on push to either branch. This fixes the 404 at the custom domain (which DNS already points at GitHub Pages but the repo never claimed) and stops the two branches from overwriting each other's docs on release. The legacy mkdocs gh-deploy path (docs-publish job in publish-pypi.yml and the manual workflow) is removed; the gh-pages branch can be deleted once the new deploy is confirmed working. Closes #2614. Supersedes #2615.
There was a problem hiding this comment.
Didn't spot any bugs in the workflow or build script, but this rewires the docs deployment pipeline (removing existing workflows, adding a new Pages artifact deploy, and requiring out-of-band Pages settings changes), so a maintainer should review and coordinate the manual steps.
Extended reasoning...
Overview
This PR replaces the mkdocs gh-deploy-based docs publishing (removing publish-docs-manually.yml and the docs-publish job in publish-pypi.yml) with a new deploy-docs.yml workflow that uses the GitHub Pages artifact deployment flow. It adds scripts/build-docs.sh, which uses git worktrees to build docs from both origin/v1.x (at /) and origin/main (at /v2/) into a single site directory. It also updates site_url in mkdocs.yml, adds a Documentation URL to pyproject.toml, adds a v2 admonition banner to docs/index.md, and ignores .worktrees/.
Security risks
The new workflow uses appropriately-scoped permissions (contents: read, pages: write, id-token: write) and pinned action SHAs, which is good. scripts/build-docs.sh runs uv sync and mkdocs build from a checkout of origin/v1.x inside a job triggered by a push to main (and vice versa) — this means code merged to one protected branch is executed in the workflow context of the other. Both are protected branches, so the risk is low, but it's a cross-branch trust boundary worth a maintainer being aware of. No injection or untrusted-input handling.
Level of scrutiny
This is a CI/CD pipeline change for a production-facing docs site. It removes existing publish workflows and depends on out-of-band repository settings changes (Pages source → GitHub Actions, custom domain) that must be made by a maintainer in the right order. CI/CD infrastructure changes generally warrant human sign-off, and the dependency on manual repo-settings steps means a bot approval would not be actionable on its own.
Other factors
The shell script is well-written: set -euo pipefail, a cleanup trap, defensive quoting (${OUTPUT_DIR:?}), and detached worktrees. The PR description is thorough and lists the required maintainer actions and a follow-up backport to v1.x. No automated bugs were flagged. The main design decision (always building both branches from origin tips so the output is order-independent) is sound, but it's the kind of choice a maintainer should explicitly endorse.
Deploys docs to
py.sdk.modelcontextprotocol.iovia GitHub Pages artifact deployment, building bothv1.xandmaininto a single site (v1 at/, v2 at/v2/). This mirrors the approach used by typescript-sdk.Closes #2614. Supersedes #2615 and #2632.
Motivation and Context
https://py.sdk.modelcontextprotocol.io/currently returns 404. DNS is correctly configured (the CNAME and verification TXT records exist in modelcontextprotocol/dns), but this repo's Pages config has never claimed the domain (cname: null, noCNAMEfile ongh-pages), so GitHub serves the org-level 404.Separately, the current
mkdocs gh-deploy --forcesetup runs identically on bothmainandv1.xand force-pushes to the samegh-pagesbranch — whichever branch released last overwrites the other's docs entirely. The first v2 release would silently replace the stable v1 docs.This PR fixes both: artifact-based deploy with the custom domain set in Pages settings (no CNAME file to lose), and a build script that always assembles both branches' docs into one site.
How Has This Been Tested?
Ran
scripts/build-docs.shlocally; confirmed v1.x content lands at/and main content at/v2/, bothmkdocs buildinvocations succeed understrict: true, and worktrees are cleaned up. The workflow itself can only be fully validated after merge + the Pages settings change (see below).Breaking Changes
None for users. The
modelcontextprotocol.github.io/python-sdk/URL will auto-redirect to the custom domain once it's set.Types of changes
Checklist
Additional context
Maintainer actions required
v1.xbackport [v1.x] ci: deploy docs to py.sdk.modelcontextprotocol.io via Pages artifact #2635. BothDeploy Docsruns will fail atconfigure-pagesbecause the Pages source is still "Deploy from a branch" — expected; the existinggh-pagescontent keeps serving in the meantime.py.sdk.modelcontextprotocol.io→ Save. DNS check should pass immediately (records already exist). Tick "Enforce HTTPS" once the cert provisions./and v2 at/v2/with correct canonical URLs.gh-pagesbranch and close Fix Issue #2614 - changed the publishing url for Python docs #2615.Merging both PRs before the settings flip means the first successful deploy reads the updated
site_urlfrom both branches; doing the flip first would work too but risks a brief 404 on the existinggithub.io/python-sdk/URL.Design notes
/v2/(not/dev/) so the path survives the v2.0 GA — when v2 ships, only the root redirect changes.cancel-in-progress: falseso an in-flight Pages deploy isn't cancelled by a closely-following push.paths:filter on the push trigger to avoid redeploying on unrelated changes;src/mcp/**is included because mkdocstrings introspects it for the API reference.mainandv1.xfor the push trigger to fire on each, butbuild-docs.shalways builds fromorigin/v1.x+origin/maintips, so output is identical regardless of which branch triggered.AI Disclaimer