Тіркелу

Publishing an MCP server to the MCP Registry

This article is not available in Kazakh yet. It is shown in English.

The MCP Registry is the official catalog of metadata about publicly available MCP servers, hosted at registry.modelcontextprotocol.io. It does not store code: each entry is a server.json document that names the server, describes it and says where to get it, in a package registry such as npm or PyPI or at the address of a remote server. Publishing a server means sending its server.json to the registry with the mcp-publisher command-line tool after proving ownership of the server's name.

The registry started in February 2025 as a community project, when the authors of MCP, David Soria Parra and Justin Spahr-Summers, asked the PulseMCP and Goose teams to help build a central registry. It was launched in preview on 8 September 2025. The registry is developed by the Registry Working Group of the MCP project.

As of November 2026 its documentation still marks it as a preview: breaking changes or data resets may occur before general availability. The API version v0.1 has been frozen since 24 October 2025, and the current published version of the server.json schema is 2025-12-11. Basic concepts of the protocol are described in the article What is MCP.

Overview

Property Value
Type Official catalog of metadata about public MCP servers, with a REST API
Address https://registry.modelcontextprotocol.io
Status Preview since 8 September 2025
API v0.1, frozen since 24 October 2025; read access without authentication
Entry format server.json, schema version 2025-12-11
Server names Reverse-DNS namespace and server name, for example io.github.user/weather
Package types npm, PyPI, NuGet, Cargo, Docker/OCI images, MCPB
Publishing tool mcp-publisher CLI
Developer Registry Working Group of the MCP project

The problem it solves

An MCP server is distributed in a package registry or runs at a remote address. To find it, a user or an application needs a catalog. To install it, the catalog needs the exact package name, transport and settings.

The announcement of the registry describes its aim as standardizing how servers are distributed and discovered. The registry is meant as a primary source of truth: a single place where the maintainers of a server publish self-reported information about it. Other catalogs, called subregistries, take the data from it and add their own, such as curation, ratings and security checks.

The registry also ties each name to a verified GitHub account or domain, so a server cannot be published under someone else's name. The package that an entry points to must name the server, so the metadata cannot claim a foreign package.

History

The table lists the launch of the registry and the main changes of its API and of the server.json schema.

Date Event
February 2025 Start of the registry as a community project
9 July 2025 First version of the server.json schema
8 September 2025 Launch of the official MCP Registry in preview
16 September 2025 Schema 2025-09-16: field names change from snake_case to camelCase (registryType, environmentVariables)
29 September 2025 Schema 2025-09-29: the status and registry metadata leave server.json and are managed by the registry
11 October 2025 Schema 2025-10-11: the package format depends on the package type; version is optional for OCI and MCPB
24 October 2025 API freeze at version v0.1: no breaking changes while integrators implement support
11 December 2025 Schema 2025-12-11: URL template variables for remote servers

Place in the ecosystem

The diagram below shows the chain from code to host applications. According to the documentation, the official registry is not intended to be consumed by host applications directly: they read subregistries that implement the same API.

Package registries (npm, PyPI, NuGet, crates.io, Docker Hub, GitHub Releases)
 |  code and binaries
 v
MCP Registry (registry.modelcontextprotocol.io)
 |  server.json metadata, REST API v0.1
 v
Subregistries and marketplaces (public or private)
 |  curation, ratings, security scans, same API
 v
Host applications (AI applications that install and connect servers)

According to the documentation, the registry is intended primarily for aggregators. It is deliberately unopinionated: it does not rate servers and does not scan their code. Security scanning is left to the package registries and to downstream aggregators.

The registry accepts open-source and closed-source servers, provided that the package is in a public registry or the remote server is publicly accessible. Private servers, available only in a private network or a private package registry, are not accepted. For them the documentation recommends a private registry.

The server.json format

Fields

server.json is a JSON document described by a JSON Schema. Its address contains the schema version, and the document refers to it in the $schema field. The main fields:

Field Required Content
$schema no URL of the schema, for example the 2025-12-11 version
name yes Unique name in reverse-DNS form, 3 to 200 characters, exactly one /
description yes What the server does, 1 to 100 characters
version yes Version of this publication, up to 255 characters; ranges are not allowed
title no Display name, up to 100 characters
repository no Source code: url, source (for example github), optional subfolder
websiteUrl no Home page or documentation
icons no Icons for user interfaces
packages no Packages: registryType, identifier, version, transport and settings
remotes no Remote endpoints: type and url, optional headers and variables
_meta no Additional metadata of the publisher

A package entry requires registryType, identifier and transport. The type of the transport of a package is stdio, streamable-http or sse. A package can also describe how to start it: runtimeHint, runtimeArguments, packageArguments and environmentVariables, each variable with name, description, isRequired and isSecret.

Example

The example describes a server that is distributed as an npm package and is also available as a remote server:

JSON
{
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "name": "io.github.example-user/weather",
  "title": "Weather",
  "description": "Current weather and forecasts for any city.",
  "version": "1.2.0",
  "repository": {
    "url": "https://github.com/example-user/mcp-weather-server",
    "source": "github"
  },
  "packages": [
    {
      "registryType": "npm",
      "identifier": "@example-user/mcp-weather-server",
      "version": "1.2.0",
      "transport": {
        "type": "stdio"
      },
      "environmentVariables": [
        {
          "name": "WEATHER_API_KEY",
          "description": "API key of the weather data provider",
          "isRequired": true,
          "isSecret": true
        }
      ]
    }
  ],
  "remotes": [
    {
      "type": "streamable-http",
      "url": "https://weather.example.com/mcp"
    }
  ]
}

Publisher metadata

The _meta field uses reverse-DNS keys. The official registry keeps only the data under the key io.modelcontextprotocol.registry/publisher-provided and silently drops other keys. This data is limited to 4096 bytes of JSON; a larger block makes the publication fail.

The registry adds its own metadata in API responses, outside server.json, under the key io.modelcontextprotocol.registry/official: the status, the dates of publication and update, and the isLatest flag. Publishers cannot set these fields.

Namespaces

The name of a server consists of a namespace and the name of the server within it, separated by /. The namespace is written in reverse-DNS form: the parts of a domain in reverse order. The way the publisher authenticates determines which namespaces it can use.

Authentication Namespace Example
GitHub (OAuth or OIDC) io.github.<username>/* or io.github.<orgname>/* io.github.alice/weather-server
DNS com.example/* and namespaces of subdomains, com.example.*/* com.example.api/analytics
HTTP com.example/* only com.example/analytics

GitHub authentication always grants the personal namespace. An organization namespace requires the role of Owner in that organization; ordinary membership is not enough. As of November 2026, the documentation notes that mcp-publisher login github cannot publish to an organization namespace, while login through OIDC or with a personal access token can.

A domain namespace is proved with DNS or HTTP. In the code of the registry, DNS verification grants the domain and all its subdomains, and HTTP verification only the domain itself. Domains github.io and its subdomains cannot be used with DNS or HTTP verification: the io.github.* namespaces are available only through GitHub authentication.

Ownership verification

Before publishing, the publisher logs in to the registry with mcp-publisher login and receives a token of the registry. The method of login proves control of the namespace.

  • GitHub OAuth. mcp-publisher login github starts the device flow: the user opens https://github.com/login/device and enters the code printed in the terminal. With the --token option, a personal access token is used instead.
  • GitHub OIDC. mcp-publisher login github-oidc is used in GitHub Actions. The workflow needs the id-token: write permission and no separate secret.
  • DNS. The publisher generates a key pair (Ed25519 or ECDSA P-384) and publishes the public key in a TXT record at the apex of the domain, not under a selector such as _mcp-auth. The login command signs a timestamp with the private key.
  • HTTP. The same record, v=MCPv1; k=ed25519; p=<public key>, is served as a file at https://<domain>/.well-known/mcp-registry-auth. The registry fetches it from its own infrastructure, does not follow redirects and expects status 200 within 10 seconds.

DNS verification with an Ed25519 key, following the documentation of the registry:

Bash
MY_DOMAIN="example.com"

# Generate an Ed25519 key pair
openssl genpkey -algorithm Ed25519 -out key.pem

# Print the TXT record to add at the apex of the domain
PUBLIC_KEY="$(openssl pkey -in key.pem -pubout -outform DER | tail -c 32 | base64)"
echo "${MY_DOMAIN}. IN TXT \"v=MCPv1; k=ed25519; p=${PUBLIC_KEY}\""

# After the record has propagated, log in with the private key
PRIVATE_KEY="$(openssl pkey -in key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n')"
mcp-publisher login dns --domain "${MY_DOMAIN}" --private-key "${PRIVATE_KEY}"

The private key can also stay in Google Cloud KMS or Azure Key Vault; mcp-publisher has login variants for both.

Package verification

The registry also checks that the package referenced in server.json belongs to the publisher of the name. Each package type has its own marker that must contain the server name exactly:

registryType Supported registry Ownership marker
npm registry.npmjs.org mcpName field in package.json
pypi pypi.org String mcp-name: <server name> in the README, may be in an HTML comment
nuget api.nuget.org String mcp-name: <server name> in the README, may be in an HTML comment
cargo crates.io String mcp-name: <server name> as visible text in the README; crates.io removes HTML comments
oci Docker Hub, GHCR, Quay.io, Google Artifact Registry, Azure Container Registry, Microsoft Container Registry Annotation io.modelcontextprotocol.server.name of the image
mcpb GitHub and GitLab releases URL contains "mcp"; fileSha256 with the SHA-256 of the file is required

For an npm package the marker looks like this:

JSON
{
  "name": "@example-user/mcp-weather-server",
  "version": "1.2.0",
  "mcpName": "io.github.example-user/weather"
}

For an OCI image the annotation is set with a LABEL instruction in the Dockerfile, for example LABEL io.modelcontextprotocol.server.name="io.github.example-user/weather". The registry does not check the hash of an MCPB file; according to the documentation, MCP clients check it before installation.

Only these public registries are accepted. Private package registries and mirrors are not supported by the official registry.

Remote servers

A remote server is described in the remotes array. Such an entry needs no packages, and package verification does not apply to it. The URL must be publicly accessible.

  • Transport. type is streamable-http or sse. The documentation recommends Streamable HTTP and describes SSE as deprecated, to be published only for existing clients.
  • URL variables. The URL can contain variables in curly braces, such as https://{tenant_id}.analytics.example.com/mcp, with a description, a default value and a list of choices in variables. The user supplies the values when configuring the server.
  • Headers. headers lists HTTP headers that the client must send, for example an API key, with the flags isRequired and isSecret.

The registry checks control of the namespace, not of the URL. Each remote URL can belong to only one server name: a publication with a URL already used by another server fails. packages and remotes can be combined, and the host application then chooses the way to install.

Publishing with mcp-publisher

mcp-publisher is installed as a pre-built binary from the releases of the modelcontextprotocol/registry repository or with Homebrew. Its commands:

Command What it does
mcp-publisher init Creates a server.json template from the project files
mcp-publisher validate Checks server.json against the schema and the rules of the registry without publishing
mcp-publisher login <method> Logs in: github, github-oidc, dns, http; none only for a local registry
mcp-publisher publish Sends server.json to the registry
mcp-publisher status Changes the status of a version or of all versions: active, deprecated, deleted
mcp-publisher logout Deletes the stored token

A typical publication of an npm-based server consists of publishing the package and then its metadata:

Bash
# The package goes to npm first: the registry stores only metadata
npm publish --access public

# Create and check server.json
mcp-publisher init
mcp-publisher validate

# Log in with GitHub and publish
mcp-publisher login github
mcp-publisher publish

During publication the registry validates the document, checks the namespace against the token and verifies the ownership of each package.

Publication can be automated with GitHub Actions. The documentation recommends OIDC, pinning a specific release of mcp-publisher and verifying its Sigstore signature before use. Running tests in such pipelines is described in the article Automated tests in CI.

Versions and statuses

Each publication has its own version, unique for the server. A published version cannot be changed: to correct metadata, a new version is published. The registry recommends semantic versioning but accepts any string, except strings that look like ranges, such as ^1.2.3, ~1.2.3, >=1.2.3 or 1.x.

The registry marks a version as the latest (isLatest) by comparing semantic versions. A version that cannot be parsed as a semantic version is always marked as the latest. To change only the metadata without a new package, it recommends a prerelease version such as 1.2.3-1; such a version sorts before 1.2.3 and does not become the latest if published after it.

The status of a version is the only field that changes after publication:

Status Meaning
active The server is visible in default listings
deprecated The server stays visible, with a message such as "Please upgrade to 2.0.0"
deleted The server is hidden from default listings; the metadata remains available with include_deleted=true

Metadata is never removed completely. A deleted server can be restored by setting the status back to active.

Registry API

The API of the official registry is open for reading without authentication. The main endpoints:

Endpoint What it returns
GET /v0.1/servers List of servers, one record per version; parameters search, version, updated_since, include_deleted, limit, cursor
GET /v0.1/servers/{serverName}/versions All versions of a server
GET /v0.1/servers/{serverName}/versions/{version} One version; latest returns the latest one

Server names in the path are URL-encoded: io.github.example-user%2Fweather. The list uses cursor pagination: the response contains metadata.nextCursor, which is passed as cursor in the next request. version=latest returns only the latest version of each server. updated_since with an RFC 3339 timestamp returns the servers changed since then and is used for incremental synchronization.

The documentation expects aggregators to read the registry on a regular but infrequent schedule, for example once per hour, and to keep the data in their own storage. The official registry gives no guarantees of availability or data durability.

Subregistries and private registries

The registry defines an OpenAPI specification of its API. A subregistry is an aggregator that implements this specification, so host applications can read it in the same way as the official registry. A subregistry can add its own metadata, such as ratings, download counts or scan results, under its own key in _meta, for example com.example.subregistry/custom.

Private registries of companies implement the same specification for their internal servers. In the specification, the publication endpoints are optional, and a registry can be read-only. A registry that requires authentication follows the MCP authorization specification and acts as an OAuth 2.1 resource server; the recommended scopes are mcp-registry:read and mcp-registry:write. The official registry itself uses its own JWT-based tokens for publication.

The code of the official registry is open, but according to its documentation it is not designed for self-hosting, and the maintainers do not support such use. An organization that forks it maintains and operates the fork on its own.

Moderation

The moderation policy of the official registry is permissive. The registry removes illegal content, malware, spam and servers that do not work. Spam includes, for example, the same server published under different names.

The registry does not remove low-quality or buggy servers, servers with security vulnerabilities, duplicates of other servers or servers with adult content. The policy states that the registry makes no guarantees about moderation and relies on package registries and subregistries for deeper checks. A removed server gets the status deleted, and its metadata remains available through the API; in extreme cases, such as unlawful metadata, it can be overwritten or erased. Abuse is reported to the package registry and in an issue of the registry repository whose title starts with "Abuse report:".

The registry, package registries and subregistries

The table compares the MCP Registry with the two kinds of systems it works with.

Package registry MCP Registry Subregistry or marketplace
What it stores Code and binaries Metadata: name, description, packages, endpoints Copy of the metadata plus its own data
Who publishes Package author Server publisher, with verified namespace and package Takes data from the MCP Registry
Curation Own scanning and policies Minimal: illegal content, malware, spam, broken servers Ratings, scans, selection
Consumers Package managers Aggregators and subregistries Host applications and users
Example npm, PyPI, Docker Hub registry.modelcontextprotocol.io GitHub MCP Registry, a private company registry

The MCP Registry does not replace a package registry. A package is published first, in its own registry, and the MCP Registry refers to it. The ownership markers connect the two: the package names the server, and the server names the package.

A subregistry does not replace the MCP Registry either: it takes the data from it and applies its own selection. Testing a server before publication is described in the article Testing MCP servers, and regression checks between versions in the article Regression testing of an MCP server.

Terms

Term Meaning
MCP Registry Official catalog of metadata about publicly available MCP servers at registry.modelcontextprotocol.io
server.json JSON document that describes an MCP server: name, description, version, packages, remote endpoints
Server namespace Part of the server name before /, in reverse-DNS form, tied to a GitHub account or a domain
Package ownership marker Value in a package, such as mcpName or mcp-name:, that names the server and links the package to it
mcp-publisher Official CLI for creating, validating and publishing server.json
Remote server entry Element of remotes with the transport type and the public URL of a server
Subregistry Aggregator that copies data from the MCP Registry, adds its own and implements the same API
Private registry Registry of an organization that implements the registry API for internal servers

Sources

Series

Model Context Protocol (MCP)
  1. What is MCP (Model Context Protocol)
  2. Tools in MCP
  3. Resources and resource templates in MCP
  4. Prompts in MCP
  5. MCP transports: stdio and Streamable HTTP
  6. Stateless MCP: changes in 2026-07-28
  7. Authorization in MCP
  8. MCP security
  9. MCP extensions
  10. MCP server over an existing API
  11. Testing MCP servers: the basics
  12. Evaluating an MCP server with models
  13. Regression testing of an MCP server
  14. Publishing an MCP server to the MCP RegistryCurrent

Wiki articles are written and maintained by the ComplexQA team.