docs: add RELEASING.md documenting OIDC publishing and retry process
Describes how packages publish (release.yml + release environment, trusted publishing on npm and PyPI, no registry tokens, provenance), what a release run does, and how to recover from a failed publish leg (rerun --failed within the window, or ride the next release). Linked from the root README alongside the other maintainer docs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
This commit is contained in:
parent
f4c86ff964
commit
1c0fdc3063
2 changed files with 55 additions and 0 deletions
|
|
@ -145,6 +145,10 @@ See [ADDITIONAL.md](ADDITIONAL.md) for a curated list of frameworks and resource
|
||||||
|
|
||||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for information about contributing to this repository.
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for information about contributing to this repository.
|
||||||
|
|
||||||
|
## 📦 Releasing
|
||||||
|
|
||||||
|
See [RELEASING.md](RELEASING.md) for how packages are published (OIDC trusted publishing from CI — no registry tokens) and how to retry a failed publish.
|
||||||
|
|
||||||
## 🔒 Security
|
## 🔒 Security
|
||||||
|
|
||||||
See [SECURITY.md](SECURITY.md) for reporting security vulnerabilities.
|
See [SECURITY.md](SECURITY.md) for reporting security vulnerabilities.
|
||||||
|
|
|
||||||
51
RELEASING.md
Normal file
51
RELEASING.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# Releasing
|
||||||
|
|
||||||
|
How the packages in this repository are published, and what to do when a publish fails.
|
||||||
|
|
||||||
|
## How publishing works
|
||||||
|
|
||||||
|
All packages publish exclusively from the [`release.yml`](.github/workflows/release.yml) GitHub Actions workflow, gated by the `release` environment (a required reviewer must approve each deployment).
|
||||||
|
|
||||||
|
**Authentication is OIDC trusted publishing on both registries — there are no registry tokens.**
|
||||||
|
|
||||||
|
- **npm** (TypeScript servers): each `@modelcontextprotocol/*` package is registered on npmjs.com with a [trusted publisher](https://docs.npmjs.com/trusted-publishers) bound to this repository, workflow filename `release.yml`, and environment `release`. npm rejects publishes from any other workflow or environment — the binding is case-sensitive. Packages are published with [provenance attestations](https://docs.npmjs.com/generating-provenance-statements) (`NPM_CONFIG_PROVENANCE`).
|
||||||
|
- **PyPI** (Python servers): published via [PyPI trusted publishing](https://docs.pypi.org/trusted-publishers/) using `pypa/gh-action-pypi-publish`.
|
||||||
|
|
||||||
|
A release run:
|
||||||
|
|
||||||
|
1. **Detects changed packages** since the last release tag (a package counts as changed if any `.py`, `.ts`, or `.md` file in its directory changed — READMEs ship inside the published artifacts).
|
||||||
|
2. **Stamps versions and tags** — versions are date-based (CalVer, e.g. `2026.7.4`).
|
||||||
|
3. **Publishes each package as an independent matrix job** (`fail-fast: false` — one package's failure never blocks another): checkout at the release tag → install → *skip if this version already exists on the registry* → **run the package's tests** → build → publish.
|
||||||
|
4. **Creates the GitHub release** with generated notes.
|
||||||
|
|
||||||
|
Runs are triggered by a daily schedule or manually via **workflow_dispatch** on `release.yml`.
|
||||||
|
|
||||||
|
## When a publish fails
|
||||||
|
|
||||||
|
A failed matrix leg means that one package didn't publish; everything else that succeeded stays published (the version-exists guard makes retries idempotent).
|
||||||
|
|
||||||
|
**Preferred: re-run the failed jobs on the same run.**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh run rerun <run-id> --failed --repo modelcontextprotocol/servers
|
||||||
|
```
|
||||||
|
|
||||||
|
- A re-run is still a `release.yml` run in the `release` environment, so it satisfies the trusted-publisher binding.
|
||||||
|
- It re-runs only the failed legs, checked out at the original release tag — it publishes exactly the tagged code.
|
||||||
|
- It needs a fresh `release` environment approval, and the run must be complete first (approve or reject any pending deployments).
|
||||||
|
- GitHub's re-run window is ~30 days from the original run, and re-runs execute the *original* workflow snapshot — workflow fixes on main don't apply to a re-run (secrets and registry-side registrations are read fresh).
|
||||||
|
|
||||||
|
**Otherwise: let the next release pick it up.** If the re-run window has closed (or the fix required a workflow change), the failed version simply never exists on that registry — that's benign; npm and PyPI version histories don't need to match. The package publishes at the next version, provided it has a qualifying change since the last tag.
|
||||||
|
|
||||||
|
**Never:**
|
||||||
|
|
||||||
|
- Publish manually with an npm token or from a laptop — there are no registry tokens, and manual publishes would break the provenance/trust chain.
|
||||||
|
- Re-dispatch `release.yml` expecting it to retry a failed version — a fresh run mints a *new* version.
|
||||||
|
|
||||||
|
## Environment approvals
|
||||||
|
|
||||||
|
The `release` environment's required-reviewer list is configured in the repository settings (Settings → Environments → `release`). Reviewer rights come only from that list — repository admin does not confer deployment approval.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The release process is evolving — see [#4463](https://github.com/modelcontextprotocol/servers/issues/4463) for planned changes (manual GitHub-release triggering, semver via changesets for the TypeScript packages). This document describes the process as it works today and will be updated when that lands.
|
||||||
Loading…
Reference in a new issue