name: Publish to MCP Registry on: push: tags: ["v*"] jobs: publish: runs-on: ubuntu-latest permissions: id-token: write # npm trusted publishing AND mcp-publisher OIDC contents: read steps: - name: Checkout code uses: actions/checkout@v5 - name: Set up Node.js uses: actions/setup-node@v5 with: node-version-file: .nvmrc registry-url: https://registry.npmjs.org package-manager-cache: false - name: Upgrade npm for trusted publishing # Node 22 ships npm 10.x; trusted publishing needs >= 11.5.1. # Pinned, not `npm@latest`: npm 12 requires Node >= 22.22.2 and would # fail against the Node pinned in .nvmrc. Bump both together, or this # pin alone when a newer npm 11.x is wanted. run: npm install -g npm@11.19.0 - name: Install dependencies run: npm ci - name: Lint run: npm run lint - name: Run tests run: npm run test:precommit - name: Build run: npm run build - name: Assert release metadata is consistent run: node scripts/assert-release-consistency.mjs "${GITHUB_REF_NAME}" # mcp-publisher release version. Bump periodically; see # https://github.com/modelcontextprotocol/registry/releases - name: Install mcp-publisher env: MCP_PUBLISHER_VERSION: v1.8.1 run: | # The default run: shell is `bash -e`, which does NOT set pipefail — # set it explicitly so a failed grep cannot feed empty input forward. set -euo pipefail OS="$(uname -s | tr '[:upper:]' '[:lower:]')" ARCH="$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')" ASSET="mcp-publisher_${OS}_${ARCH}.tar.gz" CHECKSUMS="registry_${MCP_PUBLISHER_VERSION#v}_checksums.txt" BASE_URL="https://github.com/modelcontextprotocol/registry/releases/download/${MCP_PUBLISHER_VERSION}" curl --fail --silent --show-error --location -O "${BASE_URL}/${ASSET}" curl --fail --silent --show-error --location -O "${BASE_URL}/${CHECKSUMS}" awk -v asset="${ASSET}" '$2 == asset' "${CHECKSUMS}" | sha256sum --check --strict tar xzf "${ASSET}" mcp-publisher - name: Validate server.json run: ./mcp-publisher validate - name: Publish package to npm run: | VERSION="$(node -p "require('./package.json').version")" if npm view "mcp-open-library@${VERSION}" version >/dev/null 2>&1; then echo "mcp-open-library@${VERSION} is already on npm, skipping publish." else npm publish fi - name: Wait for npm to serve the new version run: | VERSION="$(node -p "require('./package.json').version")" for attempt in $(seq 1 12); do if npm view "mcp-open-library@${VERSION}" version >/dev/null 2>&1; then echo "mcp-open-library@${VERSION} is visible on npm." exit 0 fi echo "Attempt ${attempt}/12: not visible yet, retrying in 5s..." sleep 5 done echo "Timed out waiting for mcp-open-library@${VERSION} to appear on npm." >&2 exit 1 - name: Authenticate to MCP Registry run: ./mcp-publisher login github-oidc - name: Publish server to MCP Registry run: ./mcp-publisher publish # Deliberately a separate job: creating a Release needs `contents: write`, # and the publish job above should not hold repo write access alongside its # npm and registry publishing rights. This job runs only if publishing # succeeded, and a failure here leaves the actual release intact. github-release: needs: publish runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout code uses: actions/checkout@v5 - name: Create GitHub Release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -euo pipefail VERSION="${GITHUB_REF_NAME#v}" # Pull this version's section out of the changelog: everything after # its heading, up to the next `## [` heading. awk -v v="## [${VERSION}]" ' index($0, v) == 1 { capture = 1; next } capture && /^## \[/ { exit } capture { print } ' CHANGELOG.md > release-notes.md if [ -s release-notes.md ]; then gh release create "${GITHUB_REF_NAME}" \ --title "${GITHUB_REF_NAME}" \ --notes-file release-notes.md else echo "No CHANGELOG section for ${VERSION}; falling back to generated notes." >&2 gh release create "${GITHUB_REF_NAME}" \ --title "${GITHUB_REF_NAME}" \ --generate-notes fi