From acd2e26e59ba74b8814e2e9c24d73da8438eefdc Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Wed, 12 Nov 2025 16:00:18 +0200 Subject: [PATCH 01/15] feat(ci): add MCP registry publishing to release workflow --- .github/workflows/release.yml | 92 +++++++++++++++++++++++++++++++++-- server.json | 7 --- 2 files changed, 87 insertions(+), 12 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0ce9274..783c38c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -242,10 +242,86 @@ name: dist-${{ needs.validate-release.outputs.version }} path: dist/ retention-days: 90 - - notify-success: + + publish-mcp-registry: runs-on: ubuntu-latest needs: [validate-release, build-and-publish] + permissions: + id-token: write # Required for GitHub OIDC authentication + contents: read + + steps: + - name: ⚙️ Harden Runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + + - name: ⚙️ Checkout the project + uses: actions/checkout@v5 + + - name: ⚙️ Update server.json version + run: | + # Determine the target version + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + TARGET_VERSION="${{ github.event.inputs.version }}" + echo "Using version from manual trigger: $TARGET_VERSION" + elif [[ "${{ github.event_name }}" == "release" ]]; then + RELEASE_TAG="${{ github.event.release.tag_name }}" + TARGET_VERSION=$(echo "$RELEASE_TAG" | sed 's/^v//') + echo "Using version from release tag: $TARGET_VERSION (tag: $RELEASE_TAG)" + fi + + # Update version in server.json + jq --arg v "$TARGET_VERSION" '.version = $v | .packages[0].version = $v' server.json > tmp && mv tmp server.json + + # Verify the change + echo "Updated server.json:" + cat server.json + + - 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 + chmod +x mcp-publisher + + - name: ⚙️ Verify server.json exists and is valid JSON + run: | + if [ ! -f server.json ]; then + echo "Error: server.json not found" + exit 1 + fi + + if ! jq empty server.json 2>/dev/null; then + echo "Error: server.json is not valid JSON" + exit 1 + fi + + echo "Success: server.json is valid JSON" + echo "Current server.json:" + cat server.json + + - name: ⚙️ Login to MCP Registry + if: ${{ !inputs.dry_run }} + run: ./mcp-publisher login github-oidc + + - name: ⚙️ Publish to MCP Registry + if: ${{ !inputs.dry_run }} + run: ./mcp-publisher publish + + - name: ⚙️ Dry run notification + if: ${{ inputs.dry_run }} + run: | + VERSION=$(jq -r '.version' server.json) + echo "🔍 DRY RUN MODE - MCP Registry preparation successful!" + echo "" + echo "server.json is valid JSON and ready to publish" + echo "Server: io.github.redis/mcp-redis" + echo "Version: $VERSION" + echo "" + echo "To actually publish to MCP Registry, run this workflow again without dry_run enabled" + + notify-success: + runs-on: ubuntu-latest + needs: [validate-release, build-and-publish, publish-mcp-registry] if: success() steps: - name: ⚙️ Success notification @@ -255,12 +331,18 @@ echo "📦 Package built successfully but not published" echo "🎯 Target environment: ${{ github.event.inputs.environment || 'pypi' }}" else - echo "🎉 Successfully released Redis MCP Server v${{ github.event.inputs.version || needs.validate-release.outputs.version }} to ${{ github.event.inputs.environment || 'PyPI' }}!" + echo "🎉 Successfully released Redis MCP Server v${{ github.event.inputs.version || needs.validate-release.outputs.version }}!" + echo "" + echo "📦 PyPI Package:" if [[ "${{ github.event.inputs.environment }}" == "testpypi" ]]; then - echo "📦 Package: https://test.pypi.org/project/redis-mcp-server/${{ github.event.inputs.version || needs.validate-release.outputs.version }}/" + echo " https://test.pypi.org/project/redis-mcp-server/${{ github.event.inputs.version || needs.validate-release.outputs.version }}/" else - echo "📦 Package: https://pypi.org/project/redis-mcp-server/${{ github.event.inputs.version || needs.validate-release.outputs.version }}/" + echo " https://pypi.org/project/redis-mcp-server/${{ github.event.inputs.version || needs.validate-release.outputs.version }}/" fi + echo "" + echo "🔌 MCP Registry:" + echo " https://registry.modelcontextprotocol.io/v0/servers?search=redis" + echo "" if [[ "${{ github.event_name }}" == "release" ]]; then echo "🏷️ Release: https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }}" else diff --git a/server.json b/server.json index 2108439..b2ae938 100644 --- a/server.json +++ b/server.json @@ -12,13 +12,6 @@ "transport": { "type": "stdio" } - }, - { - "registryType": "oci", - "identifier": "docker.io/mcp/redis:latest", - "transport": { - "type": "stdio" - } } ] } From 80a8200d5b71463b0a77bc7676198ac36b4fc593 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Thu, 13 Nov 2025 14:59:40 +0200 Subject: [PATCH 02/15] test: temp remove PyPI dependency from MCP publish for a workflow test --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 783c38c..d53b406 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -245,7 +245,7 @@ publish-mcp-registry: runs-on: ubuntu-latest - needs: [validate-release, build-and-publish] + needs: [validate-release] # TODO: restore build-and-publish dependency after testing permissions: id-token: write # Required for GitHub OIDC authentication contents: read From 040034ece89f0eefb917de0a7e54258aaf9a4dd3 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Thu, 13 Nov 2025 15:41:51 +0200 Subject: [PATCH 03/15] fix(ci): restore PyPI dependency and add conditions for MCP publish --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d53b406..2ed89e2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -245,7 +245,8 @@ publish-mcp-registry: runs-on: ubuntu-latest - needs: [validate-release] # TODO: restore build-and-publish dependency after testing + needs: [validate-release, build-and-publish] + if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && !inputs.dry_run) }} permissions: id-token: write # Required for GitHub OIDC authentication contents: read From e7c5a5449c1cadece085fb560e43b605cf8608de Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Fri, 14 Nov 2025 14:44:53 +0200 Subject: [PATCH 04/15] fix(ci): correct tar extraction by adding -f - to read from stdin Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2ed89e2..952acc1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -281,7 +281,7 @@ - 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 + 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 xzf - mcp-publisher chmod +x mcp-publisher - name: ⚙️ Verify server.json exists and is valid JSON From 148cb7082ea8e528c249e6a0866fe99982ffbbf2 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Fri, 14 Nov 2025 14:50:31 +0200 Subject: [PATCH 05/15] fix(ci): handle undefined dry_run input in release workflow Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 952acc1..627d920 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -301,11 +301,11 @@ cat server.json - name: ⚙️ Login to MCP Registry - if: ${{ !inputs.dry_run }} + if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.dry_run != true) }} run: ./mcp-publisher login github-oidc - name: ⚙️ Publish to MCP Registry - if: ${{ !inputs.dry_run }} + if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.dry_run != true) }} run: ./mcp-publisher publish - name: ⚙️ Dry run notification From 701ebde4cee0d1b8fa8c97fa6bf69982e55f1bd5 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Fri, 14 Nov 2025 15:47:05 +0200 Subject: [PATCH 06/15] fix(ci): add error handling for unexpected GitHub event types in release workflow Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 627d920..1644fb6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -270,6 +270,9 @@ RELEASE_TAG="${{ github.event.release.tag_name }}" TARGET_VERSION=$(echo "$RELEASE_TAG" | sed 's/^v//') echo "Using version from release tag: $TARGET_VERSION (tag: $RELEASE_TAG)" + else + echo "Error: Unexpected event type: ${{ github.event_name }}" + exit 1 fi # Update version in server.json From 7bfcfdc2addff97f1c19d5f7d2524a269bee682f Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Fri, 14 Nov 2025 15:58:59 +0200 Subject: [PATCH 07/15] fix(ci): ensure dry run check only applies to workflow_dispatch events Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1644fb6..3175e99 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -312,7 +312,7 @@ run: ./mcp-publisher publish - name: ⚙️ Dry run notification - if: ${{ inputs.dry_run }} + if: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run == true }} run: | VERSION=$(jq -r '.version' server.json) echo "🔍 DRY RUN MODE - MCP Registry preparation successful!" From ee662cbfa3ade2aa6ce4a4c26d952babab025faa Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Fri, 14 Nov 2025 17:47:01 +0200 Subject: [PATCH 08/15] fix(ci): validate server.json before and after modification --- .github/workflows/release.yml | 52 ++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3175e99..145f072 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -260,6 +260,22 @@ - name: ⚙️ Checkout the project uses: actions/checkout@v5 + - name: ⚙️ Verify server.json exists and is valid JSON + run: | + if [ ! -f server.json ]; then + echo "Error: server.json not found" + exit 1 + fi + + if ! jq empty server.json 2>/dev/null; then + echo "Error: server.json is not valid JSON" + exit 1 + fi + + echo "Success: server.json is valid JSON" + echo "Original server.json:" + cat server.json + - name: ⚙️ Update server.json version run: | # Determine the target version @@ -275,10 +291,24 @@ exit 1 fi - # Update version in server.json - jq --arg v "$TARGET_VERSION" '.version = $v | .packages[0].version = $v' server.json > tmp && mv tmp server.json + # Update version in server.json (with validation) + if ! jq --arg v "$TARGET_VERSION" '.version = $v | .packages[0].version = $v' server.json > tmp; then + echo "Error: jq failed to update server.json" + rm -f tmp + exit 1 + fi + + # Verify the updated content is valid JSON before replacing + if ! jq empty tmp 2>/dev/null; then + echo "Error: Updated server.json is not valid JSON" + cat tmp + rm -f tmp + exit 1 + fi + + # Replace original with validated update + mv tmp server.json - # Verify the change echo "Updated server.json:" cat server.json @@ -287,22 +317,6 @@ 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 xzf - mcp-publisher chmod +x mcp-publisher - - name: ⚙️ Verify server.json exists and is valid JSON - run: | - if [ ! -f server.json ]; then - echo "Error: server.json not found" - exit 1 - fi - - if ! jq empty server.json 2>/dev/null; then - echo "Error: server.json is not valid JSON" - exit 1 - fi - - echo "Success: server.json is valid JSON" - echo "Current server.json:" - cat server.json - - name: ⚙️ Login to MCP Registry if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.dry_run != true) }} run: ./mcp-publisher login github-oidc From b22bf3ea82e25e82593f3b0e528361d451757959 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Fri, 14 Nov 2025 18:06:27 +0200 Subject: [PATCH 09/15] fix(ci): use template variable for version in server.json --- server.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.json b/server.json index b2ae938..da31b84 100644 --- a/server.json +++ b/server.json @@ -3,12 +3,12 @@ "name": "io.github.redis/mcp-redis", "title": "Redis MCP Server", "description": "Natural language interface designed for agentic applications to manage and search data in Redis.", - "version": "0.3.6", + "version": "$VERSION", "packages": [ { "registryType": "pypi", "identifier": "redis-mcp-server", - "version": "0.3.6", + "version": "$VERSION", "transport": { "type": "stdio" } From 3ff89f6c1f15e32780825dbebcc59dd63bece9f0 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Mon, 17 Nov 2025 14:32:20 +0200 Subject: [PATCH 10/15] fix(ci): notify success even when dependencies are skipped Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 145f072..ec1eb18 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -340,7 +340,7 @@ notify-success: runs-on: ubuntu-latest needs: [validate-release, build-and-publish, publish-mcp-registry] - if: success() + if: ${{ always() && !cancelled() && needs.build-and-publish.result == 'success' }} steps: - name: ⚙️ Success notification run: | From c48f4f57d0d42e0fa3cc0e4afadf938d13016621 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Mon, 17 Nov 2025 14:37:27 +0200 Subject: [PATCH 11/15] fix(ci): fail fast if MCP publisher download fails --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ec1eb18..4216c27 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -314,7 +314,7 @@ - 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 xzf - mcp-publisher + curl -fL "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 xzf - mcp-publisher chmod +x mcp-publisher - name: ⚙️ Login to MCP Registry From 8d36a9ca841a02e81315ad02e2216abba83f5d02 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Mon, 17 Nov 2025 14:56:44 +0200 Subject: [PATCH 12/15] fix(ci): remove premature server.json validation Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/release.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4216c27..47ef682 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -260,22 +260,6 @@ - name: ⚙️ Checkout the project uses: actions/checkout@v5 - - name: ⚙️ Verify server.json exists and is valid JSON - run: | - if [ ! -f server.json ]; then - echo "Error: server.json not found" - exit 1 - fi - - if ! jq empty server.json 2>/dev/null; then - echo "Error: server.json is not valid JSON" - exit 1 - fi - - echo "Success: server.json is valid JSON" - echo "Original server.json:" - cat server.json - - name: ⚙️ Update server.json version run: | # Determine the target version From f30cc97abe4dafda0a2dabc15e9e0b8f4d6eb842 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Mon, 17 Nov 2025 15:06:35 +0200 Subject: [PATCH 13/15] fix: use consistent dry_run check in publish steps Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 47ef682..e715497 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -302,11 +302,11 @@ chmod +x mcp-publisher - name: ⚙️ Login to MCP Registry - if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.dry_run != true) }} + if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && !inputs.dry_run) }} run: ./mcp-publisher login github-oidc - name: ⚙️ Publish to MCP Registry - if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.dry_run != true) }} + if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && !inputs.dry_run) }} run: ./mcp-publisher publish - name: ⚙️ Dry run notification From 2701d46ddee2e642fdf54c488aa76e4a9b7404b6 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Mon, 17 Nov 2025 18:08:54 +0200 Subject: [PATCH 14/15] test: temporarily disable PyPI publish to test MCP registry step --- .github/workflows/release.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e715497..e793c3e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -219,13 +219,14 @@ with: subject-path: 'dist/*' - - name: ⚙️ Publish to PyPI - if: ${{ !inputs.dry_run }} - uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: ${{ github.event.inputs.environment == 'testpypi' && 'https://test.pypi.org/legacy/' || '' }} - print-hash: true - attestations: true + # TEMPORARY: Commented out for testing MCP publish + # - name: ⚙️ Publish to PyPI + # if: ${{ !inputs.dry_run }} + # uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # repository-url: ${{ github.event.inputs.environment == 'testpypi' && 'https://test.pypi.org/legacy/' || '' }} + # print-hash: true + # attestations: true - name: ⚙️ Dry run - Package ready for publishing if: ${{ inputs.dry_run }} From 27ad7789ae0079d96e97ba87ab4586117370e7a2 Mon Sep 17 00:00:00 2001 From: Vasil Chomakov Date: Mon, 17 Nov 2025 19:09:27 +0200 Subject: [PATCH 15/15] chore: restore PyPI publish step after MCP publish step testing --- .github/workflows/release.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e793c3e..e715497 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -219,14 +219,13 @@ with: subject-path: 'dist/*' - # TEMPORARY: Commented out for testing MCP publish - # - name: ⚙️ Publish to PyPI - # if: ${{ !inputs.dry_run }} - # uses: pypa/gh-action-pypi-publish@release/v1 - # with: - # repository-url: ${{ github.event.inputs.environment == 'testpypi' && 'https://test.pypi.org/legacy/' || '' }} - # print-hash: true - # attestations: true + - name: ⚙️ Publish to PyPI + if: ${{ !inputs.dry_run }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: ${{ github.event.inputs.environment == 'testpypi' && 'https://test.pypi.org/legacy/' || '' }} + print-hash: true + attestations: true - name: ⚙️ Dry run - Package ready for publishing if: ${{ inputs.dry_run }}