Guide · MCP Registry Distribution
MCP server registry requirements
The four major MCP server registries — Smithery, Glama, PulseMCP, and MCP.so — each have their own submission processes and metadata formats, but they share a common set of technical requirements. A server that satisfies the universal requirements will pass all four registries' verification steps and maintain its listings over time. A server that meets only some requirements will fail at one or more registries and lose listings when re-scan cycles catch a regression. This guide consolidates the universal checklist and explains the reasoning behind each requirement.
TL;DR
Before submitting to any MCP registry: (1) verify your server responds to a real MCP initialize request with a valid protocolVersion, (2) confirm tools/list returns at least one tool with a name, description, and input schema, (3) check that your TLS certificate is valid and issued by a public CA, (4) write tool descriptions from the user's perspective (not the implementation's). Then set up AliveMCP monitoring before submitting so you know immediately if a post-launch regression would fail a registry's re-scan.
The universal registry checklist
| Requirement | Smithery | Glama | PulseMCP | MCP.so | Why it matters |
|---|---|---|---|---|---|
| HTTPS with public CA certificate | Required | Required | Required for remote | Required for remote | All registry crawlers reject self-signed certs; agent frameworks refuse to connect without valid TLS |
initialize handshake succeeds | Required | Required | For remote | For remote | The minimum bar for "MCP-compliant" — HTTP 200 alone is not enough |
tools/list returns non-empty array | Required | Required | Preferred | Preferred | A server with no tools provides no value; registries deprioritize empty tool lists |
Each tool has name, description, inputSchema | Required | Required | Preferred | Preferred | Missing descriptions make tools unsearchable in directory; missing schemas break callers |
| README with tool table and install command | Preferred | Preferred | Required | Required | PulseMCP and MCP.so primarily surface README content; no README = incomplete listing |
GitHub topics include mcp-server | Helpful | Helpful | Required | Required | PulseMCP and MCP.so use GitHub topics as primary discovery mechanism |
smithery.yaml manifest | Required | Not required | Not required | Not required | Smithery-specific; enables install-from-browser UI and config form generation |
| Server responds in <5 seconds | Required | Required | For remote | For remote | Crawler timeouts at 5–30s; slow servers may be marked unavailable even if they eventually respond |
Protocol compliance verification script
Run this script against your server before submitting to any registry. It replicates the verification sequence every major registry's crawler performs:
#!/bin/bash
# verify-mcp-registry-ready.sh — run before submitting to any MCP registry
SERVER_URL="${1:-https://your-server.example.com/mcp}"
echo "=== MCP Registry Readiness Check ==="
echo "Target: $SERVER_URL"
echo ""
# 1. TLS verification
echo "[1/4] TLS certificate check..."
CERT_CHECK=$(echo | openssl s_client -connect "$(echo $SERVER_URL | sed 's|https://||' | cut -d/ -f1):443" 2>&1 | grep "Verify return code")
if echo "$CERT_CHECK" | grep -q "0 (ok)"; then
echo " ✓ TLS certificate valid"
else
echo " ✗ TLS issue: $CERT_CHECK"
exit 1
fi
# 2. HTTP reachability
echo "[2/4] HTTP reachability check..."
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST "$SERVER_URL" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":0,"method":"ping","params":{}}')
if [ "$HTTP_STATUS" != "000" ]; then
echo " ✓ Server reachable (HTTP $HTTP_STATUS)"
else
echo " ✗ Server unreachable"
exit 1
fi
# 3. MCP initialize handshake
echo "[3/4] MCP initialize handshake..."
INIT_RESPONSE=$(curl -s -X POST "$SERVER_URL" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"registry-verifier","version":"1.0"}}
}')
if echo "$INIT_RESPONSE" | grep -q '"protocolVersion"'; then
PROTOCOL_VERSION=$(echo "$INIT_RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['result']['protocolVersion'])" 2>/dev/null)
echo " ✓ initialize succeeded (protocolVersion: $PROTOCOL_VERSION)"
else
echo " ✗ initialize failed. Response:"
echo " $INIT_RESPONSE"
exit 1
fi
# 4. tools/list check
echo "[4/4] Tool list verification..."
TOOLS_RESPONSE=$(curl -s -X POST "$SERVER_URL" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}')
TOOL_COUNT=$(echo "$TOOLS_RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d['result']['tools']))" 2>/dev/null)
if [ -n "$TOOL_COUNT" ] && [ "$TOOL_COUNT" -gt 0 ]; then
echo " ✓ tools/list returned $TOOL_COUNT tool(s)"
echo ""
echo "=== Registry Readiness: PASS ==="
echo "Your server passes the universal MCP registry requirements."
else
echo " ✗ tools/list failed or returned empty tools array"
echo " Response: $TOOLS_RESPONSE"
exit 1
fi
Save this script as scripts/verify-registry-ready.sh in your repository and run it as part of your pre-release checklist. A server that passes all four checks is ready to submit to any MCP registry. The script exits 0 on success and 1 on failure — add it to CI to catch regressions before they affect your live registry listings.
Common registry rejection reasons
The most frequent reasons MCP servers fail registry verification or lose their listings after approval:
| Failure | Root cause | Fix |
|---|---|---|
| HTTP 200 but initialize fails | Reverse proxy returns "OK" for unrecognized paths without forwarding to MCP server | Check proxy routing config; verify POST to /mcp reaches the MCP process |
| Self-signed TLS rejected | Using a development certificate in production | Use Let's Encrypt via Caddy or Certbot; automatic renewal prevents expiry failures |
| Expired TLS certificate | Auto-renewal disabled or failed silently | Enable auto-renewal; add certificate expiry monitoring |
| Empty tools array | Tool registration happens in an async init that hasn't completed at list time | Wait for async initialization before accepting requests; use a ready probe |
| Missing tool descriptions | Descriptions not set in server.tool() calls | Add descriptions to every tool — required by spec and all registries |
| Crawler timeout | Cold start on serverless platform exceeds 5s | Use keep-alive pings or minimum-instances=1 to prevent cold starts |
| Server healthy at submission, fails at re-scan | Deployment broke MCP protocol layer after listing was created | Add post-deploy verification; use AliveMCP to catch regressions between re-scans |
Why uptime monitoring is essential for registry health
There is a fundamental gap in the registry lifecycle: registries verify your server at submission time and then re-check on a schedule. Between those checks, your server could be down for hours without your listing showing any indication of a problem. The consequences compound:
- Registry re-scan catches the failure — your verified badge is removed and your listing is deprioritized.
- Users try to connect during the outage — they fail, attribute the failure to your server quality, and move on to an alternative. They may never return.
- Search engines index the down state — if a registry page loads slowly or errors because your server appears unhealthy, it signals poor quality.
The economics of registry discoverability make uptime critically important. You may invest significant effort getting your server listed across four registries. That distribution work is continuously at risk if your server has reliability issues that you discover only after a registry flags them.
AliveMCP probes your endpoint every 60 seconds — the same initialize + tools/list sequence that registries run, but continuously. When a failure happens at 3am after a bad deployment, you know within 3 minutes (3 consecutive probe failures), not the next time you log in or the next time a registry crawls. This is the gap between registry monitoring and real-time protocol monitoring.
// Example: post-deploy health check that mirrors what registries verify
// Run this in your deployment pipeline after every push
async function verifyRegistryReadiness(serverUrl: string): Promise<void> {
const client = new McpClient();
const transport = new StreamableHTTPClientTransport(new URL(serverUrl));
try {
await client.connect(transport);
// If connect() succeeds, initialize handshake completed
const tools = await client.listTools();
if (tools.tools.length === 0) {
throw new Error('Server returned empty tools list — registry verification will fail');
}
const missingDescriptions = tools.tools.filter(t => !t.description?.trim());
if (missingDescriptions.length > 0) {
console.warn(`Warning: ${missingDescriptions.length} tools missing descriptions: ${missingDescriptions.map(t => t.name).join(', ')}`);
}
console.log(`✓ Registry readiness verified: ${tools.tools.length} tools registered`);
} finally {
await client.close();
}
}
// In your CI/CD pipeline:
await verifyRegistryReadiness(process.env.MCP_SERVER_URL!);
Related questions
Do I need to meet all requirements for every registry simultaneously?
The GitHub topic and README requirements are relevant for PulseMCP and MCP.so but not for Smithery's direct submission flow. The smithery.yaml is required for Smithery but ignored by all other registries. However, the core protocol requirements (TLS, initialize handshake, non-empty tools list with descriptions) are universal — meeting them is necessary for all four registries, not just one. It is most efficient to meet all requirements before any submission, then submit to all registries in one pass.
My server uses SSE transport instead of streamable HTTP — does that affect registry compatibility?
Most MCP registries and their crawlers support both SSE transport (the older standard) and streamable HTTP transport (the newer standard introduced in MCP protocol version 2025-03-26). If you use SSE transport, ensure your crawler-visible endpoint URL accepts SSE connections with the correct Content-Type: text/event-stream response header. Some newer registry crawlers may prefer or default to streamable HTTP — if your listing shows as unverified despite your endpoint being reachable, check whether the crawler is sending streamable HTTP requests to an SSE-only endpoint.
How often do registries re-scan listed servers?
Re-scan frequency varies by registry and is not always publicly documented: Smithery re-crawls on a roughly weekly cadence with more frequent checks for servers with a history of instability. Glama re-verifies on a similar weekly schedule. PulseMCP's GitHub topic crawl runs weekly. MCP.so's re-verification cadence for remote servers is less documented but observed to be bi-weekly to monthly. The implication: a server can be down for a week before a registry flags it. This is why continuous external monitoring is not optional for maintaining registry listings — it fills the gap that registry re-scans leave.
What should my server's initialize response include for registries?
The initialize response serverInfo object should include a human-readable name (not an internal identifier like "mcp-service-v2-prod") and a version string following semver (e.g., "1.2.0"). Registries may display serverInfo.name as a fallback if the submission name is not set. The capabilities object should accurately reflect what your server supports — if you claim resources: {} capability but your server doesn't actually implement resources/list, some registry crawlers will flag the mismatch.
Further reading
- MCP server Smithery listing — smithery.yaml manifest and submission guide
- MCP server Glama listing — scanner verification requirements
- MCP server PulseMCP — GitHub topic discovery and README requirements
- MCP server MCP.so — community directory submission
- MCP server health check — complete protocol health verification guide
- MCP server SSL certificate — certificate management for production
- MCP server uptime badge — embed live status in README for social proof
- AliveMCP — continuous MCP protocol monitoring, the same checks registries run but every 60 seconds