klaridian()
How-to guides

Publishing to the MCP Registry

Name and version your server for the official MCP Registry.

What this does

The official MCP Registry expects servers to identify themselves with a reverse-DNS-style name, like io.github.you/server-name. Setting --registry-name at generation time writes that name into the generated server.json and marks the project as publishable (see below). It works for both targets: the TypeScript output records the name in package.json's mcpName, and the Python output records it as an mcp-name: line in the README — each is the ownership proof its package registry (npm / PyPI) expects.

npx klaridian generate --spec ./api.yaml --out ./my-server \
  --registry-name io.github.yourname/your-server

Versioning

Every generated server carries a version. klaridian derives it rather than inventing one, and stamps the same value into three places so they can never drift: the runtime the server reports at handshake, package.json, and server.json (both the server-level version and the package entry's).

The version is resolved with this precedence:

  1. --server-version <x.y.z> — an explicit override.
  2. The spec's info.version, if it's valid SemVer.
  3. 1.0.0, if neither is available.
# Use the spec's info.version automatically:
npx klaridian generate --spec ./api.yaml --out ./my-server \
  --registry-name io.github.yourname/your-server

# Or set it explicitly:
npx klaridian generate --spec ./api.yaml --out ./my-server \
  --registry-name io.github.yourname/your-server \
  --server-version 2.1.0

Rules the registry enforces

  • Use SemVer. The registry parses version as SemVer to sort releases and pick which one is "latest." A value it can't parse is always marked latest, so a single non-SemVer version sinks your real ones. klaridian fails at generation time if your version isn't valid SemVer — pass --server-version to fix it rather than shipping something the registry mishandles.
  • No ranges. ^1.2.3, ~1.2.3, >=1.2.3, 1.2.* are rejected — a version is one concrete point, not a range.
  • Each version is unique and immutable. Once you publish a version you can't edit or replace it; you supersede it by publishing a new one. There's no un-publish.
  • Server version aligns with package version. klaridian keeps server.json and package.json on the same number for you.

Cutting a new version

klaridian is a generator, so a new version of your server is a regenerate: bump your spec's info.version (or pass a new --server-version), run generate again, and the new number flows into every manifest. Then republish. The registry's immutability rule is your safety net — it refuses to republish a version you've already shipped.

Publishing

--registry-name prepares the files; it doesn't publish. Publishing is a step you run yourself once the project is generated:

  • The package goes to its package registry. For the TypeScript target that's npm publish (npm proves you own the package through the mcpName field klaridian writes into package.json). For the Python target it's a PyPI publish (uv build / twine upload), and ownership is proved by an mcp-name: line in the README — see below.
  • The registry metadata goes to the MCP Registry with the mcp-publisher CLI: mcp-publisher login github && mcp-publisher publish.

Both targets emit a server.json describing how to launch the server (npm/npx for TypeScript, PyPI/uvx for Python), so either one is a single publish away from the registry.

How ownership is proved

The registry won't let you publish metadata for a package you don't control, so it checks a proof that lives in the package:

  • npm (TypeScript): the generated package.json carries an mcpName equal to the server.json name. Nothing more to do.
  • PyPI (Python): the registry reads the published package's description (which PyPI builds from your README.md) and looks for the exact line mcp-name: <your server.json name>. klaridian writes this into the generated README.md as an HTML comment (so it stays invisible in the rendered page) and wires readme = "README.md" into pyproject.toml so it reaches PyPI. The name must match server.json exactly, including case — klaridian keeps them in sync for you.

Generated files are marked "do not edit"

Every generated code file starts with a Generated by klaridian. DO NOT EDIT. header (JSON manifests can't carry comments, so they're the exception). This is the standard code-generation convention: it records provenance and warns that regenerating will overwrite hand edits. Change your spec or flags and re-run generate rather than editing the output — that's also what keeps your version and registry metadata consistent.

Without --registry-name

If you don't pass --registry-name, the server is generated to run, not to publish: package.json stays private and server.json declares no package entry (it still carries a valid name, description, and version). This keeps the two files honest — a private package is never paired with metadata claiming a published one.

On this page