8. Distribution to clients and developers
Question: How do users and developers connect to the interface?
Rationale
A server that nobody can find or configure serves nobody. Users of assistants need a configuration they can paste into their application. Developers of agents need the manifest, the guidance, the terms, and an endpoint they can test against. Registries need a listing in their own format. Each of these pieces is small, and their absence is the usual reason a working server has no traffic.
Distribution is therefore a short list of published things: a developer page that holds them all, a listing where clients look for servers, and a support channel through which the organization hears when something is wrong.
Target state
- A developer page publishes the endpoint, the client configurations, the manifest, the guidance resource, the tiers and the terms, the changelog, and the support contact.
- The server is listed in the MCP registry with a listing that passes the format check, and in the organization's own catalog.
- The configurations are tested with the common assistants and frameworks at each release.
Maturity levels
| Level | Steps |
|---|---|
| Foundational | The developer page is published with the endpoint, one client configuration, the terms, and a contact. |
| AI-ready | Configurations exist for the common assistants and frameworks. The registry listing is published and checked. The configurations are tested at each release. |
| AI-native | A server package is published for local use beside the hosted endpoint. The listing and the configurations are updated automatically from the manifest and the version. |
The example server's developer page holds a configuration for an assistant that connects over streamable HTTP with a bearer token. The registry listing names the hosted endpoint and a package for local use, and the listing check passes with no errors or warnings.
Recipes
8.1 Publish the client configurations
- Level
- Foundational
- Skills
- Developer; dissemination officer
- Indicative time
- Half a day; tested each release
Result: a user can connect their assistant to the server by pasting a short configuration, and a developer can connect a framework with a few lines, because both are published and have been tested.
An assistant such as a desktop chat application learns about a server through a configuration block in its settings. The block names the server, gives its address, and says how to authenticate. Each client has its own format, and a user who has to work the format out from the specification usually gives up. The configuration for the running example, for a desktop assistant, is:
{
"mcpServers": {
"statistics-example": {
"url": "https://stats.example/mcp",
"transport": "streamable-http",
"headers": {"Authorization": "Bearer <token issued by the organization>"}
}
}
}
- Publish a configuration for each kind of client the organization's
users have: desktop assistants that take an
mcpServersblock, assistants that add servers through a settings page, coding tools, and agent frameworks. The Data360 server documents connection from several clients, and its page is the pattern to follow. - State for each configuration the transport (streamable HTTP for the hosted endpoint, stdio for a package run locally), where the key goes, and the first question to try.
- Test every configuration with each release, as chapter 9 describes, and keep a screenshot or a transcript of the first question's answer, so that a user can compare what they see with what they should see.
Worked example. The running example's configuration block names the
server statistics-example, points it at https://stats.example/mcp,
and carries the client's key in an Authorization: Bearer header. The
page beside it says: "Paste this block into the mcpServers section of
the assistant's settings file, replace YOUR_KEY with the key issued at
registration, restart the assistant, and ask: What was the prevalence of
undernourishment in 2024? The answer should state 7.6% and cite
https://stats.example/series/FS_UNDERNOURISH_PCT."
What this does not do. Configurations change when the clients change. The page says which client versions were tested and on which date, and a user with a newer client may have to adapt.
8.2 List the server in the registry and the catalog
- Level
- AI-ready
- Skills
- Developer
- Indicative time
- Half a day
Result: the server appears where clients and developers look for servers, with a listing that passes the format check.
The MCP registry is a public directory of servers. A listing is a JSON
file with the server's name, its version, a description, the hosted
endpoint, and the installable package where one exists. The name is
written under the organization's domain in reverse, for example
org.example.stats/statistics-example, and the registry verifies that
the publisher owns that domain, which is how a user can tell the
organization's server from an imitation. The script checks a listing
against the registry's format:
"""Check a server listing (server.json) before publishing it to a registry.
Reads a server.json in the MCP registry format and reports the required
fields (a reverse-DNS name such as org.example.stats/server, a semantic
version), the fields a client needs to connect (a remote with transport
streamable-http or sse and an https URL, or a package with a registry type
and a transport), and the fields a person needs to trust the listing
(title, description, website, repository). Exit status 1 when a required
or connection field is missing. Uses jsonschema for the listing's shape.
Usage:
python check_server_listing.py server_listing.json
What this does not do: it checks the listing's shape against the format
documented by the registry at the time of writing; the registry validates
against its own schema (the ``$schema`` URL) on submission, and the
version of that schema changes. Whether the endpoint answers is the
operation chapter's check.
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from jsonschema import Draft202012Validator
# The parts of the registry's server.json format that a listing needs; the
# registry's own dated schema (named in $schema) is the full definition.
SCHEMA = {
"type": "object",
"required": ["name", "version"],
"properties": {
"name": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9.-]*\\.[a-z0-9.-]+/[A-Za-z0-9._-]+$",
},
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?$",
},
"remotes": {
"type": "array",
"items": {
"type": "object",
"required": ["type", "url"],
"properties": {
"type": {"enum": ["streamable-http", "sse"]},
"url": {"type": "string", "pattern": "^https://"},
},
},
},
"packages": {
"type": "array",
"items": {
"type": "object",
"required": ["registryType", "identifier", "version", "transport"],
},
},
},
"anyOf": [
{"required": ["remotes"], "properties": {"remotes": {"minItems": 1}}},
{"required": ["packages"], "properties": {"packages": {"minItems": 1}}},
],
}
MESSAGES = {
(
"name",
"pattern",
): "name must be reverse-DNS namespace plus server name, for example org.example.stats/statistics-example",
("version", "pattern"): "version must be a semantic version such as 1.0.0",
}
def describe(error) -> str:
path = list(error.absolute_path)
key = (path[0] if path else "", error.validator)
if key in MESSAGES:
return MESSAGES[key]
if error.validator == "anyOf":
return "a listing needs at least one remote (hosted endpoint) or one package (installable server)"
if path[:1] == ["remotes"] and error.validator == "enum":
return f"remotes[{path[1]}].type must be one of ['sse', 'streamable-http']"
if path[:1] == ["remotes"] and error.validator == "pattern":
return f"remotes[{path[1]}].url must be an https URL"
if path[:1] == ["packages"] and error.validator == "required":
return f"packages[{path[1]}] lacks {error.message.split()[0].strip(chr(39))}"
return ".".join(map(str, path)) + ": " + error.message
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("listing", type=Path)
args = parser.parse_args(argv)
s = json.loads(args.listing.read_text(encoding="utf-8"))
errors = [
describe(e)
for e in sorted(
Draft202012Validator(SCHEMA).iter_errors(s),
key=lambda e: list(e.absolute_path),
)
]
warnings = [
f"{key} missing; clients show it to users"
for key in ("title", "description", "websiteUrl")
if not s.get(key)
]
if not (s.get("repository") or {}).get("url"):
warnings.append(
"repository.url missing; readers cannot inspect the server's code"
)
if "$schema" not in s:
warnings.append(
"$schema missing; the registry validates against a dated schema"
)
if len(s.get("description", "")) > 300:
warnings.append(
f"description is {len(s['description'])} characters; keep it under 300"
)
remotes, packages = s.get("remotes", []), s.get("packages", [])
print(
f"{args.listing.name}: {s.get('name')} {s.get('version')}; {len(remotes)} remote(s), {len(packages)} package(s)"
)
for e in errors:
print(f"error {e}")
for w in warnings:
print(f"warning {w}")
print(f"{len(errors)} error(s), {len(warnings)} warning(s)")
return 1 if errors else 0
if __name__ == "__main__":
sys.exit(main())
It runs with the listing as its argument:
python check_server_listing.py server_listing.json
For the running example the output is:
server_listing.json: org.example.stats/statistics-example 1.0.0; 1 remote(s), 1 package(s)
0 error(s), 0 warning(s)
The first line names the listing, its version, and how many hosted endpoints (remotes) and packages it declares. The second line counts the problems found.
- Write the listing, following the running example's server_listing.json. It holds the name, the version, a title and a description, the website, the repository, the hosted endpoint with its transport and URL, and the package where one exists.
- Run the check. Then publish the listing to the MCP registry with its publisher tool, which validates the file against the dated schema and verifies that the organization owns the namespace.
- List the server in the organization's own catalog and developer page, and in the AI component register. Update the listing's version with each release.
Worked example. The running example's listing declares one remote,
the streamable HTTP endpoint at https://stats.example/mcp, and one
package, statistics-example-mcp on PyPI, for users who want to run the
server locally over stdio. Its description reads "Read-only access to the
published statistics of the example organization: search, metadata,
observations, and code lists, with provenance in every response." The
check passed, and the listing was published under the namespace
org.example.stats after the registry verified the domain.
What this does not do. A listing makes the server findable. The registry does not vouch for it. Users decide to trust the organization's domain, which is why the namespace and the website matter.
8.3 Publish the developer page and the support channel
- Level
- Foundational
- Skills
- Dissemination officer; developer
- Indicative time
- Half a day; ongoing
Result: one page holds everything a user or a developer needs in order to connect to and use the server, and there is a way to reach the organization when something is wrong.
The developer page is the single address the organization gives out. Every other chapter produces something that belongs on it, and a page that collects them saves the user from hunting through the catalog. The support channel closes the loop: a user who finds a wrong answer has somewhere to report it, and the report reaches the evaluation.
- Put on the page:
- the endpoint and the transport;
- the client configurations of recipe 8.1;
- the manifest of chapter 2 and the guidance resource of chapter 3;
- the tiers, the terms, and the registration form of chapter 5;
- the changelog and the deprecation policy of chapter 9;
- the licence, the citation form, and the support contact.
- Add a "first question" walkthrough with the expected answer, so that a user can tell a working connection from a broken one.
- Open a support channel, such as an address or an issue tracker, and state the response time. Route bug reports about answers to the evaluation of chapter 7, and misquotes of the organization's figures to the monitoring cookbook.
- Link the page from the catalog's API documentation and from each series page, so that a developer who found the series finds the server.
Worked example. The example organization's developer page sits at
https://stats.example/developers/agents. It opens with the endpoint and
the first-question walkthrough, then lists the configurations for three
assistants and one agent framework, with the dates they were tested. The
manifest and the guidance are linked as files. The tiers table and the
registration form follow, then the changelog with its one entry for
version 1.0.0. The page ends with the support address, a stated response
time of two working days, and the sentence "Questions about a figure go
to the dissemination team at data@stats.example".
What this does not do. A developer page documents the interface. The documentation of the data, which is the definitions and the methods, stays in the catalog, and the metadata tool returns it.
Implementation options
- Configurations.
mcpServersblocks for desktop assistants, settings-page instructions for other assistants, and SDK snippets for frameworks. - Listing. The registry's server.json format and its publisher tool, plus the organization's catalog and developer page.
- Package. A PyPI or npm package for local use with stdio transport, beside the hosted endpoint.
- Support. An address or a tracker, with the response time stated.
World Bank examples
- The Data360 MCP server documents connection from several clients and publishes its endpoint and configuration.
- The program's MCP page describes the interfaces and how to connect to them.
Resources
- The MCP registry is the official registry of servers, with the publisher tool and the server.json format.
- The server.json reference documents the fields of a listing (name, version, repository, packages, remotes).
- The MCP clients page lists the client applications and the features each supports (tools, resources, prompts).
- The server listing and the listing check are the running example's listing and its check.
- The client configuration is the running example's configuration for a desktop assistant.
Common mistakes
- A server with no page. It works, and nobody uses it.
- One configuration. Users have different assistants. The page publishes the ones they use and says which were tested.
- A listing never updated. A stale version in the registry sends clients to tools that no longer exist.
- Support nobody reads. The page states the response time, and reports are routed to the evaluation and the monitoring.
Verification
- Page. A new user connects from the page alone and receives the expected first answer.
- Listing. The check passes, and the registry entry shows the current version.
- Configurations. Each has been tested with the current release, with the date recorded.
- Support. Every report received in the period has a recorded response.
Checklist
Ticks are saved in this browser only.