
This lesson is part of Learn MCP, our free course on the Model Context Protocol, within The MCP Guide.
In this lesson you will publish an MCP server to the official MCP Registry. You will prepare your package, create a server.json file, prove you own the namespace, publish with the mcp-publisher command-line tool, and check that the listing is live.
The steps follow the official registry quickstart and related registry docs, checked on 28 October 2026. As of October 2026 the registry is in preview. The docs warn that "breaking changes or data resets may occur before general availability." Re-check the quickstart before you publish, because commands may change.
Publishing is public and permanent for each version. Finish Lesson 27: Version and Update Your Server first, so your version numbers are ready.
Key Takeaways
- The MCP Registry stores metadata about public servers; your code still lives on npm, PyPI, NuGet, Docker Hub or your own remote URL.
- Your server's registry name is tied to a namespace you prove you own:
io.github.<username>/via GitHub login, or a reverse-DNS domain via DNS or HTTP verification. - The registry checks that your package points back to the same name, for example with
mcpNameinpackage.jsonor anmcp-name:line in a PyPI README. - Each published version is immutable, and as of October 2026 you cannot delete or unpublish a server.
- The registry does not security-scan servers; it relies on package registries and downstream aggregators for that.
What the registry is (and isn't)
The About the registry page calls it "the official centralized metadata repository for publicly accessible MCP servers." It hosts metadata that points to packages, not the packages themselves.
It is designed mainly for downstream aggregators, such as marketplaces, rather than for host apps to read directly. It does not support private servers. And it "delegates security scanning" to package registries and aggregators. For the business view, read what the MCP Registry is.
Step 1: Prepare a public package or a public URL
The registry accepts a server if its install method is public, such as a public npm package, or the server itself is publicly reachable.
For a local server, publish the package first. The quickstart uses an npm package and these commands:
npm install
npm run build
npm adduser
npm publish --access public
For a remote server, you need a public HTTPS endpoint. The remote servers guide says remote servers should use Streamable HTTP, and that the SSE transport is deprecated. Lesson 21 covers deployment.
Step 2: Add the ownership marker to your package
The registry verifies that your package claims the same server name you publish. The method depends on the package type, per the package types guide:
| Package type | Ownership marker |
|---|---|
| npm | "mcpName": "io.github.my-username/weather" in package.json |
| PyPI | mcp-name: io.github.my-username/weather in the README (may be an HTML comment) |
| NuGet | mcp-name: line in the README |
| Cargo | mcp-name: as visible text in the README (crates.io strips HTML comments) |
| Docker/OCI | LABEL io.modelcontextprotocol.server.name="..." |
The quickstart is strict about the name: with GitHub login, mcpName "must start with io.github.my-username/." Rebuild and republish the package after you add the marker.
Step 3: Install mcp-publisher
On macOS or Linux, the quickstart offers Homebrew or a prebuilt binary:
brew install mcp-publisher
mcp-publisher --help
The help output lists four commands: init, login, logout and publish. Windows users can download the binary with the PowerShell command in the quickstart.
Step 4: Create server.json
In your project folder, run:
mcp-publisher init
This generates a template. After editing, a minimal npm-based file from the quickstart looks like this:
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.my-username/weather",
"description": "An MCP server for weather information.",
"repository": {
"url": "https://github.com/my-username/mcp-weather-server",
"source": "github"
},
"version": "1.0.1",
"packages": [
{
"registryType": "npm",
"identifier": "@my-username/mcp-weather-server",
"version": "1.0.1",
"transport": {
"type": "stdio"
}
}
]
}
Three rules to check:
namemust match your package'smcpName.versionmust be unique for every publication. The versioning guide recommends semantic versioning and prohibits ranges such as^1.2.3.- If your server needs an API key, the template's
environmentVariablesentry can mark itisSecret: true. Never put a real key in this file.
A remote server uses a remotes array instead of, or alongside, packages, with "type": "streamable-http" and the URL. The remote guide also shows headers for API keys and URL variables for multi-tenant setups.
Write a plain, honest description. The moderation policy says maintainers remove spam, including "a server with a description stuffed with marketing copy and an unrelated implementation."
Step 5: Log in to prove namespace ownership
The authentication guide offers three methods:
| Method | Name format | How you prove it |
|---|---|---|
| GitHub | io.github.username/* or io.github.orgname/* | Device-code login in the browser |
| DNS | com.example.*/* | A TXT record with your public key |
| HTTP | com.example.*/* | A key file at /.well-known/mcp-registry-auth |
For GitHub, run:
mcp-publisher login github
The tool prints a code. Open https://github.com/login/device, enter it and authorize. A company with its own domain will usually prefer DNS login so listings appear as com.yourcompany/... rather than under a personal GitHub account.
Step 6: Publish
mcp-publisher publish
The quickstart's sample output ends with "Successfully published" and the server name and version. If you see "You do not have permission to publish this server," your login method doesn't match your name's namespace. If you see "Registry validation failed for package," the ownership marker from Step 2 is missing or wrong.
Step 7: Verify the listing
Search the registry API for your server name:
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.my-username/weather"
When we ran a search against this endpoint on 28 October 2026, each result included your server metadata plus a registry-added _meta block with fields such as status, publishedAt and isLatest.
Step 8: Automate future releases
The GitHub Actions guide shows a workflow that runs on version tags such as v1.0.0. It builds and tests, publishes the package, then runs mcp-publisher login github-oidc and mcp-publisher publish. The OIDC method needs id-token: write permission and no stored registry secret.
Try it
You can practice safely without publishing anything.
- Run
mcp-publisher initin your project and read the generatedserver.json. - Fill in
name,descriptionandversion, and add the matching ownership marker to your package. - Run the
curlsearch above with your intended name to confirm it is not taken. - Write a 1–2 sentence description a stranger would understand. Remove any marketing words.
Only run mcp-publisher publish when the server is ready for strangers, because you can't unpublish it.
Recap
You learned that the registry stores metadata, not code. You added an ownership marker, created server.json, proved your namespace with GitHub, DNS or HTTP, published, verified the listing and saw how to automate releases. Being listed also helps people find you; our guide on how to market an MCP server covers what comes next.
Course navigation
Previous lesson: Lesson 27: Version and Update Your Server.
Next lesson: Lesson 29: Long-Running Tasks and MCP Apps.
Back to the Learn MCP course outline.
Frequently asked questions
Does listing in the registry mean my server is approved or safe?
No. The registry verifies namespace ownership, not code quality. Its moderation policy says it is "quite permissive" and consumers "should assume minimal-to-no moderation." Users should still review servers, as in Lesson 9: Read a Server Before You Trust It.
Can I remove or edit a published version?
Not as of October 2026. The registry FAQ says you currently cannot delete or unpublish a server, and version metadata is immutable. To change details, publish a new version.
How do I update only the description without a new package release?
The versioning guide suggests a prerelease version such as 1.2.3-1 for registry-only updates. It warns that a prerelease published after 1.2.3 will not be marked "latest," because semantic versioning sorts it earlier.
Can I publish a private, internal server?
No. The registry does not support private servers. The About page suggests running your own registry that implements the official OpenAPI spec for that.
Will Claude or ChatGPT show my server automatically once it's listed?
Not necessarily. The registry is meant to feed aggregators and marketplaces, and each app has its own directory and review rules. The registry is one channel among several.











