| 1 | # MCP Registry |
| 2 | |
| 3 | The Onde CLI's MCP server (`onde --mcp`, added in v0.4.0) is listed in the |
| 4 | [official MCP Registry](https://registry.modelcontextprotocol.io) as |
| 5 | **`io.github.ondeinference/onde-cli`**. The registry is a metadata index — it |
| 6 | doesn't host binaries — so the listing points at packages we already publish to |
| 7 | npm and NuGet, and clients that browse the registry can offer a one-click |
| 8 | install. |
| 9 | |
| 10 | ## What makes up the listing |
| 11 | |
| 12 | | Piece | Where | |
| 13 | | --- | --- | |
| 14 | | Server metadata | [`server.json`](../server.json) at the repo root | |
| 15 | | npm ownership proof | `mcpName` in `npm/package-main.json.tmpl`, copied verbatim into the published manifest by `npm/scripts/render-main-package.cjs` | |
| 16 | | NuGet ownership proof | `<!-- mcp-name: ... -->` in `nuget/onde-cli/README.md` | |
| 17 | | Publishing | `.github/workflows/release-mcp-registry.yml` | |
| 18 | |
| 19 | The registry checks each listed package for a marker naming the server. If the |
| 20 | marker is missing or doesn't match `name` in `server.json`, publishing fails |
| 21 | with "Registry validation failed for package". |
| 22 | |
| 23 | The markers ship *inside* the published artifacts, so they have to be in place |
| 24 | before the npm and NuGet packages are built. A version published before the |
| 25 | marker landed can never be listed, since neither registry lets you overwrite a |
| 26 | version. The publish workflow checks the real published artifacts, not just the |
| 27 | sources in this repo, and stops early if a marker is missing. |
| 28 | |
| 29 | **v0.4.0 cannot be listed.** It shipped the MCP server, and its NuGet package |
| 30 | carries the `mcp-name` marker, but `@ondeinference/cli@0.4.0` published without |
| 31 | `mcpName` — the template change adding it came afterwards. `server.json` |
| 32 | therefore targets 0.4.1, the first release where both markers are live. |
| 33 | |
| 34 | ### Why the name is `io.github.ondeinference/...` |
| 35 | |
| 36 | The namespace has to match the authentication method. We authenticate with |
| 37 | GitHub OIDC from Actions, which grants the `io.github.ondeinference/*` namespace |
| 38 | (the reverse-DNS form of the `ondeinference` org). |
| 39 | |
| 40 | The registry grants the namespace with the org's exact GitHub casing and |
| 41 | compares case-sensitively, so a mis-cased namespace is rejected with a 403 even |
| 42 | though GitHub itself treats org names case-insensitively. The `ondeinference` |
| 43 | org is all lowercase, which makes this a non-issue here — but every marker still |
| 44 | has to spell it identically. |
| 45 | |
| 46 | ### Which packages are listed |
| 47 | |
| 48 | - **npm** — `@ondeinference/cli`, launched as `npx @ondeinference/cli --mcp`. |
| 49 | The package declares a single binary (`onde`), so `npx` resolves it despite |
| 50 | the name difference. |
| 51 | - **NuGet** — `Onde.Cli`, launched as `dnx Onde.Cli --mcp`. |
| 52 | |
| 53 | PyPI is deliberately not listed. The `onde-cli` wheel installs its executable as |
| 54 | `onde` (maturin `bindings = "bin"`), and `uvx onde-cli` looks for an executable |
| 55 | matching the distribution name, so the launch command the registry hands to |
| 56 | clients wouldn't work. Adding PyPI would mean shipping an extra console script |
| 57 | named `onde-cli`. pub.dev, Homebrew, and the direct GitHub release binaries have |
| 58 | no registry package type at all. |
| 59 | |
| 60 | ## Releasing a new version |
| 61 | |
| 62 | `server.json` carries the version twice, once for the server and once per |
| 63 | package. The publish workflow rewrites both from the tag it was given, so the |
| 64 | committed values are documentation rather than the source of truth — keep them |
| 65 | pointing at the next intended listing. |
| 66 | |
| 67 | Publishing is chained off the release: pushing a `v*` tag runs the crates.io |
| 68 | workflow, which fans out to the distribution workflows, and **NuGet Release** |
| 69 | triggers **MCP Registry Release** once its publish job succeeds. It hangs off |
| 70 | NuGet rather than the fan-out because the listing needs both npm and NuGet live |
| 71 | at that version, and NuGet is the slower of the two — in the v0.4.0 release, |
| 72 | NuGet took 55 minutes against npm's 35. |
| 73 | |
| 74 | The registry fetches the package metadata during publish, so |
| 75 | `@ondeinference/cli@<version>` and `Onde.Cli <version>` must already exist. npm |
| 76 | is queryable within seconds of publishing; nuget.org validates first and takes |
| 77 | roughly 5–15 minutes to reach the flat container. The workflow polls both for up |
| 78 | to ten minutes rather than failing on that gap. |
| 79 | |
| 80 | To publish by hand — a re-run after a transient failure, say — dispatch it with |
| 81 | the tag: |
| 82 | |
| 83 | ```sh |
| 84 | gh workflow run release-mcp-registry.yml --ref main -f tag=v0.4.1 |
| 85 | ``` |
| 86 | |
| 87 | The workflow publishes the `server.json` on the branch you dispatch from, not |
| 88 | the one at the tag. It uploads metadata rather than building from source, and |
| 89 | that metadata can change after a tag is cut; the tag input only selects which |
| 90 | version to publish. |
| 91 | |
| 92 | Confirm the listing afterwards: |
| 93 | |
| 94 | ```sh |
| 95 | curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.ondeinference/onde-cli" |
| 96 | ``` |
| 97 | |
| 98 | ## Publishing without Actions |
| 99 | |
| 100 | Rarely needed, but if Actions is unavailable: |
| 101 | |
| 102 | ```sh |
| 103 | brew install mcp-publisher |
| 104 | mcp-publisher login github # device flow, needs push access to ondeinference |
| 105 | mcp-publisher publish # reads ./server.json |
| 106 | ``` |
| 107 | |
| 108 | Versions are immutable — republishing the same version is rejected. Fixing a bad |
| 109 | listing means shipping a new patch version. |