name: Publish to MCP Registry
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version tag to publish (e.g., v1.4.0)'
required: true
type: string
permissions:
contents: read
id-token: write
jobs:
publish-npm:
runs-on: ubuntu-latest
outputs:
should_publish: ${{ steps.check.outputs.should_publish }}
package_version: ${{ steps.extract.outputs.version }}
steps:
- name: Determine version
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
else
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
fi
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ steps.version.outputs.version }}
- name: Extract package version
id: extract
run: |
PKG_VERSION=$(jq -r '.version' package.json)
SERVER_VERSION=$(jq -r '.version' server.json)
TAG_VERSION="${{ steps.version.outputs.version }}"
TAG_VERSION_STRIPPED="${TAG_VERSION#v}"
echo "version=$PKG_VERSION" >> $GITHUB_OUTPUT
# Validate versions match
if [ "$PKG_VERSION" != "$SERVER_VERSION" ]; then
echo "::error::Version mismatch: package.json=$PKG_VERSION, server.json=$SERVER_VERSION"
exit 1
fi
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "$PKG_VERSION" != "$TAG_VERSION_STRIPPED" ]; then
echo "::error::Version mismatch: package.json=$PKG_VERSION, input tag=$TAG_VERSION_STRIPPED"
exit 1
fi
- name: Check if package exists on npm
id: check
run: |
VERSION="${{ steps.extract.outputs.version }}"
# Keep npm for registry queries
if npm view "attio-mcp@$VERSION" version &>/dev/null; then
echo "should_publish=false" >> $GITHUB_OUTPUT
echo "::notice::Package attio-mcp@$VERSION already exists on npm, skipping publish"
else
echo "should_publish=true" >> $GITHUB_OUTPUT
echo "::notice::Package attio-mcp@$VERSION not found on npm, will publish"
fi
- name: Setup Bun
if: steps.check.outputs.should_publish == 'true'
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Setup Node.js
if: steps.check.outputs.should_publish == 'true'
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
if: steps.check.outputs.should_publish == 'true'
run: bun install --frozen-lockfile
- name: Run tests
if: steps.check.outputs.should_publish == 'true'
run: bun run test:offline
- name: Build package
if: steps.check.outputs.should_publish == 'true'
run: bun run build
- name: Publish to NPM
if: steps.check.outputs.should_publish == 'true'
# Keep npm for publishing to npm registry
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-registry:
needs: publish-npm
runs-on: ubuntu-latest
steps:
- name: Determine version
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
else
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
fi
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ steps.version.outputs.version }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install MCP Publisher CLI
run: |
# Use latest to avoid schema version drift
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
chmod +x mcp-publisher
./mcp-publisher --version
- name: Validate server.json schema
run: |
# Get schema version from server.json
SCHEMA_URL=$(jq -r '."$schema"' server.json)
echo "Validating against schema: $SCHEMA_URL"
curl -s -o /tmp/server.schema.json "$SCHEMA_URL"
npx ajv-cli validate \
-s /tmp/server.schema.json \
-d server.json \
--strict=false
- name: Authenticate with GitHub OIDC
run: ./mcp-publisher login github-oidc
- name: Publish to MCP Registry
run: ./mcp-publisher publish
- name: Verify publication
run: |
VERSION="${{ needs.publish-npm.outputs.package_version }}"
echo "✓ Successfully published to MCP Registry"
echo "Server: io.github.kesslerio/attio-mcp-server"
echo "Version: $VERSION"
echo "npm: https://www.npmjs.com/package/attio-mcp/v/$VERSION"
echo "Registry: https://registry.modelcontextprotocol.io"