development
yml 133 lines 5.3 KB
Raw
1 name: MCP Registry Release
2
3 on:
4 workflow_dispatch:
5 inputs:
6 tag:
7 description: "Release tag (e.g. v0.1.0)"
8 required: true
9
10 # One registry publish per tag at a time, and never cancelled: cancelling
11 # `mcp-publisher` mid-publish could leave the listing half-updated.
12 concurrency:
13 group: release-mcp-registry-${{ github.event.inputs.tag || github.ref }}
14 cancel-in-progress: false
15
16 # OIDC is how we authenticate to the MCP Registry: the registry trusts a GitHub
17 # Actions token issued for this repository, so no long-lived secret is needed.
18 permissions:
19 id-token: write
20 contents: read
21
22 jobs:
23 publish:
24 name: Publish the MCP server to the MCP Registry
25 runs-on: ubuntu-latest
26 steps:
27 - name: Checkout
28 uses: actions/checkout@v6
29 with:
30 ref: ${{ github.event.inputs.tag || github.ref }}
31
32 - name: Set the release version
33 shell: bash
34 run: |
35 release_version="${{ github.event.inputs.tag }}"
36 release_version="${release_version#v}"
37
38 echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
39
40 - name: Check the server name is consistent across the sources
41 shell: bash
42 run: |
43 server_name="$(jq -r '.name' server.json)"
44 echo "Server name: ${server_name}"
45
46 # The registry proves ownership by fetching the published crate and
47 # finding this marker in its README, so the marker has to be in the
48 # README of the crate named in server.json's packages — the CLI, not
49 # the library.
50 grep -q "mcp-name: ${server_name}" crates/cli/README.md
51 grep -q "mcp-name: ${server_name}" README.md
52
53 - name: Check the crate version matches the release
54 shell: bash
55 run: |
56 workspace_version="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)"
57 if [ "${workspace_version}" != "${RELEASE_VERSION}" ]; then
58 echo "Workspace version ${workspace_version} does not match release version ${RELEASE_VERSION}." >&2
59 exit 1
60 fi
61
62 - name: Set the release version in server metadata
63 shell: bash
64 run: |
65 jq --arg v "${RELEASE_VERSION}" \
66 '.version = $v | .packages |= map(.version = $v)' \
67 server.json > server.tmp
68 mv server.tmp server.json
69 cat server.json
70
71 - name: Verify the published crate carries the ownership marker
72 shell: bash
73 run: |
74 # Checking the source tree is not enough: a crate published before
75 # the marker landed will still be missing it, and the registry reads
76 # the published artifact, not this checkout. The comparison is
77 # case-sensitive.
78 server_name="$(jq -r '.name' server.json)"
79 crate="$(jq -r '.packages[0].identifier' server.json)"
80
81 # crates.io indexes a few seconds to a few minutes after publish, and
82 # this workflow may run while the crate release is still in flight.
83 for attempt in $(seq 1 20); do
84 if curl -fsSL -H "User-Agent: smbcloudXYZ/smbcloud-ascapi release-workflow" \
85 "https://crates.io/api/v1/crates/${crate}/${RELEASE_VERSION}" >/dev/null; then
86 echo "${crate} ${RELEASE_VERSION} is indexed on crates.io."
87 break
88 fi
89 if [ "${attempt}" -eq 20 ]; then
90 echo "${crate} ${RELEASE_VERSION} is still not indexed on crates.io after 10 minutes." >&2
91 exit 1
92 fi
93 echo "Waiting for crates.io to index ${crate} ${RELEASE_VERSION} (attempt ${attempt}/20)..."
94 sleep 30
95 done
96
97 curl -fsSL -H "User-Agent: smbcloudXYZ/smbcloud-ascapi release-workflow" -o crate.crate \
98 "https://crates.io/api/v1/crates/${crate}/${RELEASE_VERSION}/download"
99 if ! tar -xOf crate.crate "${crate}-${RELEASE_VERSION}/README.md" | grep -q "mcp-name: ${server_name}"; then
100 echo "${crate} ${RELEASE_VERSION} README is missing the 'mcp-name: ${server_name}' marker." >&2
101 echo "crates.io versions are immutable — cut a new release with the marker in place." >&2
102 exit 1
103 fi
104 rm crate.crate
105
106 - name: Install mcp-publisher
107 shell: bash
108 run: |
109 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
110
111 - name: Authenticate to the MCP Registry
112 shell: bash
113 run: ./mcp-publisher login github-oidc
114
115 - name: Publish
116 shell: bash
117 run: |
118 # Re-running a release should not fail the workflow: the registry
119 # rejects a version it already holds, which is the desired end state
120 # anyway.
121 out="$(./mcp-publisher publish 2>&1)" && { echo "${out}"; exit 0; }
122 echo "${out}"
123 if echo "${out}" | grep -q "duplicate version"; then
124 echo "Version already published — skipping."
125 exit 0
126 fi
127 exit 1
128
129 - name: Verify the server is listed
130 shell: bash
131 run: |
132 server_name="$(jq -r '.name' server.json)"
133 curl -fsSL "https://registry.modelcontextprotocol.io/v0.1/servers?search=${server_name}" | jq .