name: "Release: Publish to PyPI & MCP Registry"
on:
release:
types: [published]
workflow_dispatch: # Allow manual trigger for testing
jobs:
publish:
# Only run for releases tagged with v* (simplified from mcp-v*)
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for trusted publishing (PyPI + MCP Registry)
steps:
- name: Verify CI passed on this commit
env:
GH_TOKEN: ${{ github.token }}
run: |
COMMIT_SHA="${{ github.sha }}"
echo "Checking CI status for commit $COMMIT_SHA..."
# Wait up to 60s for any in-progress checks to settle
for i in $(seq 1 6); do
RUNS=$(gh api "repos/${{ github.repository }}/commits/$COMMIT_SHA/check-runs" \
--jq '.check_runs[] | select(.name != "Release: Publish to PyPI & MCP Registry") | {name, status, conclusion}')
IN_PROGRESS=$(echo "$RUNS" | grep '"status": "in_progress"' | wc -l | tr -d ' ')
if [ "$IN_PROGRESS" -eq 0 ]; then break; fi
echo " $IN_PROGRESS check(s) still in progress, waiting 10s..."
sleep 10
done
FAILURES=$(gh api "repos/${{ github.repository }}/commits/$COMMIT_SHA/check-runs" \
--jq '[.check_runs[] | select(.name != "Release: Publish to PyPI & MCP Registry") | select(.conclusion == "failure" or .conclusion == "cancelled")] | length')
if [ "$FAILURES" -gt 0 ]; then
echo "❌ $FAILURES CI check(s) failed on this commit — aborting release."
gh api "repos/${{ github.repository }}/commits/$COMMIT_SHA/check-runs" \
--jq '.check_runs[] | select(.conclusion == "failure" or .conclusion == "cancelled") | " FAILED: \(.name)"'
exit 1
fi
echo "✅ All CI checks passed on commit $COMMIT_SHA"
- name: Checkout code
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.10"
- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Extract version from tag
id: version
run: |
# Extract version from tag (e.g., v1.1.0 -> 1.1.0)
VERSION=${GITHUB_REF#refs/tags/v}
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Publishing version: $VERSION"
- name: Verify version matches pyproject.toml
run: |
PYPROJECT_VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
TAG_VERSION="${{ steps.version.outputs.version }}"
if [ "$PYPROJECT_VERSION" != "$TAG_VERSION" ]; then
echo "❌ Version mismatch!"
echo " pyproject.toml: $PYPROJECT_VERSION"
echo " Git tag: $TAG_VERSION"
exit 1
fi
echo "✅ Version verified: $PYPROJECT_VERSION"
- name: Build package
run: |
python -m build
echo "📦 Built package:"
ls -lh dist/
- name: Check package
run: |
twine check dist/*
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/
print-hash: true
# Using trusted publishing (OIDC) - configured at https://pypi.org/manage/project/wemo-mcp-server/settings/publishing/
# Publisher setup: apiarya/wemo-mcp-server -> release.yml
- name: Verify PyPI publish succeeded
run: |
VERSION="${{ steps.version.outputs.version }}"
echo "⏳ Waiting for PyPI to index version $VERSION..."
# Retry up to 5 times (max ~2.5 minutes) before giving up
for i in 1 2 3 4 5; do
sleep 30
echo "Attempt $i: checking https://pypi.org/pypi/wemo-mcp-server/$VERSION/json"
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
"https://pypi.org/pypi/wemo-mcp-server/$VERSION/json")
if [ "$HTTP_STATUS" = "200" ]; then
echo "✅ Package wemo-mcp-server==$VERSION is live on PyPI"
break
fi
echo "Not available yet (HTTP $HTTP_STATUS), retrying..."
if [ "$i" = "5" ]; then
echo "❌ Package not found on PyPI after 5 attempts"
exit 1
fi
done
- name: Install mcp-publisher
run: |
echo "📥 Installing mcp-publisher CLI..."
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz" | tar xz
chmod +x mcp-publisher
./mcp-publisher --version
- name: Authenticate with MCP Registry (OIDC)
run: |
echo "🔐 Authenticating with MCP Registry using GitHub OIDC..."
./mcp-publisher login github-oidc
- name: Verify server.json version
run: |
SERVER_VERSION=$(grep '"version"' server.json | head -n 1 | sed 's/.*"version": "\(.*\)".*/\1/')
TAG_VERSION="${{ steps.version.outputs.version }}"
if [ "$SERVER_VERSION" != "$TAG_VERSION" ]; then
echo "❌ Version mismatch in server.json!"
echo " server.json: $SERVER_VERSION"
echo " Git tag: $TAG_VERSION"
exit 1
fi
echo "✅ server.json version verified: $SERVER_VERSION"
- name: Wait for PyPI propagation
run: |
echo "⏳ Waiting 60s for PyPI to fully propagate before MCP Registry validation..."
sleep 60
- name: Publish to MCP Registry
run: |
echo "📤 Publishing to MCP Registry..."
# Retry up to 3 times — MCP Registry validates against PyPI, which may lag
for i in 1 2 3; do
if ./mcp-publisher publish server.json; then
echo "✅ Successfully published to MCP Registry"
exit 0
fi
echo "⚠️ Attempt $i failed. Waiting 30s before retry..."
sleep 30
done
echo "❌ MCP Registry publish failed after 3 attempts"
exit 1
- name: Create release summary
run: |
echo "## 🎉 Published Successfully" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📦 PyPI" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Install command:**" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo "pip install wemo-mcp-server==${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "# or" >> $GITHUB_STEP_SUMMARY
echo "uvx wemo-mcp-server@${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**PyPI page:** https://pypi.org/project/wemo-mcp-server/${{ steps.version.outputs.version }}/" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🌐 MCP Registry" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Registry page:** https://registry.modelcontextprotocol.io/?q=apiarya/wemo" >> $GITHUB_STEP_SUMMARY
echo "**Server name:** \`io.github.apiarya/wemo\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Repository:** https://github.com/apiarya/wemo-mcp-server" >> $GITHUB_STEP_SUMMARY