The official MCP registry refuses a server.json whose remotes[].url is
already claimed by a server with a different name. The publish fails with 400 and this message:
400: remote URL https://mcp.zovo.one/mcp/pdf is already used by server
io.github.theluckystrike/pdf-merge-split-stamp-extract-pages
That is not documented on the registry's publishing pages. It is in the code. From
internal/service/registry_service.go in modelcontextprotocol/registry,
function validateNoDuplicateRemoteURLs, read 2026-09-09:
for _, remote := range serverDetail.Remotes {
filter := &database.ServerFilter{RemoteURL: &remote.URL}
conflictingServers, _, err := s.db.ListServers(ctx, tx, filter, "", 1000)
...
for _, conflictingServer := range conflictingServers {
if conflictingServer.Server.Name != serverDetail.Name {
return fmt.Errorf("remote URL %s is already used by server %s", ...)
}
}
}
The check runs inside the publish transaction, on every remote in the submission, against every row in the table.
Other publishers hit it and filed:
Give every server its own URL path and treat that path as permanent. A gateway at
https://example.com/mcp serving several logical servers can list only one of them,
because they would all declare the same URL. Paths of the form
https://example.com/mcp/<server> give each name something of its own to claim.
If you have already collided, one escape exists and it is legitimate rather than a trick: add a second, distinct endpoint path that answers the same server, and publish the new name against that path. Both rows then work, both are honest about where they point, and neither is a duplicate of the other's URL. Nothing in the schema requires two names to share an endpoint.
The other case that works is a server with no remotes block at all. A stdio package
or a downloadable bundle has no URL to collide with, so the same code can be published under two
names for comparison. That is how the namespace comparison behind
how registry search works was run at all: the one
server in this catalogue that ships without a hosted endpoint.
It compares URLs, not hosts. Two servers on the same domain with different paths are fine. It also does not follow redirects or resolve DNS, so a URL that no longer works still holds its claim. An independent survey filed as #1485 on 2026-07-28 found 80 remote hosts that no longer resolve, still listed.
Sources: the registry's own source at internal/service/registry_service.go and
internal/database/postgres.go, read from the main branch on 2026-09-09; the publish
failure above, produced by mcp-publisher publish against the live registry on
2026-09-08 and recorded in docs/NAMESPACE_R1.md in this repository; the registry FAQ at
modelcontextprotocol.io/registry/faq; the linked issues.
Yes. The loop runs over every entry in the remotes array whatever its type, so a streamable-http URL and an sse URL are each claimed independently. Publishing both types at different URLs under one name is fine, because the name comparison only fires when the conflicting row has a different name.
Yes. The conflict check skips rows whose name matches the one being published, so new versions of your own server are unaffected. What it stops is a second name pointing at a URL you already used.
It makes no difference. The comparison is on the server name string, not on the publisher or the authenticated namespace, so two names you both own still collide.
Open issues ask for deleted and deprecated rows to be excluded from the check, which would help anyone reusing a URL after retiring a name. Nothing suggests the basic one-URL-one-name rule is going away, and designing around it costs nothing.
A directory that resolved one endpoint to several names would let anyone attach their own name and description to somebody else's running service. Binding the URL to the first name that claimed it makes the listing mean something.
All MCP servers and prices · All guides · Buy the bundle $39