development
md 4.96 KB

MCP Registry

The Onde CLI's MCP server (onde --mcp, added in v0.4.0) is listed in the official MCP Registry as io.github.ondeinference/onde-cli. The registry is a metadata index — it doesn't host binaries — so the listing points at packages we already publish to npm and NuGet, and clients that browse the registry can offer a one-click install.

What makes up the listing

Piece Where
Server metadata server.json at the repo root
npm ownership proof mcpName in npm/package-main.json.tmpl, copied verbatim into the published manifest by npm/scripts/render-main-package.cjs
NuGet ownership proof <!-- mcp-name: ... --> in nuget/onde-cli/README.md
Publishing .github/workflows/release-mcp-registry.yml

The registry checks each listed package for a marker naming the server. If the marker is missing or doesn't match name in server.json, publishing fails with "Registry validation failed for package".

The markers ship inside the published artifacts, so they have to be in place before the npm and NuGet packages are built. A version published before the marker landed can never be listed, since neither registry lets you overwrite a version. The publish workflow checks the real published artifacts, not just the sources in this repo, and stops early if a marker is missing.

v0.4.0 cannot be listed. It shipped the MCP server, and its NuGet package carries the mcp-name marker, but @ondeinference/cli@0.4.0 published without mcpName — the template change adding it came afterwards. server.json therefore targets 0.4.1, the first release where both markers are live.

Why the name is io.github.ondeinference/...

The namespace has to match the authentication method. We authenticate with GitHub OIDC from Actions, which grants the io.github.ondeinference/* namespace (the reverse-DNS form of the ondeinference org).

The registry grants the namespace with the org's exact GitHub casing and compares case-sensitively, so a mis-cased namespace is rejected with a 403 even though GitHub itself treats org names case-insensitively. The ondeinference org is all lowercase, which makes this a non-issue here — but every marker still has to spell it identically.

Which packages are listed

  • npm — @ondeinference/cli, launched as npx @ondeinference/cli --mcp. The package declares a single binary (onde), so npx resolves it despite the name difference.
  • NuGet — Onde.Cli, launched as dnx Onde.Cli --mcp.

PyPI is deliberately not listed. The onde-cli wheel installs its executable as onde (maturin bindings = "bin"), and uvx onde-cli looks for an executable matching the distribution name, so the launch command the registry hands to clients wouldn't work. Adding PyPI would mean shipping an extra console script named onde-cli. pub.dev, Homebrew, and the direct GitHub release binaries have no registry package type at all.

Releasing a new version

server.json carries the version twice, once for the server and once per package. The publish workflow rewrites both from the tag it was given, so the committed values are documentation rather than the source of truth — keep them pointing at the next intended listing.

Publishing is chained off the release: pushing a v* tag runs the crates.io workflow, which fans out to the distribution workflows, and NuGet Release triggers MCP Registry Release once its publish job succeeds. It hangs off NuGet rather than the fan-out because the listing needs both npm and NuGet live at that version, and NuGet is the slower of the two — in the v0.4.0 release, NuGet took 55 minutes against npm's 35.

The registry fetches the package metadata during publish, so @ondeinference/cli@<version> and Onde.Cli <version> must already exist. npm is queryable within seconds of publishing; nuget.org validates first and takes roughly 5–15 minutes to reach the flat container. The workflow polls both for up to ten minutes rather than failing on that gap.

To publish by hand — a re-run after a transient failure, say — dispatch it with the tag:

gh workflow run release-mcp-registry.yml --ref main -f tag=v0.4.1

The workflow publishes the server.json on the branch you dispatch from, not the one at the tag. It uploads metadata rather than building from source, and that metadata can change after a tag is cut; the tag input only selects which version to publish.

Confirm the listing afterwards:

curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.ondeinference/onde-cli"

Publishing without Actions

Rarely needed, but if Actions is unavailable:

brew install mcp-publisher
mcp-publisher login github        # device flow, needs push access to ondeinference
mcp-publisher publish             # reads ./server.json

Versions are immutable — republishing the same version is rejected. Fixing a bad listing means shipping a new patch version.