Skip to content
Merged
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
184 changes: 184 additions & 0 deletions .github/workflows/release-mcp-npm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
name: Release native MCP npm packages

on:
push:
tags:
- "mcp-npm-v*"

permissions:
contents: read

concurrency:
group: release-mcp-npm-${{ github.ref }}
cancel-in-progress: false

jobs:
metadata:
name: validate metadata
runs-on: ubuntu-24.04
outputs:
matrix: ${{ steps.metadata.outputs.matrix }}
version: ${{ steps.metadata.outputs.version }}

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Read release metadata
id: metadata
shell: bash
env:
RELEASE_TAG: ${{ github.ref_name }}
run: |
set -euo pipefail
node <<'NODE'
const fs = require('node:fs');
const manifest = fs.readFileSync('mcp/Cargo.toml', 'utf8');
const packageSection = manifest.match(/\[package\]([\s\S]*?)(?=\n\[|$)/);
const version = packageSection?.[1].match(/^version\s*=\s*"([^"]+)"\s*$/m)?.[1];
if (!version) throw new Error('could not read rustwright-mcp crate version');
const expectedTag = `mcp-npm-v${version}`;
if (process.env.RELEASE_TAG !== expectedTag) {
throw new Error(`tag ${process.env.RELEASE_TAG} does not match ${expectedTag}`);
}
const targets = JSON.parse(fs.readFileSync('mcp/npm/targets.json', 'utf8'));
if (targets.length !== 5) throw new Error(`expected 5 targets, found ${targets.length}`);
fs.appendFileSync(process.env.GITHUB_OUTPUT, `version=${version}\n`);
fs.appendFileSync(
process.env.GITHUB_OUTPUT,
`matrix=${JSON.stringify({ include: targets })}\n`,
);
NODE

- name: Validate main package generation
run: node mcp/npm/scripts/build-npm.mjs --main-only

build:
name: build ${{ matrix.id }}
needs: metadata
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.metadata.outputs.matrix) }}

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"

- name: Set up Rust target
shell: bash
run: rustup toolchain install 1.95.0 --profile minimal --target "${{ matrix.rustTarget }}"

- name: Set up Zig
if: ${{ matrix.zig }}
uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
with:
version: 0.14.1

- name: Install cargo-zigbuild
if: ${{ matrix.zig }}
uses: taiki-e/install-action@2ca9b94c269419b7b0c711c09d0b21c4e1d51145 # v2.83.1
with:
tool: cargo-zigbuild@0.23.0

- name: Build native MCP server
if: ${{ !matrix.zig }}
shell: bash
run: >-
cargo +1.95.0 build
--release
--target "${{ matrix.rustTarget }}"
--manifest-path mcp/Cargo.toml

- name: Build portable GNU/Linux MCP server
if: ${{ matrix.zig }}
shell: bash
run: >-
cargo +1.95.0 zigbuild
--release
--target "${{ matrix.zigTarget }}"
--manifest-path mcp/Cargo.toml

- name: Assemble platform package
shell: bash
run: |
set -euo pipefail
node mcp/npm/scripts/build-npm.mjs \
--target "${{ matrix.id }}" \
--binary "$GITHUB_WORKSPACE/mcp/target/${{ matrix.rustTarget }}/release/${{ matrix.binary }}"
mkdir -p "$RUNNER_TEMP/npm-dist"
npm pack "$GITHUB_WORKSPACE/mcp/npm/packages/${{ matrix.id }}" \
--pack-destination "$RUNNER_TEMP/npm-dist"

- name: Upload platform package
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: rustwright-mcp-${{ matrix.id }}-${{ needs.metadata.outputs.version }}
path: ${{ runner.temp }}/npm-dist/*.tgz
if-no-files-found: error

publish:
name: publish npm packages
needs: [metadata, build]
runs-on: ubuntu-24.04
environment:
name: npm
url: https://www.npmjs.com/package/rustwright-mcp
permissions:
contents: read
id-token: write

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"

- name: Download platform packages
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: rustwright-mcp-*-${{ needs.metadata.outputs.version }}
path: mcp/npm/release-packages
merge-multiple: true

- name: Validate release payload
shell: bash
run: |
set -euo pipefail
package_count="$(find mcp/npm/release-packages -type f -name '*.tgz' | wc -l | tr -d ' ')"
test "$package_count" = "5"
node mcp/npm/scripts/build-npm.mjs --main-only
test "$(node -p "require('./mcp/npm/main/package.json').version")" = \
"${{ needs.metadata.outputs.version }}"

- name: Select dist-tag from version
id: dist_tag
shell: bash
run: |
set -euo pipefail
version="${GITHUB_REF_NAME#mcp-npm-v}"
case "$version" in
*-*) tag=next ;;
*) tag=latest ;;
esac
echo "tag=$tag" >> "$GITHUB_OUTPUT"

- name: Publish platform packages, then main package
shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
while IFS= read -r package_archive; do
npm publish "$package_archive" --access public --provenance --tag "${{ steps.dist_tag.outputs.tag }}"
done < <(find mcp/npm/release-packages -type f -name '*.tgz' | sort)
npm publish mcp/npm/main --access public --provenance --tag "${{ steps.dist_tag.outputs.tag }}"
Loading