MCP Registry: GitHub, server.json y cómo listar tu servidor
El MCP Registry es donde los clientes y los marketplaces encuentran tu servidor, y darlo de alta requiere un solo server.json, un espacio de nombres verificado y un comando. Este artículo recorre el inicio de sesión con GitHub, la comprobación de propiedad de los paquetes, los servidores remotos y un flujo de lanzamiento con etiquetas.
Un buen servidor MCP que nadie encuentra es como si no existiera. El MCP Registry oficial soluciona eso con un archivo JSON, un nombre verificado y un solo comando, y GitHub aparece en tres puntos distintos del proceso: el inicio de sesión, el espacio de nombres y la automatización de los lanzamientos. Este artículo sigue los archivos y comandos exactos de la documentación del registro, para que tu servidor llegue al registro en el primer intento y no en el quinto.
💡 Respuesta rápida: escribe un server.json, demuestra que eres dueño del paquete al que apunta, ejecuta mcp-publisher login github y luego mcp-publisher publish. Todo lo que sigue explica por qué existe cada paso y qué se rompe si lo saltas.
Qué es realmente el MCP Registry
El MCP Registry es el repositorio centralizado y oficial de metadatos de los servidores MCP de acceso público, respaldado por Anthropic, GitHub, PulseMCP y Microsoft. Se abrió en vista previa en septiembre de 2025, la API lleva congelada en v0.1 desde finales de octubre de 2025 y la documentación sigue mostrando un aviso de vista previa, así que espera pequeños cambios. El servicio en vivo está en registry.modelcontextprotocol.io.
Metadatos, no código
El registro nunca almacena tu código. Guarda un registro que apunta a un paquete en npm, PyPI, NuGet, crates.io, un registro de contenedores o una versión publicada en GitHub. Piensa en un puerto de contenedores: el manifiesto dice qué hay en cada caja y de dónde viene, mientras que la carga está en otro lugar. Por eso importa el orden. Primero publicas el paquete y solo después la entrada del registro.
Dónde encaja GitHub
GitHub interviene en el proceso en tres puntos:
Identidad. Inicia sesión con GitHub y el nombre de tu servidor debe empezar por io.github.username/, o por el nombre de tu organización en lugar del nombre de usuario.
Metadatos.server.json incluye un objeto repository con "source": "github" y la URL del repositorio.
Automatización. GitHub Actions puede autenticarse en el registro mediante OIDC, sin ningún secreto almacenado.
Además, hay un escaparate aparte. GitHub tiene su propio MCP Registry en github.com/mcp, y GitHub anunció que los servidores que se publican por su cuenta en el registro de código abierto de la comunidad "aparecerán automáticamente" allí. Tómalo como un extra, no como una promesa: después de publicar, revisa tú mismo el listado de GitHub.
Quién puede dar de alta un servidor
Se aceptan servidores de código abierto y de código cerrado, con una condición: el servidor debe ser accesible públicamente. Eso significa un paquete público (un paquete de npm, una imagen de Docker en un registro público) o un endpoint remoto que no esté encerrado en una red privada. Los servidores en un host interno como mcp.acme-corp.internal, o detrás de un registro de paquetes privado, quedan fuera del alcance. Para esos casos, ejecuta tu propio registro privado.
También conviene saber que las aplicaciones anfitrionas no están pensadas para leer el registro oficial directamente. Los marketplaces y los agregadores lo consultan con regularidad, por ejemplo una vez por hora, y añaden su propia selección y sus valoraciones. Tu entrada viaja a través de ellos.
Elige primero tu espacio de nombres
El campo name de server.json es la identidad permanente de tu servidor, y tu método de inicio de sesión decide qué nombres puedes usar.
Método de inicio de sesión
Formato del nombre
Ejemplo
GitHub
io.github.username/* o io.github.orgname/*
io.github.alice/weather-server
Dominio (DNS o HTTP)
Forma invertida de tu dominio
com.example/acme-analytics
Nombres de GitHub para empezar rápido
Elige la ruta de GitHub si eres desarrollador independiente o un proyecto de código abierto. La CLI usa un flujo de dispositivo de OAuth, lo apruebas en el navegador y listo, en un par de minutos. Sin panel de DNS, sin archivos que alojar. La contrapartida está en el nombre: io.github.alice/weather-server queda bien para un proyecto personal, pero una marca de empresa suele querer su propio dominio.
Nombres de dominio con DNS o HTTP
Los nombres basados en dominios usan la forma invertida de un dominio que controlas, como com.example/acme-analytics. Demuestras el control de una de dos maneras:
DNS. Genera un par Ed25519 (o ECDSA P-384) con openssl, y luego publica la mitad pública como registro TXT con el formato example.com. IN TXT "v=MCPv1; k=ed25519; p=<base64>". Deja pasar varios minutos para la propagación.
HTTP. Aloja la misma línea v=MCPv1; ... como archivo en https://example.com/.well-known/mcp-registry-auth.
Después, inicia sesión con mcp-publisher login dns --domain example.com o mcp-publisher login http --domain example.com, añadiendo la mitad privada de tu par como se muestra en la documentación de autenticación. Los equipos que prefieran no guardar un archivo privado en un equipo portátil pueden firmar en su lugar con los servicios de firma en la nube de Google o Azure.
Escribe server.json paso a paso
Genera la plantilla base
Instala el publicador con Homebrew (brew install mcp-publisher) o descarga un binario desde las versiones de GitHub del registro. Luego, dentro de la carpeta de tu proyecto de servidor:
mcp-publisher --help
mcp-publisher init
El comando init escribe una plantilla de server.json y rellena lo que puede a partir de tu proyecto.
Un archivo mínimo que funciona
Esta es la estructura que usa la documentación para un servidor npm local:
Conserva la línea $schema que genera init, ya que la fecha del esquema cambia con el tiempo. Tres campos causan la mayoría de los problemas. El name debe coincidir con la prueba de propiedad dentro de tu paquete (más abajo se explica). El packages[].identifier debe apuntar a algo ya publicado. Y transport.type indica a los clientes cómo comunicarse con el servidor, donde stdio significa un proceso local.
¿Necesitas variables de entorno? Añádelas a la entrada del paquete con las marcas isRequired y isSecret, para que los clientes las pidan y oculten lo que escribas.
Reglas de versiones que dan problemas
Cada publicación necesita un version único, y una vez publicada, esa versión y sus metadatos no pueden cambiar. Se recomienda el control de versiones semántico, aunque se acepta cualquier cadena. Los rangos de versiones se rechazan a propósito.
Cadena de versión
Estado
1.0.0, 1.0.0-beta.1, 3.0.0-rc.2
Recomendada
2025-06-18, v1.0
Permitida
^1.2.3, ~1.2.3, >=1.2.3, 1.x
Prohibida
Dos hábitos te evitan problemas. Primero, alinea la versión del servidor con la versión del paquete, de modo que 1.2.3 en server.json coincida con 1.2.3 en npm. Segundo, si solo necesitas corregir los metadatos del registro sin tocar el paquete, publica una versión preliminar como 1.2.3-1. Ojo con la trampa: semver ordena una versión preliminar antes que su versión normal, así que publicar 1.2.3-1 después de 1.2.3 no se marcará como la más reciente.
Servidores remotos con remotes
Los servidores alojados usan un array remotes en lugar de packages, o junto a él:
Un remoto debe ser accesible públicamente en su URL. Prefiere Streamable HTTP; el transporte SSE está obsoleto, así que añade un remoto "sse" solo para clientes existentes. Las configuraciones multiinquilino pueden usar variables de URL como https://{tenant_id}.analytics.example.com/mcp, cada una descrita con isRequired, default o choices. Y si distribuyes tanto un paquete como un remoto, lista ambos: la aplicación anfitriona elige el método de instalación que prefiera.
Demuestra que eres dueño del paquete
El registro comprueba que el paquete realmente pertenece al nombre que reclamas. Si lo saltas, la publicación falla con "Registry validation failed for package". Cada tipo de paquete tiene su propia prueba.
Una comprobación por tipo de paquete
Tipo de paquete
registryType
Prueba de propiedad
npm
npm
mcpName en package.json igual al nombre del servidor
PyPI
pypi
mcp-name: <server name> en el README, se permite comentario oculto
NuGet
nuget
mcp-name: <server name> en el README, se permite comentario oculto
Cargo (crates.io)
cargo
mcp-name: <server name> como texto visible del README
Hay algunos detalles que dan problemas. La comprobación de npm usa solo el registro público de npm, y PyPI y NuGet están igualmente limitados a sus registros oficiales. crates.io elimina los comentarios HTML, así que el token de Cargo tiene que ser texto visible, no un comentario oculto. En las imágenes de contenedor, identifier sigue a registry/namespace/repository:tag, y los hosts compatibles son Docker Hub, GitHub Container Registry (ghcr.io), Google Artifact Registry, Azure Container Registry y Microsoft Container Registry. Para los archivos MCPB alojados en versiones de GitHub o GitLab, calcula el hash con openssl dgst -sha256 your-file.mcpb. El registro no verifica ese hash, pero los clientes sí lo hacen antes de instalar.
💡 Consejo: el nombre del servidor en server.json y la prueba dentro del paquete deben coincidir carácter por carácter. Basta una letra mayúscula de más para que la validación falle.
Publica desde tu terminal
Inicia sesión con GitHub
Ejecuta el inicio de sesión desde la carpeta de tu proyecto:
mcp-publisher login github
La CLI muestra un código de un solo uso y una URL:
To authenticate, please:
1. Go to: https://github.com/login/device
2. Enter code: ABCD-1234
3. Authorize this application
Waiting for authorization...
Abre el enlace, pega el código, aprueba y la terminal confirma el inicio de sesión. Si más adelante ves "Invalid or expired Registry JWT token", la sesión caducó. Vuelve a iniciar sesión.
Publica y verifica
Con el paquete ya publicado en npm y server.json guardado, publica:
mcp-publisher publish
Una ejecución correcta muestra la URL del registro y el nombre de tu servidor con su versión. Confírmalo a través de la API pública:
Los metadatos de tu servidor deberían aparecer en el JSON que devuelve. Los marketplaces que consultan el registro actualizan según su propio calendario, así que dales un tiempo antes de esperar ver el listado allí, y búscalo también en github.com/mcp.
Las actualizaciones siguen el mismo camino. Sube la versión del paquete, publícalo en npm, actualiza server.json para que coincida y vuelve a ejecutar mcp-publisher publish. Cada publicación es una versión inmutable propia, y el registro marca la versión semántica más reciente como la última, así que los clientes que piden la versión actual reciben la correcta.
Lanza versiones con GitHub Actions
Un flujo de trabajo de lanzamiento con etiquetas
Una vez que la ejecución manual funciona, pásala a CI para que cada etiqueta de versión publique el paquete y la entrada del registro a la vez. Este flujo de trabajo usa OIDC de GitHub, el método que recomienda la documentación:
name: Publish to MCP Registry
on:
push:
tags: ["v*"]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: "lts/*"
- name: Install dependencies
run: npm ci
- name: Build package
run: npm run build --if-present
- name: Publish package to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Install mcp-publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
- name: Authenticate to MCP Registry
run: ./mcp-publisher login github-oidc
- name: Publish server to MCP Registry
run: ./mcp-publisher publish
Lanzas con dos comandos: git tag v1.0.0 y git push origin v1.0.0. Un detalle que la plantilla deja opcional es el incremento de versión. Si server.json tiene una versión fija en el código, el registro rechazará una publicación repetida, así que defínela a partir de la etiqueta antes del paso de publicación. En un servidor de un solo paquete, esta línea jq actualiza ambos campos de versión:
OIDC de GitHub: no necesitas ningún secreto del registro. Solo necesitas el permiso id-token: write.
Token de acceso personal de GitHub: guárdalo como secreto y ejecuta mcp-publisher login github --token, con los ámbitos read:org y read:user.
Inicio de sesión con DNS: guarda la mitad privada de tu par Ed25519 como secreto y pásala a mcp-publisher login dns.
Registro de paquetes: el flujo de trabajo anterior también necesita un secreto NPM_TOKEN para npm publish.
Corrige los errores antes de que los vean los usuarios
La mayoría de las publicaciones fallidas se reducen a cinco mensajes:
Mensaje de error
Solución probable
"Registry validation failed for package"
El paquete no tiene su prueba de propiedad, como mcpName en package.json.
"Invalid or expired Registry JWT token"
Vuelve a iniciar sesión con mcp-publisher login github.
"You do not have permission to publish this server"
Tu método de inicio de sesión no coincide con el prefijo del nombre. El inicio de sesión con GitHub necesita io.github.your-username/.
"Authentication failed"
En Actions, confirma que id-token: write está definido, o revisa tus secretos.
"Package validation failed"
El paquete aún no está en su registro, o le falta la prueba de propiedad.
Antes de cada lanzamiento, repasa esta lista corta:
El name en server.json coincide con mcpName (o con el token del README, o con la etiqueta de la imagen).
La versión del paquete en server.json ya existe en npm, PyPI o en tu host de contenedores.
El version del servidor nunca se ha publicado antes y no es un rango.
Cualquier URL remota responde desde internet público, no solo desde la red de tu oficina.
El servidor está pensado para el público. Los servidores privados pertenecen a un registro privado.
Redacta e ilustra con PicassoIA
Un modelo de lenguaje (LLM) es una máquina rápida para hacer borradores iniciales de server.json, siempre que sea el registro el que juzgue el resultado. PicassoIA aloja modelos de lenguaje que puedes usar directamente desde el navegador, entre ellos Claude Sonnet 5, GPT 5.6 Sol y Gemini 3.5 Flash.
Abre la página de Claude Sonnet 5 en PicassoIA y empieza un chat nuevo.
Pega los campos de tu package.json (nombre, versión, descripción, repositorio) más la línea $schema que generó mcp-publisher init.
Pide solo JSON, indica al modelo que deje $schema sin cambios y prohíbe los campos inventados.
Copia el resultado en server.json y comprueba a simple vista que name coincide con tu mcpName.
Ejecuta mcp-publisher publish. Si la validación falla, pega el error exacto de vuelta en el chat.
Los prompts cortos con código fuente pegado funcionan mejor que los prompts largos con descripciones, porque los modelos inventan campos verosímiles cuando no ven el archivo real. ¿Quieres también la plantilla del flujo de trabajo de Actions? GPT 5.6 Sol es una buena segunda opinión para eso.
PicassoIA también ofrece una API para desarrolladores, y sirve de ejemplo práctico para entender para qué sirven environmentVariables. La API está en https://api.picassoia.com/v1 y funciona como otras APIs de predicción: creas una predicción, consultas su estado y luego obtienes el resultado, con un máximo de 5 predicciones simultáneas por cuenta (a principios de octubre de 2026). Un servidor envoltorio hipotético pediría a cada usuario su propia credencial una sola vez, mediante una entrada como esta dentro de su paquete:
Una entrada del registro es solo texto, pero el README, la imagen para redes sociales y la publicación de lanzamiento necesitan imágenes. Abre PicassoIA, elige un modelo de imagen o de video y genera una imagen principal o un clip corto de demostración para tu servidor. El catálogo completo de modelos está en picassoia.com/en/all-models. Prueba tres prompts, quédate con el mejor y publícalo junto con tu primer mcp-publisher publish.