Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,25 @@ gh workflow run prepare-python-release.yml --repo modelcontextprotocol/servers \
It opens a PR that starts with `Closes #N`, on a branch named
`v2/chore/<N>-python-calver-<date>`, labeled `v2`, and dispatches the
TypeScript, Python and DCO workflows on that branch, as the Version Packages
workflow does (not the Everything diff, whose paths it never touches). Wait
for its three `(dispatched)` statuses to pass, check that each stamped package really
changed, and a maintainer merges it.
workflow does (not the Everything diff, whose paths it never touches).
No PR means no Python server has a shipped change since its last stamp.

Then, on the PR:

1. **Link it to the release issue.** Its `Closes #N` is only a
cross-reference on `v2/main`, and the workflow makes no API call, so link
it with the `addCloseIssueReferences` mutation from `/pr-flow` (step 6)
and read it back: `closingIssuesReferences` must list `#N`. On `v2/main`
Comment on lines +264 to +267

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed (PR body edited; no code change). The body was overwritten by another session's draft for #5334 before the PR was opened: the agents shared a scratch file. The body now starts Closes #5335 and describes this release-documentation change. The API link was always to #5335 only (closingIssuesReferences reads [5335]), so nothing here was recorded against #5334.

it closes nothing at merge. Find the PR by its branch:

```sh
gh pr list --repo modelcontextprotocol/servers --base v2/main \
--json number,headRefName,url \
| jq --arg p "v2/chore/$N-python-calver-" '.[] | select(.headRefName | startswith($p))'
```
2. **Wait for its three `(dispatched)` statuses to pass**, check that each
stamped package really changed, and a maintainer merges it.

⚠️ GitHub only dispatches a workflow that exists on the default branch. Until
the first milestone merge carries this one to `main`, do it by hand, which is
the same script:
Expand All @@ -274,7 +288,9 @@ node scripts/prepare-python-release.mjs # prints "name: old -> new" per stam
git commit -s -am "chore: stamp Python CalVer versions for $(date -u +%Y.%-m.%-d)"
```

then open the PR through `/pr-flow`, body starting `Closes #N`.
then open the PR through `/pr-flow`, body starting `Closes #N`. Its step 6
links the PR to the release issue and reads the link back, as step 1 above
does for the workflow's PR: do not skip it.

## 3. The merge PR: `v2/main` → `main`

Expand Down
4 changes: 2 additions & 2 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ node scripts/prepare-python-release.mjs # prints one "name: old -> new" line
### PRs opened by these workflows

> [!NOTE]
> Both workflows push their PR's branch with the workflow token, and a push made with that token starts no workflow, so each one then dispatches the TypeScript, Python and DCO workflows on that branch, and Version Packages the Everything diff too (`workflow_dispatch` is the one event the token can start; the Python stamps touch nothing the diff runs on). A PR does not list dispatched checks, so each dispatched run also reports itself on the PR's head commit as a status: `TypeScript (dispatched)`, `Python (dispatched)` and `DCO (dispatched)`, plus `Everything diff (dispatched)` on Version Packages; wait for them to pass before merging. Closing and reopening the PR does not start the CI workflows: that fires `pull_request`, and those run on `push`. The token's `pull_request` events do not run DCO or the diff either: GitHub holds those runs as `action_required` (#5173), so the PR may also list them as pending or failed with no jobs; the `(dispatched)` statuses are the results. To run one again by hand: `gh workflow run typescript.yml --ref <branch>` (or `python.yml`, `dco.yml`, `everything-mcp-diff.yml`). The Version Packages PR's body is rewritten on every push to `v2/main`, so it is linked to the release issue with `addCloseIssueReferences` (which lives outside the body), carries a `Part of #N` comment as its textual record, and gets `Part of #N` as its body's first line only immediately before it is merged. The repository setting **Settings → Actions → General → Allow GitHub Actions to create and approve pull requests** must be on, or the workflows fail at the step that opens the PR.
> Both workflows push their PR's branch with the workflow token, and a push made with that token starts no workflow, so each one then dispatches the TypeScript, Python and DCO workflows on that branch, and Version Packages the Everything diff too (`workflow_dispatch` is the one event the token can start; the Python stamps touch nothing the diff runs on). A PR does not list dispatched checks, so each dispatched run also reports itself on the PR's head commit as a status: `TypeScript (dispatched)`, `Python (dispatched)` and `DCO (dispatched)`, plus `Everything diff (dispatched)` on Version Packages; wait for them to pass before merging. Closing and reopening the PR does not start the CI workflows: that fires `pull_request`, and those run on `push`. The token's `pull_request` events do not run DCO or the diff either: GitHub holds those runs as `action_required` (#5173), so the PR may also list them as pending or failed with no jobs; the `(dispatched)` statuses are the results. To run one again by hand: `gh workflow run typescript.yml --ref <branch>` (or `python.yml`, `dco.yml`, `everything-mcp-diff.yml`). The Version Packages PR's body is rewritten on every push to `v2/main`, so it is linked to the release issue with `addCloseIssueReferences` (which lives outside the body), carries a `Part of #N` comment as its textual record, and gets `Part of #N` as its body's first line only immediately before it is merged. The Prepare Python Release PR keeps its `Closes #N` line and is linked to the release issue with `addCloseIssueReferences` too, as every PR into `v2/main` is. The repository setting **Settings → Actions → General → Allow GitHub Actions to create and approve pull requests** must be on, or the workflows fail at the step that opens the PR.

## How publishing works

Expand Down Expand Up @@ -78,7 +78,7 @@ A release ships one **milestone**. The step-by-step procedure, with its commands
2. **Preparation PRs land on `v2/main`**, each starting with `Closes #<release issue>`:
- the **audit** (`npm audit`, and `pip-audit` over each Python server's locked requirements): the report goes on the release issue, and any fix it forces is its own commit in a PR;
- the **Version Packages** PR (TypeScript), which is linked to the release issue with `addCloseIssueReferences` and a `Part of #N` comment, and gets `Part of #N` as its body's first line just before merging, because the changesets action rewrites its body on every push;
- the **Prepare Python Release** PR (Python).
- the **Prepare Python Release** PR (Python), which keeps its `Closes #N` line and is also linked to the release issue with `addCloseIssueReferences`, since on `v2/main` a closing keyword is only a cross-reference.

A milestone that touches both languages and needs an audit fix has all three. They are merged before the next step starts.
3. **The merge PR** takes `v2/main` into `main`. It is a pure merge: its branch is `origin/v2/main` with no commits of its own, and the merged tree equals `origin/v2/main`'s. Its body starts with `Part of #<release issue>`, not `Closes`, because `main` is the default branch and a closing keyword there would close the issue before anything is published. It is merged with a merge commit, never squashed.
Expand Down
Loading