registry/docs/guides/publishing/github-actions.md
adam jones f975e68cf2
Clean up schema by simplifying version structure (#379)
## Summary

Simplified the schema structure by:
- Replacing `version_detail.version` with direct `version` field  
- Removing unused `release_date` field from seed data
- Updating all API types, models, and tests to match new structure
- Maintaining backwards compatibility in API responses

This change makes the schema more intuitive and reduces nesting depth.
2025-09-08 14:32:59 -07:00

331 lines
No EOL
8.3 KiB
Markdown

# Automate Publishing with GitHub Actions
Set up automated MCP server publishing using GitHub Actions.
## What You'll Learn
By the end of this tutorial, you'll have:
- A GitHub Actions workflow that automatically publishes your server
- Understanding of GitHub OIDC authentication
- Knowledge of best practices for automated publishing
- Working examples for Node.js, Python, and Docker projects
## Prerequisites
- Already published your server manually (complete [Publishing Tutorial](publish-server.md) first)
- GitHub repository with your MCP server code
- Basic understanding of CI/CD concepts
- 20-30 minutes
## GitHub Actions Setup
### Step 1: Create Workflow File
Create `.github/workflows/publish-mcp.yml` in your repository:
```yaml
name: Publish to MCP Registry
on:
push:
tags: ['v*'] # Triggers on version tags like v1.0.0
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC authentication
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js # Adjust for your language
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build package
run: npm run build
- name: Publish to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Install MCP Publisher
run: |
# Build publisher from source (requires Go)
git clone https://github.com/modelcontextprotocol/registry publisher-repo
cd publisher-repo
make publisher
cp cmd/publisher/bin/mcp-publisher ../mcp-publisher
cd ..
chmod +x mcp-publisher
- name: Login to MCP Registry
run: ./mcp-publisher login github-oidc
- name: Publish to MCP Registry
run: ./mcp-publisher publish
```
### Step 2: Configure Secrets
For npm publishing, add your NPM token to repository secrets:
1. Go to repository Settings → Secrets and variables → Actions
2. Add `NPM_TOKEN` with your npm access token
**Note:** GitHub OIDC authentication requires no additional secrets for MCP Registry publishing.
### Step 3: Tag and Release
Create a version tag to trigger the workflow:
```bash
git tag v1.0.0
git push origin v1.0.0
```
The workflow will:
1. Run tests
2. Build your package
3. Publish to npm
4. Automatically authenticate with the MCP Registry
5. Publish updated server.json
## Authentication Methods by CI Platform
### GitHub Actions - OIDC (Recommended)
```yaml
- name: Login to MCP Registry
run: mcp-publisher login github-oidc
```
**Advantages:**
- No secrets to manage
- Automatically scoped to your repository
- Most secure option
### GitHub Actions - Personal Access Token
```yaml
- name: Login to MCP Registry
run: mcp-publisher login github --token ${{ secrets.GITHUB_TOKEN }}
env:
GITHUB_TOKEN: ${{ secrets.MCP_GITHUB_TOKEN }}
```
Add `MCP_GITHUB_TOKEN` secret with a GitHub PAT that has repo access.
### DNS Authentication (Any CI)
For custom domain namespaces (`com.yourcompany/*`):
```yaml
- name: Login to MCP Registry
run: |
echo "${{ secrets.MCP_PRIVATE_KEY }}" > key.pem
mcp-publisher login dns --domain yourcompany.com --private-key-file key.pem
```
Add your Ed25519 private key as `MCP_PRIVATE_KEY` secret.
## Language-Specific Examples
### Python Project
```yaml
name: Publish Python MCP Server
on:
push:
tags: ['v*']
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install Poetry
run: pipx install poetry
- name: Build package
run: poetry build
- name: Publish to PyPI
run: poetry publish
env:
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
- name: Install MCP Publisher
run: |
git clone https://github.com/modelcontextprotocol/registry publisher-repo
cd publisher-repo && make publisher && cd ..
cp publisher-repo/cmd/publisher/bin/mcp-publisher mcp-publisher
- name: Publish to MCP Registry
run: |
./mcp-publisher login github-oidc
./mcp-publisher publish
```
### Docker Project
```yaml
name: Publish Docker MCP Server
on:
push:
tags: ['v*']
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract version
id: version
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: yourname/your-server:${{ steps.version.outputs.version }}
labels: |
io.modelcontextprotocol.server.name=io.github.yourname/your-server
- name: Install MCP Publisher
run: |
git clone https://github.com/modelcontextprotocol/registry publisher-repo
cd publisher-repo && make publisher && cd ..
cp publisher-repo/cmd/publisher/bin/mcp-publisher mcp-publisher
- name: Publish to MCP Registry
run: |
./mcp-publisher login github-oidc
./mcp-publisher publish
```
## Best Practices
### 1. Version Alignment
Keep your package version and server.json version in sync:
```yaml
- name: Update server.json version
run: |
VERSION=${GITHUB_REF#refs/tags/v}
jq --arg version "$VERSION" '.version = $version' server.json > tmp.json
mv tmp.json server.json
```
### 2. Conditional Publishing
Only publish to registry after package publishing succeeds:
```yaml
- name: Publish to npm
run: npm publish
id: npm-publish
- name: Publish to MCP Registry
if: steps.npm-publish.outcome == 'success'
run: ./mcp-publisher publish
```
### 3. Test Before Publishing
Include validation in your workflow:
```yaml
- name: Validate server.json
run: |
# Validate against schema
curl -s https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json | \
jq . > schema.json
npx ajv-cli validate -s schema.json -d server.json
# Test with publisher
./mcp-publisher init --validate-only
```
### 4. Notification Setup
Get notified of publishing status:
```yaml
- name: Notify on success
if: success()
run: |
curl -X POST "${{ secrets.WEBHOOK_URL }}" \
-H "Content-Type: application/json" \
-d '{"text": "✅ MCP server ${{ github.repository }} published successfully"}'
- name: Notify on failure
if: failure()
run: |
curl -X POST "${{ secrets.WEBHOOK_URL }}" \
-H "Content-Type: application/json" \
-d '{"text": "❌ MCP server ${{ github.repository }} publishing failed"}'
```
## Troubleshooting
**"Publisher binary not found"** - Ensure you download the correct binary for your CI platform (linux/mac/windows).
**"Authentication failed"** - For GitHub OIDC, verify `id-token: write` permission is set. For other methods, check secret configuration.
**"Package validation failed"** - Ensure your package was published successfully before MCP Registry publishing runs.
**"Version already exists"** - Each server.json version must be unique. Consider using build numbers: `1.0.0-build.123`.
## What You've Accomplished
You now have automated MCP server publishing that:
- Triggers on version tags
- Runs tests before publishing
- Publishes to package registry first
- Automatically publishes to MCP Registry
- Handles authentication securely
- Provides failure notifications
Your MCP server publishing is now fully automated - just tag a release and everything happens automatically!