@ondeinference / cli / commits / 23f1596

List the CLI on the MCP Registry

v0.4.0 ships the MCP server, so the CLI can be listed on the registry. The registry stores metadata only and proves ownership by fetching each package it lists and looking for a marker naming the server: mcpName in the npm package.json, and an mcp-name comment in the NuGet README. The NuGet README already carries its marker; this adds mcpName to the npm template, which render-main-package.cjs copies through verbatim at release time. release-mcp-registry.yml rewrites server.json with the tag version, waits for both packages to be queryable, checks the markers on the published artifacts rather than the sources, then publishes through mcp-publisher with GitHub OIDC. It hangs off release-nuget.yml because NuGet is the slower of the two to index. Note this cannot list 0.4.0: that npm package published without mcpName and npm versions are immutable, so server.json targets 0.4.1. Co-Authored-By: siGit Code <297239231+sigitc@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Seto Elkahfi committed Jul 23, 2026 at 00:20 UTC 23f1596403d60629e40915802c22dd0df4911f19
4 files changed +222
.github/workflows/release-mcp-registry.yml new
+128
@@ -0,0 +1,128 @@
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 .
.github/workflows/release-nuget.yml
+23
@@ -301,3 +301,26 @@ jobs:
301 --api-key "${NUGET_API_KEY}" \
302 --source https://api.nuget.org/v3/index.json \
303 --skip-duplicate
304 +
305 + dispatch-mcp-registry:
306 + name: Trigger MCP Registry release
307 + needs: publish-nuget
308 + runs-on: ubuntu-latest
309 + permissions:
310 + actions: write
311 + steps:
312 + # The MCP Registry listing needs both npm and NuGet live at this version,
313 + # and NuGet is the slower of the two, so it hangs off this workflow rather
314 + # than the fan-out in release-crates.yml.
315 + - name: Trigger MCP Registry release workflow
316 + uses: actions/github-script@v7
317 + with:
318 + script: |
319 + const tag = '${{ github.event.inputs.tag }}' || context.ref.replace('refs/tags/', '')
320 + await github.rest.actions.createWorkflowDispatch({
321 + owner: context.repo.owner,
322 + repo: context.repo.repo,
323 + workflow_id: 'release-mcp-registry.yml',
324 + ref: tag,
325 + inputs: { tag }
326 + })
npm/package-main.json.tmpl
+1
@@ -1,6 +1,7 @@
1 {
2 "name": "@ondeinference/cli",
3 "version": "${release_version}",
4 + "mcpName": "io.github.ondeinference/onde-cli",
5 "keywords": [
6 "onde",
7 "cli",
server.json new
+70
@@ -0,0 +1,70 @@
1 +{
2 + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3 + "name": "io.github.ondeinference/onde-cli",
4 + "title": "Onde Inference CLI",
5 + "description": "Manage your Onde Inference account and models: apps, model catalog, fine-tuned GGUF deploys.",
6 + "version": "0.4.1",
7 + "websiteUrl": "https://ondeinference.com/cli",
8 + "repository": {
9 + "url": "https://github.com/ondeinference/onde-cli",
10 + "source": "github",
11 + "id": "1207617309"
12 + },
13 + "packages": [
14 + {
15 + "registryType": "npm",
16 + "registryBaseUrl": "https://registry.npmjs.org",
17 + "identifier": "@ondeinference/cli",
18 + "version": "0.4.1",
19 + "runtimeHint": "npx",
20 + "transport": {
21 + "type": "stdio"
22 + },
23 + "packageArguments": [
24 + {
25 + "type": "named",
26 + "name": "--mcp",
27 + "description": "Run the CLI as an MCP server over stdio instead of launching the TUI.",
28 + "isRequired": true
29 + }
30 + ]
31 + },
32 + {
33 + "registryType": "nuget",
34 + "registryBaseUrl": "https://api.nuget.org/v3/index.json",
35 + "identifier": "Onde.Cli",
36 + "version": "0.4.1",
37 + "runtimeHint": "dnx",
38 + "transport": {
39 + "type": "stdio"
40 + },
41 + "packageArguments": [
42 + {
43 + "type": "named",
44 + "name": "--mcp",
45 + "description": "Run the CLI as an MCP server over stdio instead of launching the TUI.",
46 + "isRequired": true
47 + }
48 + ]
49 + }
50 + ],
51 + "_meta": {
52 + "io.modelcontextprotocol.registry/publisher-provided": {
53 + "categories": ["developer-tools", "ai"],
54 + "keywords": [
55 + "onde",
56 + "inference",
57 + "llm",
58 + "fine-tuning",
59 + "lora",
60 + "gguf",
61 + "hugging face",
62 + "model deployment",
63 + "on-device"
64 + ],
65 + "products": {
66 + "Onde Inference": "https://ondeinference.com"
67 + }
68 + }
69 + }
70 +}