From 9d5b4dde4533663e2392d418d3307cbc72d6e6bb Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Mon, 8 Dec 2025 14:07:48 +0100 Subject: [PATCH 1/5] chore: fix publish workflow for MCP registry --- .github/actions/docker-publish.yml | 48 ++++++++++++++++++++++++++++++ .github/workflows/docker.yml | 41 +++++++++---------------- .github/workflows/publish.yml | 41 +++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 27 deletions(-) create mode 100644 .github/actions/docker-publish.yml diff --git a/.github/actions/docker-publish.yml b/.github/actions/docker-publish.yml new file mode 100644 index 000000000..f29f1d82a --- /dev/null +++ b/.github/actions/docker-publish.yml @@ -0,0 +1,48 @@ +--- +name: Build and Push Docker Image +on: + workflow_call: + secrets: + DOCKERHUB_USERNAME: + required: true + DOCKERHUB_PASSWORD: + required: true + +jobs: + build-push: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + with: + persist-credentials: false + + - name: Get version and date + id: release-meta + run: | + VERSION=$(npm pkg get version | tr -d '"') + DATE=$(date +'%Y-%m-%d') + echo "VERSION=${VERSION}" >> "$GITHUB_OUTPUT" + echo "DATE=${DATE}" >> "$GITHUB_OUTPUT" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 + + - name: Login to Docker Hub + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef + with: + username: "${{ secrets.DOCKERHUB_USERNAME }}" + password: "${{ secrets.DOCKERHUB_PASSWORD }}" + + - name: Build and push image to dockerhub registry + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 + with: + context: . + platforms: linux/amd64,linux/arm64 + tags: ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:latest, ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:${{ steps.release-meta.outputs.VERSION }}, ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:${{ steps.release-meta.outputs.VERSION }}-${{ steps.release-meta.outputs.DATE }} + file: Dockerfile + push: true + provenance: mode=max + sbom: true + build-args: | + VERSION=${{ steps.release-meta.outputs.VERSION }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5d32b7beb..49cd3226c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -7,8 +7,16 @@ permissions: contents: read issues: write jobs: - push: + docker-push: + uses: ./.github/actions/docker-publish.yml + secrets: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} + + handle-failure: runs-on: ubuntu-latest + needs: docker-push + if: ${{ failure() }} steps: - uses: GitHubSecurityLab/actions-permissions/monitor@v1 with: @@ -17,43 +25,22 @@ jobs: uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: persist-credentials: false - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 - - name: Login to Docker Hub - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef - with: - username: "${{ secrets.DOCKERHUB_USERNAME }}" - password: "${{ secrets.DOCKERHUB_PASSWORD }}" - - name: Set date and version - id: set-properties + - name: Get version and date + id: release-meta run: | - DATE=$(date +'%Y-%m-%d') VERSION=$(npm pkg get version | tr -d '"') - echo "DATE=${DATE}" >> "$GITHUB_OUTPUT" + DATE=$(date +'%Y-%m-%d') echo "VERSION=${VERSION}" >> "$GITHUB_OUTPUT" - - name: Build and push image to dockerhub registry - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 - with: - context: . - platforms: linux/amd64,linux/arm64 - tags: ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:latest, ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:${{ steps.set-properties.outputs.VERSION }}, ${{ vars.DOCKERHUB_IMAGE_REPOSITORY }}:${{ steps.set-properties.outputs.VERSION }}-${{ steps.set-properties.outputs.DATE }} - file: Dockerfile - push: true - provenance: mode=max - sbom: true - build-args: | - VERSION=${{ steps.set-properties.outputs.VERSION }} + echo "DATE=${DATE}" >> "$GITHUB_OUTPUT" - uses: mongodb-js/devtools-shared/actions/setup-bot-token@main id: app-token - if: ${{ failure() }} with: app-id: ${{ vars.DEVTOOLS_BOT_APP_ID }} private-key: ${{ secrets.DEVTOOLS_BOT_PRIVATE_KEY }} - name: Create Issue - if: ${{ failure() }} uses: imjohnbo/issue-bot@572eed14422c4d6ca37e870f97e7da209422f5bd with: token: ${{ steps.app-token.outputs.token }} - title: Release Failure for Docker Image ${{ steps.set-properties.outputs.VERSION }}-${{ steps.set-properties.outputs.DATE }} + title: Release Failure for Docker Image ${{ steps.release-meta.outputs.VERSION }}-${{ steps.release-meta.outputs.DATE }} body: See https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} labels: "docker, release_failure" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d17a341ef..014cd06ef 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -101,6 +101,47 @@ jobs: run: | gh release create ${{ needs.check.outputs.VERSION }} --title "${{ needs.check.outputs.VERSION }}" --generate-notes --target ${{ github.sha }} ${{ (needs.check.outputs.RELEASE_CHANNEL != 'latest' && '--prerelease') || ''}} + - name: Wait for package to be available on npm + run: | + PACKAGE_NAME=$(jq -r '.name' < package.json) + VERSION="${{ needs.check.outputs.VERSION }}" + MAX_ATTEMPTS=30 + SLEEP_SECONDS=10 + + echo "Waiting for ${PACKAGE_NAME}@${VERSION} to be available on npm..." + + for i in $(seq 1 $MAX_ATTEMPTS); do + if npm view "${PACKAGE_NAME}@${VERSION}" version >/dev/null 2>&1; then + echo "✓ Package ${PACKAGE_NAME}@${VERSION} is now available on npm" + exit 0 + fi + echo "Attempt $i/$MAX_ATTEMPTS: Package not yet available, waiting ${SLEEP_SECONDS}s..." + sleep $SLEEP_SECONDS + done + + echo "::error::Package ${PACKAGE_NAME}@${VERSION} did not become available after $((MAX_ATTEMPTS * SLEEP_SECONDS)) seconds" + exit 1 + + docker-push: + needs: [check, publish] + uses: ./.github/actions/docker-publish.yml + secrets: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} + + mcp-publish: + runs-on: ubuntu-latest + environment: Production + permissions: + id-token: write + needs: [check, docker-build] + if: needs.check.outputs.VERSION_EXISTS == 'false' + steps: + - uses: GitHubSecurityLab/actions-permissions/monitor@v1 + - uses: actions/checkout@v5 + with: + persist-credentials: false + - 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 From 6a9157db46f885dc29de5a557a44d4a9dd07d531 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Mon, 8 Dec 2025 14:12:55 +0100 Subject: [PATCH 2/5] chore: add permissions to docker-push job --- .github/workflows/publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 014cd06ef..7dec24717 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -125,6 +125,7 @@ jobs: docker-push: needs: [check, publish] uses: ./.github/actions/docker-publish.yml + permissions: {} secrets: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} From 9326014c4f3239b2cd96b999da1e879014a85bb2 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Mon, 8 Dec 2025 14:22:58 +0100 Subject: [PATCH 3/5] chore: address copilot suggestions --- .github/{actions => workflows}/docker-publish.yml | 0 .github/workflows/docker.yml | 2 +- .github/workflows/publish.yml | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename .github/{actions => workflows}/docker-publish.yml (100%) diff --git a/.github/actions/docker-publish.yml b/.github/workflows/docker-publish.yml similarity index 100% rename from .github/actions/docker-publish.yml rename to .github/workflows/docker-publish.yml diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 49cd3226c..d60cb4353 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -8,7 +8,7 @@ permissions: issues: write jobs: docker-push: - uses: ./.github/actions/docker-publish.yml + uses: ./.github/workflows/docker-publish.yml secrets: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7dec24717..a468f7c9d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -124,7 +124,7 @@ jobs: docker-push: needs: [check, publish] - uses: ./.github/actions/docker-publish.yml + uses: ./.github/workflows/docker-publish.yml permissions: {} secrets: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} @@ -135,7 +135,7 @@ jobs: environment: Production permissions: id-token: write - needs: [check, docker-build] + needs: [check, docker-push] if: needs.check.outputs.VERSION_EXISTS == 'false' steps: - uses: GitHubSecurityLab/actions-permissions/monitor@v1 From a991f2fc0b4f737683a5f918a600e3e2dc348c29 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Mon, 8 Dec 2025 14:25:05 +0100 Subject: [PATCH 4/5] chore: add explicit permission --- .github/workflows/docker-publish.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index f29f1d82a..e6202d89f 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -11,6 +11,8 @@ on: jobs: build-push: runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Check out code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 From f607e465ff245922910ed2e1778f60d0f912df45 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 11 Dec 2025 11:53:48 +0100 Subject: [PATCH 5/5] chore: add MCP publish workflow for manual dispatch --- .github/workflows/docker.yml | 7 +++++- .github/workflows/mcp-publish.yml | 28 ++++++++++++++++++++++++ .github/workflows/publish.yml | 36 +++++++++++-------------------- 3 files changed, 46 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/mcp-publish.yml diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index d60cb4353..01987ad76 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -9,14 +9,19 @@ permissions: jobs: docker-push: uses: ./.github/workflows/docker-publish.yml + permissions: + contents: read secrets: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} handle-failure: runs-on: ubuntu-latest + permissions: + contents: read + issues: write needs: docker-push - if: ${{ failure() }} + if: ${{ always() && needs.docker-push.result == 'failure' }} steps: - uses: GitHubSecurityLab/actions-permissions/monitor@v1 with: diff --git a/.github/workflows/mcp-publish.yml b/.github/workflows/mcp-publish.yml new file mode 100644 index 000000000..8ae57ec1b --- /dev/null +++ b/.github/workflows/mcp-publish.yml @@ -0,0 +1,28 @@ +--- +name: Publish to MCP Registry +on: + workflow_call: + workflow_dispatch: + +jobs: + mcp-publish: + runs-on: ubuntu-latest + environment: Production + permissions: + id-token: write + contents: read + steps: + - uses: GitHubSecurityLab/actions-permissions/monitor@v1 + - uses: actions/checkout@v5 + with: + persist-credentials: false + + - 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 + + - name: Login to MCP Registry + run: ./mcp-publisher login github-oidc + + - name: Publish to MCP Registry + run: ./mcp-publisher publish diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a468f7c9d..9f9342ef2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -105,50 +105,38 @@ jobs: run: | PACKAGE_NAME=$(jq -r '.name' < package.json) VERSION="${{ needs.check.outputs.VERSION }}" + # Strip the 'v' prefix for npm + NPM_VERSION="${VERSION#v}" MAX_ATTEMPTS=30 SLEEP_SECONDS=10 - echo "Waiting for ${PACKAGE_NAME}@${VERSION} to be available on npm..." + echo "Waiting for ${PACKAGE_NAME}@${NPM_VERSION} to be available on npm..." for i in $(seq 1 $MAX_ATTEMPTS); do - if npm view "${PACKAGE_NAME}@${VERSION}" version >/dev/null 2>&1; then - echo "✓ Package ${PACKAGE_NAME}@${VERSION} is now available on npm" + if npm view "${PACKAGE_NAME}@${NPM_VERSION}" version >/dev/null 2>&1; then + echo "✓ Package ${PACKAGE_NAME}@${NPM_VERSION} is now available on npm" exit 0 fi echo "Attempt $i/$MAX_ATTEMPTS: Package not yet available, waiting ${SLEEP_SECONDS}s..." sleep $SLEEP_SECONDS done - echo "::error::Package ${PACKAGE_NAME}@${VERSION} did not become available after $((MAX_ATTEMPTS * SLEEP_SECONDS)) seconds" + echo "::error::Package ${PACKAGE_NAME}@${NPM_VERSION} did not become available after $((MAX_ATTEMPTS * SLEEP_SECONDS)) seconds" exit 1 docker-push: needs: [check, publish] uses: ./.github/workflows/docker-publish.yml - permissions: {} + permissions: + contents: read secrets: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} mcp-publish: - runs-on: ubuntu-latest - environment: Production - permissions: - id-token: write needs: [check, docker-push] if: needs.check.outputs.VERSION_EXISTS == 'false' - steps: - - uses: GitHubSecurityLab/actions-permissions/monitor@v1 - - uses: actions/checkout@v5 - with: - persist-credentials: false - - - 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 - - - name: Login to MCP Registry - run: ./mcp-publisher login github-oidc - - - name: Publish to MCP Registry - run: ./mcp-publisher publish + uses: ./.github/workflows/mcp-publish.yml + permissions: + id-token: write + contents: read