Skip to content

Stable release

Stable release #40

name: Stable release
on:
# Trigger a stable version release via GitHub's UI, with the ability to specify the type of release.
workflow_dispatch:
inputs:
release_type:
description: Release type
required: true
type: choice
default: auto
options:
- auto
- custom
- patch
- minor
- major
custom_version:
description: The custom version to bump to (only for "custom" type)
required: false
type: string
default: ""
permissions:
id-token: write
contents: write
actions: write
concurrency:
group: release
cancel-in-progress: false
jobs:
release_metadata:
name: Update release metadata
uses: ./.github/workflows/_update_release_metadata.yaml
secrets: inherit
with:
release_type: ${{ inputs.release_type }}
custom_version: ${{ inputs.custom_version }}
build_mcpb:
name: Build MCPB package
needs: [release_metadata]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ needs.release_metadata.outputs.changelog_commitish }}
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
- name: Install pnpm and dependencies
uses: apify/actions/pnpm-install@v1.1.2
- name: Build module
run: pnpm run build
- name: Prepare MCPB package
# `pnpm deploy` (modern, non-`--legacy`) builds a self-contained deployment dir:
# production-only deps, a flat (hoisted) node_modules. Modern deploy also derives
# a dedicated lockfile from the workspace lockfile, which keeps the supply-chain
# check (blockExoticSubdeps) from re-resolving and tripping on transitive deps.
# `dist`, `manifest.json`, README/LICENSE land via the npm `files` field — only
# `docs/` and the icon copy still need an explicit cp.
run: |
pnpm --filter=@apify/actors-mcp-server deploy --prod --node-linker=hoisted mcpb
cp -r docs mcpb/docs
cp docs/apify-logo-claude-desktop.png mcpb/icon.png
# `pnpm dlx` instead of `npx` because devEngines.packageManager is
# pinned to pnpm with onFail: error — npx invokes npm, which is rejected
# with EBADDEVENGINES at the repo root. Pinned mcpb version preserved
# for reproducible builds.
- name: Validate MCPB manifest
run: pnpm dlx @anthropic-ai/mcpb@2.1.2 validate mcpb/manifest.json
- name: Create MCPB package
run: pnpm dlx @anthropic-ai/mcpb@2.1.2 pack mcpb/ apify-mcp-server.mcpb
- name: Upload MCPB artifacts
uses: actions/upload-artifact@v4
with:
name: mcpb-packages
path: apify-mcp-server.mcpb
smoke_test_mcpb:
name: Smoke test MCPB package
needs: [build_mcpb]
uses: ./.github/workflows/_smoke_test_mcpb.yaml
create_github_release:
name: Create github release
needs: [release_metadata, build_mcpb, smoke_test_mcpb]
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Download MCPB artifacts
uses: actions/download-artifact@v4
with:
name: mcpb-packages
- name: Create release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.release_metadata.outputs.tag_name }}
name: ${{ needs.release_metadata.outputs.version_number }}
target_commitish: ${{ needs.release_metadata.outputs.changelog_commitish }}
body: ${{ needs.release_metadata.outputs.release_notes }}
files: apify-mcp-server.mcpb
publish_to_npm:
name: Publish to NPM
needs: [ release_metadata ]
runs-on: ubuntu-latest
steps:
- name: Execute publish workflow
uses: apify/actions/execute-workflow@v1.1.2
with:
workflow: manual_publish_to_npm.yaml
inputs: >
{
"ref": "${{ needs.release_metadata.outputs.changelog_commitish }}",
"tag": "latest"
}
smoke_test:
name: Smoke test published package
needs: [ release_metadata, publish_to_npm ]
uses: ./.github/workflows/_smoke_test_npm_package.yaml
with:
version: ${{ needs.release_metadata.outputs.version_number }}
bump_dependency_in_internal_repo:
name: Bump dependency in apify-mcp-server-internal
needs: [ release_metadata, publish_to_npm ]
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
steps:
- name: Checkout internal repo
uses: actions/checkout@v6
with:
repository: apify/apify-mcp-server-internal
token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
- name: Resolve pnpm version from internal repo
# Read the version from the internal repo's devEngines so this job
# tracks the source of truth instead of carrying a hardcoded duplicate.
# `jq -e` exits non-zero if the key is missing, so a structure change
# in the internal repo's package.json fails this step loudly.
id: pnpm-version
run: |
version=$(jq -er '.devEngines.packageManager.version' package.json)
echo "version=$version" >> "$GITHUB_OUTPUT"
- name: Install pnpm
# v6 is the first major running on Node 24 (matches `.nvmrc`).
# Exact patch pin (vs. floating `v6`) sidesteps the unmarked
# pre-releases in the v6 line (pnpm/action-setup#236) and lets
# newer patches age 14 days before adoption.
uses: pnpm/action-setup@v6.0.5
with:
version: ${{ steps.pnpm-version.outputs.version }}
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'pnpm'
cache-dependency-path: 'pnpm-lock.yaml'
# The internal repo pins `devEngines.packageManager` (onFail: error),
# so npm refuses to run inside the checkout. setup-node still calls
# `npm config get cache` for env diagnostics — NPM_CONFIG_FORCE
# (== `--force`) is the only documented bypass (npm/rfcs#830).
# Scoped to this step; install work below uses pnpm.
env:
NPM_CONFIG_FORCE: 'true'
- name: Configure GitHub Packages auth
run: pnpm config set //npm.pkg.github.com/:_authToken ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
- name: Install updated dependency
uses: nick-fields/retry@v3 # Retry to compensate for npm registry propagation lag
with:
timeout_minutes: 10
max_attempts: 3
retry_wait_seconds: 30
command: pnpm add --save-exact @apify/actors-mcp-server@${{ needs.release_metadata.outputs.version_number }}
- name: Commit dependency bump
id: commit
uses: apify/actions/signed-commit@v1.0.0
with:
message: "chore: bump @apify/actors-mcp-server to ${{ needs.release_metadata.outputs.version_number }}"
github-token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
repository: apify/apify-mcp-server-internal
branch: "release/${{ needs.release_metadata.outputs.tag_name }}"
create-branch: 'true'
- name: Create pull request
if: steps.commit.outputs.committed == 'true'
run: |
gh pr create \
--repo apify/apify-mcp-server-internal \
--head "release/${{ needs.release_metadata.outputs.tag_name }}" \
--title "chore: bump @apify/actors-mcp-server to ${{ needs.release_metadata.outputs.version_number }}" \
--body "$BODY" \
--reviewer "${{ github.actor }}"
env:
GH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
BODY: |
Automated PR to bump `@apify/actors-mcp-server` to `${{ needs.release_metadata.outputs.version_number }}`.
## Release notes
${{ needs.release_metadata.outputs.release_notes }}
publish_to_mcp_registry:
name: Publish to MCP Registry
needs: [ release_metadata ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ needs.release_metadata.outputs.changelog_commitish }}
- name: Install mcp-publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
sudo mv mcp-publisher /usr/local/bin/
- name: Login to MCP Registry
env:
MCP_REGISTRY_PUBLISH_SECRET: ${{ secrets.MCP_REGISTRY_PUBLISH_SECRET }}
run: |
set +x
mcp-publisher login dns --domain "apify.com" --private-key "${MCP_REGISTRY_PUBLISH_SECRET}"
- name: Publish to MCP Registry
run: mcp-publisher publish