diff --git a/.github/workflows/publish-mcp-registry.yml b/.github/workflows/publish-mcp-registry.yml new file mode 100644 index 000000000..d045be42b --- /dev/null +++ b/.github/workflows/publish-mcp-registry.yml @@ -0,0 +1,73 @@ +name: Publish to MCP Registry + +# Publishes the repo-root server.json to the official MCP Registry +# (registry.modelcontextprotocol.io) whenever a GitHub Release is published. +# +# Auth is keyless: mcp-publisher exchanges the workflow's GitHub OIDC token for a +# short-lived Registry JWT. The OIDC token proves this repo lives in the +# `smart-mcp-proxy` org, which owns the `io.github.smart-mcp-proxy` namespace — +# so no secrets or stored login are required. See docs/mcp-registry-publishing.md. + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: "Version to publish (no leading v, e.g. 0.34.0). Defaults to server.json's value." + required: false + type: string + +permissions: + contents: read + id-token: write # required for mcp-publisher login github-oidc + +concurrency: + group: mcp-registry-publish + cancel-in-progress: false + +env: + MCP_PUBLISHER_VERSION: "1.7.9" + +jobs: + publish: + name: Publish server.json + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Install mcp-publisher + run: | + set -euo pipefail + url="https://github.com/modelcontextprotocol/registry/releases/download/v${MCP_PUBLISHER_VERSION}/mcp-publisher_linux_amd64.tar.gz" + echo "Downloading $url" + curl -fsSL "$url" -o mcp-publisher.tar.gz + tar -xzf mcp-publisher.tar.gz mcp-publisher + chmod +x mcp-publisher + ./mcp-publisher --version || true + + - name: Sync version into server.json + run: | + set -euo pipefail + # Prefer the release tag; fall back to the workflow_dispatch input; else keep server.json's value. + raw="${{ github.event.release.tag_name || inputs.version }}" + if [ -n "$raw" ]; then + ver="${raw#v}" # strip leading v + echo "Setting server.json version to $ver" + tmp="$(mktemp)" + jq --arg v "$ver" '.version = $v' server.json > "$tmp" + mv "$tmp" server.json + else + echo "No tag/input supplied; publishing server.json as committed ($(jq -r .version server.json))." + fi + cat server.json + + - name: Validate + run: ./mcp-publisher validate server.json + + - name: Authenticate (GitHub OIDC) + run: ./mcp-publisher login github-oidc + + - name: Publish + run: ./mcp-publisher publish server.json diff --git a/docs/mcp-registry-publishing.md b/docs/mcp-registry-publishing.md index f9cef0940..5162fe5a6 100644 --- a/docs/mcp-registry-publishing.md +++ b/docs/mcp-registry-publishing.md @@ -1,6 +1,8 @@ # Publishing MCPProxy to the MCP Registry -This guide covers how to publish (or update) the `server.json` at the repo root to the official [MCP Registry](https://registry.modelcontextprotocol.io). This is a manual step that requires authentication as the namespace owner — it cannot be automated without a GitHub OIDC workflow scoped to the `smart-mcp-proxy` org. +This guide covers how to publish (or update) the `server.json` at the repo root to the official [MCP Registry](https://registry.modelcontextprotocol.io). + +**Publishing is automated.** The [`.github/workflows/publish-mcp-registry.yml`](../.github/workflows/publish-mcp-registry.yml) workflow publishes `server.json` on every GitHub Release using keyless GitHub OIDC auth — no stored token or secret. It syncs `server.json`'s `version` to the release tag at publish time, so you don't need to hand-bump it. The manual steps below remain useful for first-time setup, validation, ad-hoc `workflow_dispatch` runs, and deprecating versions. ## Prerequisites @@ -91,7 +93,7 @@ mcp-publisher status --status deleted \ ## What Requires the User - **GitHub authentication**: Only a member/owner of the `smart-mcp-proxy` GitHub org can authenticate for the `io.github.smart-mcp-proxy` namespace. There is no way to delegate or automate this without adding a GitHub Actions workflow with `id-token: write` permission to the release pipeline. -- **Automating via CI**: To run `mcp-publisher login github-oidc` + `mcp-publisher publish` in the release workflow, add a new job after the `release` job in `.github/workflows/release.yml`, grant `id-token: write` in its `permissions` block, and run the two commands against the tagged `server.json`. The OIDC token is valid for the duration of the workflow run only. +- **Automating via CI** (done): [`.github/workflows/publish-mcp-registry.yml`](../.github/workflows/publish-mcp-registry.yml) runs `mcp-publisher login github-oidc` + `mcp-publisher publish` on `release: published` (and via manual `workflow_dispatch`). It declares `id-token: write`, downloads the pinned `mcp-publisher` binary, syncs `version` from the release tag, validates, then publishes. The OIDC token is minted per run and valid only for that run — no secret is stored. The first run must succeed as a member identity of the `smart-mcp-proxy` org (the workflow's repo identity satisfies this). ## Registry Schema Notes