|
| 1 | +# Publish the MCP server to the official Model Context Protocol registry. |
| 2 | +# |
| 3 | +# No secret and no browser: `login github-oidc` proves ownership of the io.github.peopleworks/* |
| 4 | +# namespace from this workflow's OIDC token, which is why `id-token: write` below is required |
| 5 | +# rather than tidy. |
| 6 | +# |
| 7 | +# The registry additionally verifies that whoever publishes owns the NuGet package, by reading |
| 8 | +# `mcp-name: io.github.peopleworks/xaf-logic-explainer` out of the README inside the published |
| 9 | +# package. That line lives in src/XafLogicExplainer.Mcp/README.md and must not be reworded. |
| 10 | +name: Publish MCP registry |
| 11 | + |
| 12 | +on: |
| 13 | + release: |
| 14 | + types: [published] |
| 15 | + workflow_dispatch: |
| 16 | + |
| 17 | +permissions: |
| 18 | + contents: read |
| 19 | + id-token: write # required for github-oidc login |
| 20 | + |
| 21 | +jobs: |
| 22 | + publish: |
| 23 | + if: github.event_name == 'workflow_dispatch' || startsWith(github.ref_name, 'v') |
| 24 | + runs-on: ubuntu-latest |
| 25 | + |
| 26 | + steps: |
| 27 | + - uses: actions/checkout@v4 |
| 28 | + |
| 29 | + # This job and the NuGet one both start from `release: published`, so they run in parallel — |
| 30 | + # and the registry rejects a server whose package it cannot download yet. NuGet's indexes |
| 31 | + # also lag its API by minutes: a push that returns "Created" is not immediately fetchable. |
| 32 | + # So wait for the artifact itself rather than assuming the sibling job's success is enough. |
| 33 | + - name: Wait for the package to be downloadable from NuGet |
| 34 | + run: | |
| 35 | + version=$(jq -r '.packages[0].version' src/XafLogicExplainer.Mcp/.mcp/server.json) |
| 36 | + url="https://api.nuget.org/v3-flatcontainer/xaflogicexplainer.mcp/$version/xaflogicexplainer.mcp.$version.nupkg" |
| 37 | + echo "Waiting for $url" |
| 38 | +
|
| 39 | + for attempt in $(seq 1 40); do |
| 40 | + code=$(curl -s -o /dev/null -w "%{http_code}" "$url" || true) |
| 41 | + if [ "$code" = "200" ]; then |
| 42 | + echo "Available after $attempt attempt(s)." |
| 43 | + exit 0 |
| 44 | + fi |
| 45 | + echo " attempt $attempt: HTTP $code" |
| 46 | + sleep 30 |
| 47 | + done |
| 48 | +
|
| 49 | + echo "::error::XafLogicExplainer.Mcp $version never became downloadable from NuGet." |
| 50 | + echo "The registry validates ownership by reading the package, so publishing would fail." |
| 51 | + exit 1 |
| 52 | +
|
| 53 | + - name: Install mcp-publisher |
| 54 | + run: | |
| 55 | + tag=$(curl -s https://api.github.com/repos/modelcontextprotocol/registry/releases/latest | jq -r .tag_name) |
| 56 | + echo "mcp-publisher $tag" |
| 57 | + curl -sL "https://github.com/modelcontextprotocol/registry/releases/download/$tag/mcp-publisher_linux_amd64.tar.gz" \ |
| 58 | + | tar xz mcp-publisher |
| 59 | + ./mcp-publisher --version || true |
| 60 | +
|
| 61 | + - name: Log in with GitHub OIDC |
| 62 | + run: ./mcp-publisher login github-oidc |
| 63 | + |
| 64 | + # `publish` reads server.json from the working directory. |
| 65 | + - name: Publish |
| 66 | + working-directory: src/XafLogicExplainer.Mcp/.mcp |
| 67 | + run: $GITHUB_WORKSPACE/mcp-publisher publish |
| 68 | + |
| 69 | + - name: Confirm the listing |
| 70 | + run: | |
| 71 | + name="io.github.peopleworks/xaf-logic-explainer" |
| 72 | + curl -s "https://registry.modelcontextprotocol.io/v0/servers?search=$name" \ |
| 73 | + | jq -r '.servers[]? | "\(.name) \(.version)"' || true |
0 commit comments