1
+name: MCP Registry Release
2
+
3
+on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ tag:
7
+ description: "Release tag (e.g. v0.4.1)"
8
+ required: true
9
+
10
+# OIDC is how we authenticate to the MCP Registry: the registry trusts a GitHub
11
+# Actions token issued for this repository, so no long-lived secret is needed.
12
+permissions:
13
+ id-token: write
14
+ contents: read
15
+
16
+jobs:
17
+ publish:
18
+ name: Publish server.json to the MCP Registry
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Checkout
22
+ uses: actions/checkout@v6
23
+ with:
24
+ ref: ${{ github.event.inputs.tag || github.ref }}
25
+
26
+ - name: Set the release version
27
+ shell: bash
28
+ run: |
29
+ release_version="${{ github.event.inputs.tag }}"
30
+ release_version="${release_version#v}"
31
+
32
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
33
+
34
+ - name: Check the server name is consistent across packages
35
+ shell: bash
36
+ run: |
37
+ server_name="$(jq -r '.name' server.json)"
38
+ echo "Server name: ${server_name}"
39
+
40
+ # npm proves ownership through `mcpName` in the published package.json,
41
+ # rendered at release time from this template.
42
+ grep -q "\"mcpName\": \"${server_name}\"" npm/package-main.json.tmpl
43
+
44
+ # NuGet proves ownership through an `mcp-name:` marker in the package README.
45
+ grep -q "mcp-name: ${server_name}" nuget/onde-cli/README.md
46
+
47
+ - name: Set the version in server.json
48
+ shell: bash
49
+ run: |
50
+ jq --arg v "${RELEASE_VERSION}" \
51
+ '.version = $v | .packages |= map(.version = $v)' \
52
+ server.json > server.tmp
53
+ mv server.tmp server.json
54
+ cat server.json
55
+
56
+ - name: Verify the published packages carry the ownership marker
57
+ shell: bash
58
+ run: |
59
+ # The registry stores metadata only, and validates it by fetching each
60
+ # listed package and looking for a marker naming this server. Checking
61
+ # the sources isn't enough: a package published before the marker
62
+ # landed will still be missing it. Both comparisons are case-sensitive.
63
+ server_name="$(jq -r '.name' server.json)"
64
+
65
+ # npm is queryable within seconds of publishing, but the npm release
66
+ # workflow may still be building its platform packages when this runs.
67
+ for attempt in $(seq 1 20); do
68
+ if npm view "@ondeinference/cli@${RELEASE_VERSION}" version; then
69
+ break
70
+ fi
71
+ if [ "${attempt}" -eq 20 ]; then
72
+ echo "@ondeinference/cli@${RELEASE_VERSION} is still not on npm after 10 minutes." >&2
73
+ exit 1
74
+ fi
75
+ echo "Waiting for @ondeinference/cli@${RELEASE_VERSION} on npm (attempt ${attempt}/20)..."
76
+ sleep 30
77
+ done
78
+
79
+ npm_mcp_name="$(npm view "@ondeinference/cli@${RELEASE_VERSION}" mcpName)"
80
+ if [ "${npm_mcp_name}" != "${server_name}" ]; then
81
+ echo "@ondeinference/cli@${RELEASE_VERSION} declares mcpName '${npm_mcp_name}', expected '${server_name}'." >&2
82
+ echo "npm versions are immutable — cut a new release with the marker in place." >&2
83
+ exit 1
84
+ fi
85
+
86
+ # nuget.org validates a package before it reaches the flat container,
87
+ # so a version pushed minutes ago is not queryable yet. Poll instead
88
+ # of failing the release on that race.
89
+ for attempt in $(seq 1 20); do
90
+ nuget_versions="$(curl -fsSL "https://api.nuget.org/v3-flatcontainer/onde.cli/index.json")"
91
+ if echo "${nuget_versions}" | jq -e --arg v "${RELEASE_VERSION}" '.versions | index($v)' >/dev/null; then
92
+ echo "Onde.Cli ${RELEASE_VERSION} is indexed."
93
+ break
94
+ fi
95
+ if [ "${attempt}" -eq 20 ]; then
96
+ echo "Onde.Cli ${RELEASE_VERSION} is still not indexed on nuget.org after 10 minutes." >&2
97
+ exit 1
98
+ fi
99
+ echo "Waiting for nuget.org to index ${RELEASE_VERSION} (attempt ${attempt}/20)..."
100
+ sleep 30
101
+ done
102
+
103
+ curl -fsSL -o package.nupkg \
104
+ "https://api.nuget.org/v3-flatcontainer/onde.cli/${RELEASE_VERSION}/onde.cli.${RELEASE_VERSION}.nupkg"
105
+ if ! unzip -p package.nupkg README.md | grep -q "mcp-name: ${server_name}"; then
106
+ echo "Onde.Cli ${RELEASE_VERSION} README is missing the 'mcp-name: ${server_name}' marker." >&2
107
+ exit 1
108
+ fi
109
+ rm package.nupkg
110
+
111
+ - name: Install mcp-publisher
112
+ shell: bash
113
+ run: |
114
+ 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
115
+
116
+ - name: Authenticate to the MCP Registry
117
+ shell: bash
118
+ run: ./mcp-publisher login github-oidc
119
+
120
+ - name: Publish
121
+ shell: bash
122
+ run: ./mcp-publisher publish
123
+
124
+ - name: Verify the server is listed
125
+ shell: bash
126
+ run: |
127
+ server_name="$(jq -r '.name' server.json)"
128
+ curl -fsSL "https://registry.modelcontextprotocol.io/v0.1/servers?search=${server_name}" | jq .