From c89a9820fc64de8befe99730a9feafeb354aad5f Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Tue, 25 Aug 2026 06:27:49 +0000 Subject: [PATCH] fix(release): serialize mcp-server-release.yml runs to prevent registry-publish races No concurrency group meant near-simultaneous pushes to a caller's main (e.g. two dependabot auto-merges seconds apart) could run this workflow twice in parallel, both detect the same releasable HEAD via the existing git-tag check, and race the MCP Registry publish step. Same mechanism confirmed live via meraki-mcp's legacy inline workflow (WYRE-AI/meraki-mcp#12, murph): 3 merges within 13s on 2026-08-21, 3 green Release runs, 3 failed "cannot publish duplicate version" 400s. Group is release-${{ github.repository }}-${{ github.ref }}. github.ref alone already fully serializes the actual bug (same-repo races) -- GitHub scopes concurrency groups per-repository automatically, even for a reusable workflow's own group declaration, so two different callers never queue against each other regardless of group-name string (verified against GitHub's docs + community discussion before writing this, after murph caught an incorrect cross-repo-collision claim in an earlier draft of this commit). github.repository is included purely for a self-documenting group name, not because it's required for correctness. cancel-in-progress: false is deliberate -- a queued run waits for the in-flight release/publish to finish rather than cancelling it mid-publish. --- .github/workflows/mcp-server-release.yml | 22 ++++++++++++++++++++++ CHANGELOG.md | 21 +++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/.github/workflows/mcp-server-release.yml b/.github/workflows/mcp-server-release.yml index 06d27b2..fd4d82c 100644 --- a/.github/workflows/mcp-server-release.yml +++ b/.github/workflows/mcp-server-release.yml @@ -160,6 +160,28 @@ on: description: 'Docker image digest (sha256:…). Empty when no release was cut.' value: ${{ jobs.docker.outputs.digest }} +# CONCURRENCY (2026-08-25, murph/forge): no group meant near-simultaneous +# pushes to a caller's main (e.g. two dependabot auto-merges seconds apart) +# could run this workflow twice in parallel, both detect the same releasable +# HEAD via the git-tag check above, and race the MCP Registry publish step — +# confirmed live via the identical mechanism in meraki-mcp's legacy inline +# workflow (WYRE-AI/meraki-mcp#12): 3 merges within 13s, 3 green Release runs, +# 3 failed "cannot publish duplicate version" 400s. github.ref alone already +# fully serializes this (same-repo, near-simultaneous pushes to main) — this +# is a REUSABLE workflow, but GitHub scopes a concurrency group per-repository +# automatically even for reusable workflows' own group declarations, so two +# different callers computing the identical literal group string never queue +# against each other (verified against GitHub's docs + community discussion +# #88761 before writing this, not assumed). `github.repository` is included +# anyway purely for a self-documenting group name in the Actions UI — it is +# not required for correctness and fixes no additional bug. +# +# cancel-in-progress: false is deliberate — a queued run should wait for the +# in-flight release/publish to finish, not cancel it mid-publish. +concurrency: + group: release-${{ github.repository }}-${{ github.ref }} + cancel-in-progress: false + jobs: # ──────────────────────────────────────────────────────────────────────────── # 0. verify — build/lint/test, UNCONDITIONAL (runs on every event this diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fb12c1..20b9ab8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,27 @@ here. The format is based on ### Fixed +- **`mcp-server-release.yml`**: added a workflow-level `concurrency` group. + No group meant near-simultaneous pushes to a caller's `main` (e.g. two + dependabot auto-merges seconds apart) could run this workflow twice in + parallel, both detect the same releasable HEAD via the existing git-tag + check, and race the MCP Registry publish step. Same mechanism confirmed + live via meraki-mcp's legacy inline workflow (`WYRE-AI/meraki-mcp#12`, + murph): 3 merges within 13s on 2026-08-21, 3 green Release runs, 3 failed + `cannot publish duplicate version` 400s. + + Group is `release-${{ github.repository }}-${{ github.ref }}`. + `github.ref` alone already fully serializes the actual bug (same-repo, + near-simultaneous pushes to main) — GitHub scopes concurrency groups + per-repository automatically, even for a reusable workflow's own group + declaration, so two different callers of this workflow computing the + identical literal group string never queue against each other (verified + against GitHub's docs + community discussion before writing this). + `github.repository` is included purely for a self-documenting group name + in the Actions UI, not because it's required for correctness. + `cancel-in-progress: false` is deliberate — a queued run waits for the + in-flight release/publish to finish rather than cancelling it mid-publish. + - **`mcp-server-release.yml`**: the `mcpb` job did not install the MCPB CLI, so it failed on 24 of the 26 repos with a `pack:mcpb` script. Pack scripts shell out to `npx mcpb pack`; only `autotask-mcp` and `blumira-mcp` carry