You built the server. You deployed it. Now you need developers — and their AI agents — to actually find it. This is the complete listing guide: official registry, PulseMCP, Smithery, and the 4 errors that will stop you if you don't know they're coming.
You don't submit to PulseMCP. You don't submit to Smithery. You submit once to the Official MCP Registry — and every aggregator in the ecosystem ingests from it automatically.
The MCP ecosystem has a clear hierarchy. At the top is registry.modelcontextprotocol.io — the canonical, Anthropic-affiliated source of truth for all MCP servers. Below it are aggregators: PulseMCP, Smithery, and a growing list of client-side discovery tools. They all pull from the registry. Submit once, appear everywhere.
When a developer using Claude, Cursor, or Windsurf searches for a commerce MCP server, they search PulseMCP or their client's built-in directory — not the official registry directly. The registry is the backend; PulseMCP is the storefront. Getting into the registry gets you onto the storefront automatically.
This guide assumes your server is already built and deployed. If it's still on your laptop, deploy it first — the registry needs a live URL to verify your server is real.
| What you need | Why | Where to get it |
|---|---|---|
| A deployed server URL | The registry lists live endpoints, not local servers. Must return a valid MCP response at the /mcp path. | Vercel, Railway, Render, Fly.io, or any public host. See the MCP Server Build Guide. |
| A GitHub account | The registry uses GitHub OAuth to verify namespace ownership. Your namespace must match your GitHub username exactly, including casing. | github.com — free account is fine. |
| A public GitHub repo | The registry requires a repository URL. It doesn't need to be the server code itself — it can be a starter, a README, or a reference implementation. | Create a new public repo at github.com/new. |
| Homebrew (macOS) or Node 18+ (Windows) | Required to install the mcp-publisher CLI. | brew.sh for macOS. github.com/modelcontextprotocol/registry/releases for Windows binaries. |
server.json is a structured description of your MCP server. The mcp-publisher CLI reads it and sends it to the registry. Get the fields right here and the publish command works first time.
Some MCP tutorials reference mcp.json — that is a different format used by the Desktop Extension installer. The official registry requires server.json with the schema URL below. They are not interchangeable.
This is the server.json for the MCP Commerce Server Starter — a real listing that is live in the registry right now. Every field is filled in correctly. Use it as your template.
server.json{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.YourGitHubUsername/your-repo-name",
"title": "Your Server Display Name",
"description": "One sentence. Must be 100 characters or fewer.",
"version": "1.0.0",
"websiteUrl": "https://yourdocumentationurl.com",
"repository": {
"url": "https://github.com/YourGitHubUsername/your-repo-name",
"source": "github"
},
"remotes": [
{
"type": "streamable-http",
"url": "https://your-deployed-server.vercel.app/mcp"
}
]
}
| Field | Required | Rules | Common mistake |
|---|---|---|---|
$schema |
Yes | Must be the exact URL shown — do not modify it. | Using an older schema URL from a tutorial. Always use 2025-12-11. |
name |
Yes | Format: io.github.YourUsername/repo-name. Casing must match your GitHub username exactly. |
Lowercase when GitHub account has capitals (e.g. newplanetww instead of NewPlanetWW) → 403 error. |
title |
No | Human-readable display name shown in directory listings. | Skipping it — without it, directories show the raw namespace. |
description |
Yes | Plain text. Maximum 100 characters. Count carefully. | Going over 100 chars → 422 error. The limit is stricter than it looks. |
version |
Yes | Semantic version string: 1.0.0. Increment when you update. |
None — this field is forgiving. |
websiteUrl |
No | URL to your documentation, guide, or landing page. | Leaving it blank — this is where directory listings link for "Learn more." |
repository |
Yes | Object with url (full GitHub URL) and source (always "github"). |
Forgetting "source": "github". |
remotes |
If no packages | Array. Each item needs type ("streamable-http" or "sse") and url. |
Using "transportType" instead of "type" → validation error. |
packages |
If no remotes | For PyPI, npm, Docker, or NuGet packages. Use if your server is distributed as an installable package rather than a hosted endpoint. | Using this when you have a remote endpoint — use remotes instead. |
Use remotes if your server is deployed to a URL (Vercel, Railway, Render, your own host). This is the most common case for MCP servers. Use packages if your server is distributed as a pip install or npm package that users run locally. If you're not sure, you want remotes.
mcp-publisher is a small CLI tool built and maintained by the MCP Registry team. You install it once per machine and use it for every server you list.
brew install mcp-publisher
Download the binary from the registry releases page. Extract it and add it to your PATH.
mcp-publisher --version
# mcp-publisher 1.7.9 (or newer)
If you installed mcp-publisher previously, check that it's current: brew upgrade mcp-publisher. Older versions may not support the latest schema version.
Before you can publish, the registry needs to verify that the GitHub account in your namespace actually belongs to you. This is a one-time browser step per session.
From any terminal directory:
mcp-publisher login github
The CLI prints a device code and a URL:
Logging in with github...
To authenticate, please:
1. Go to: https://github.com/login/device
2. Enter code: XXXX-XXXX
3. Authorize this application
Waiting for authorization...
Go to github.com/login/device in your browser. Enter the code shown in the terminal exactly. Click Authorize.
The terminal completes automatically within a few seconds:
Successfully authenticated!
✓ Successfully logged in
The JWT token issued at login expires quickly — often within a few minutes. If you authenticate, then make edits to server.json, then try to publish, you'll see: Invalid or expired Registry JWT token. The fix: chain the commands so publish runs immediately after login with no gap between them.
mcp-publisher login github && mcp-publisher publish
What you just authorized: identity verification only. The registry confirms "this person owns this GitHub account." No access to your code, repositories, or other GitHub data is granted. This is equivalent to signing a package before putting it on a shelf.
The publish command itself is trivial. What trips people up is the validation — the registry has strict rules that it enforces at submission time. Know these four errors before you run it and you'll clear them on the first try.
Run from the directory containing your server.json. Chain it with login to avoid the token expiry issue:
mcp-publisher login github && mcp-publisher publish
On success:
Publishing to https://registry.modelcontextprotocol.io...
✓ Successfully published
✓ Server io.github.YourUsername/your-repo version 1.0.0
The registry enforces a hard 100-character limit on the description field. The error shows you the offending value:
{"message":"expected length <= 100","location":"body.description"}
The registry matches your namespace against your GitHub account name with case sensitivity. If your account is NewPlanetWW and your server.json says newplanetww, it fails:
{"detail":"You do not have permission to publish this server.
You have permission to publish: io.github.NewPlanetWW/*
Attempting to publish: io.github.newplanetww/..."}
name field in server.json. Character-for-character match required.The registry schema uses "type" for the transport type inside remotes. Some tutorials and auto-generated templates use "transportType" — which fails validation:
{"message":"value must be \"streamable-http\"","location":"remotes[0].type"}
{"message":"unsupported transport type for remotes"}
remotes array, use "type": "streamable-http" — not "transportType". The field name is type, full stop.If too much time passes between mcp-publisher login and mcp-publisher publish, the session token expires:
{"detail":"Invalid or expired Registry JWT token"}
mcp-publisher login github && mcp-publisher publish. The && operator runs publish immediately after login completes, before the token has time to expire.The publish command reports success, but always verify directly against the registry API. This takes 10 seconds and tells you exactly what the registry has on file.
curl "https://registry.modelcontextprotocol.io/v0/servers?search=YourGitHubUsername"
A successful listing looks like this:
{
"servers": [
{
"server": {
"name": "io.github.YourUsername/your-repo",
"title": "Your Server Display Name",
"description": "Your description here.",
"version": "1.0.0",
...
},
"_meta": {
"io.modelcontextprotocol.registry/official": {
"status": "active",
"publishedAt": "2026-05-24T00:48:03Z",
"isLatest": true
}
}
}
],
"metadata": { "count": 1 }
}
What to look for: "status": "active" and "isLatest": true. Both present means you're live.
While you're verifying, hit your health endpoint to confirm the deployed server is responding: curl https://your-project.vercel.app/health. The registry lists a URL — make sure that URL is actually alive.
Once you're in the official registry, PulseMCP and Smithery pick you up automatically — but not instantly. Here's the timeline and how to speed it up.
| Directory | How it ingests | Normal timeline | How to expedite |
|---|---|---|---|
| PulseMCP | Ingests from the official registry daily, processes new entries weekly | Up to 7 days | Email hello@pulsemcp.com after publishing — they respond to direct requests. Mention your server name and registry namespace. |
| Smithery | Aggregates from the official registry on its own schedule | 3–14 days | Smithery has a manual submission option at smithery.ai for faster inclusion. |
| MCP clients (Claude, Cursor, Windsurf) | Pull from PulseMCP or the registry API directly | Within days of PulseMCP listing | No direct action needed — follows PulseMCP automatically. |
PulseMCP doesn't just mirror the registry. It enriches each listing with popularity data (GitHub stars, download counts), security analysis, compatibility flags, and editorial categorization. A server with a complete server.json, a polished README, and a live endpoint gets a richer listing than one with bare minimum fields. Quality of the GitHub repo matters.
The registry is versioned. When you make significant changes to your server — new tools, new deployment URL, updated description — republish with an incremented version number.
Bump the version field. Follow semantic versioning: new tools = minor bump (1.0.0 → 1.1.0), bug fixes = patch bump (1.0.0 → 1.0.1), breaking changes = major bump (1.0.0 → 2.0.0).
"version": "1.1.0"
New Vercel URL? Update remotes[0].url. Better description? Update description. New documentation page? Update websiteUrl.
mcp-publisher login github && mcp-publisher publish
The registry replaces your existing entry. PulseMCP picks up the update on its next cycle.
Keep server.json in your GitHub repository alongside server.py and README.md. When you push a code change to GitHub, also update and republish server.json. Treat it like a package manifest — it should always reflect the current state of the deployed server.
The official registry at registry.modelcontextprotocol.io is the canonical source — you publish there using the mcp-publisher CLI. PulseMCP is an aggregator: it ingests from the official registry daily and adds extra data like popularity scores and security analysis. You never submit directly to PulseMCP. Submit to the registry and PulseMCP picks you up automatically within about a week.
No. If your server is deployed to a URL (Vercel, Railway, Render, etc.), use the remotes field in server.json instead of packages. You do not need to publish to PyPI, npm, or Docker Hub. A live URL and a public GitHub repository are sufficient to get listed.
The JWT token issued at login expires quickly. If you see Invalid or expired Registry JWT token, run both commands chained together: mcp-publisher login github && mcp-publisher publish. The && runs publish immediately after login completes, before the token expires.
PulseMCP ingests from the official registry daily and processes new entries weekly. Expect your listing to appear within 7 days. To expedite, email hello@pulsemcp.com after publishing — mention your server name and registry namespace. They are responsive to direct requests.
The registry validates your namespace against your authenticated GitHub account with case sensitivity. If your GitHub account is NewPlanetWW, your namespace must be io.github.NewPlanetWW — not io.github.newplanetww. A mismatch returns a 403 Forbidden error even though the account is otherwise correct. Open your GitHub profile and copy your username character-for-character.
Yes. Increment the version field in server.json (e.g. 1.0.0 → 1.0.1), update any changed fields, then run mcp-publisher login github && mcp-publisher publish again. The registry replaces your existing entry with the new version. PulseMCP picks up the update on its next ingestion cycle.
The MCP Registry has over 15,000 servers — but the vast majority are developer tools, data connectors, and internal utilities. The commerce layer is wide open. An agent that can browse products, search a catalog, and initiate checkout is still rare enough that listing one makes you findable by anyone looking for it. That window is open now. It won't be in 18 months.
Back to MCP Server Ops →Sources: Official MCP Registry · PulseMCP · modelcontextprotocol/registry on GitHub · MCP Registry Publishing Guide · Smithery. Verify all timelines and limits against live sources — the MCP ecosystem moves fast.
New MCP Server Ops spokes ship every few weeks — testing, auth, databases, Stripe, and more. Drop your email and we'll let you know.