diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..887b242 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,98 @@ +name: Release + +# Phase-6 publish workflow per AI-discoverability-plan.md §7 Phase 6. +# Fires on a v* tag push. Three artifacts ship in order: +# 1. The wheel is attached to the GitHub Release (Phase-4 path; backup +# install channel for environments that can't reach PyPI). +# 2. The same wheel is published to PyPI under the `m-dev-tools-mcp` +# name via Trusted Publisher OIDC (no stored token). +# 3. The MCP registry record at registry.modelcontextprotocol.io is +# updated via `mcp-publisher` with GitHub OIDC auth. +# +# Manual prereqs the maintainer must do once: +# * PyPI: configure m-dev-tools-mcp as a Trusted Publisher pointing +# at this workflow (PyPI project settings → Publishing). +# * MCP registry: nothing — first publish auto-claims the +# io.github.m-dev-tools/* namespace via the GitHub OIDC token. + +on: + push: + tags: + - 'v*' + +permissions: + contents: write # GitHub Release creation + id-token: write # PyPI Trusted Publisher + mcp-publisher OIDC + +jobs: + release: + runs-on: ubuntu-latest + environment: release + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install build deps + run: pip install --upgrade pip build + + - name: Build wheel + run: python -m build --wheel + + - name: Create GitHub Release with wheel attached + # `gh release create` is idempotent on already-existing tags + # (re-running fails harmlessly), so a manual run won't clobber + # a previously cut release. + run: | + gh release create "${GITHUB_REF_NAME}" \ + dist/*.whl \ + --title "${GITHUB_REF_NAME}" \ + --generate-notes + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish to PyPI (Trusted Publisher OIDC) + uses: pypa/gh-action-pypi-publish@release/v1 + # No password / API token — Trusted Publisher uses the + # `id-token: write` permission to mint an OIDC token PyPI + # exchanges for a short-lived publish credential. Configured + # once on PyPI's side. + + - name: Install mcp-publisher + # Pulled fresh on every release; the CLI is small (single Go + # binary). Homebrew/apt are out of the question on the + # GitHub-Actions runner. + run: | + curl -L --fail \ + "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz" \ + | tar -xz mcp-publisher + chmod +x mcp-publisher + ./mcp-publisher --help + + - name: Update server.json version to match the tag + # server.json's `version` and `packages[0].version` are pinned + # to the release tag at publish time. The committed copy is a + # template; CI rewrites both fields before mcp-publisher + # publish. + run: | + tag="${GITHUB_REF_NAME#v}" + python3 - <