← Alle Playbooks
Playbook· build

Publicar un servidor MCP paso a paso

Has construido un servidor MCP. Ahora alguien más tiene que poder instalarlo sin preguntarte. Aquí están los diez pasos de 'funciona en mi laptop' a 'npx -y tu-servidor'.

Construir un MCP server es una cosa. Distribuirlo de forma que otra persona lo instale en 30 segundos es otra. La mayoría de repos se queda en fase "build" porque la distribución parece pesada. No lo es, una vez que has hecho el camino una vez.

Asumimos que ya tienes un MCP server stdio local funcionando (ruta: /path/to/tu-server con package.json + src/index.ts). Ahora quieres publicarlo en npm más GitHub. Al final cualquiera puede engancharlo con npx -y tu-server.

1. Decisión de naming

El nombre del paquete npm debe ser único y el patrón es siempre mcp-{tema} (con guión, minúsculas). Ejemplos existentes: mcp-academy, mcp-personal-suite, mcp-stateless-migrator, mcp-spec-migrator.

Busca en npm si tu nombre está libre:

npm view mcp-tu-nombre

Si devuelve 404 not found, el nombre está libre. Si muestra un número de versión, busca otro.

Un consejo: no uses un acrónimo que solo entiendas tú. mcp-cli-buddy es mejor que mcp-cb.

2. Limpiar package.json

Estos son los campos obligatorios para un paquete MCP publicado:

{
  "name": "mcp-tu-nombre",
  "version": "0.1.0",
  "description": "Una frase de qué hace el server.",
  "license": "MIT",
  "author": "Tu Nombre <email>",
  "homepage": "https://github.com/tuusuario/mcp-tu-nombre#readme",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/tuusuario/mcp-tu-nombre.git"
  },
  "bugs": "https://github.com/tuusuario/mcp-tu-nombre/issues",
  "keywords": ["mcp", "model-context-protocol", "claude", "tu-tema"],
  "type": "module",
  "main": "dist/index.js",
  "bin": {
    "mcp-tu-nombre": "dist/index.js"
  },
  "files": [
    "dist/**/*",
    "README.md",
    "LICENSE"
  ],
  "engines": {
    "node": ">=20"
  },
  "scripts": {
    "build": "tsc -p tsconfig.json",
    "prepublishOnly": "npm run build"
  }
}

El campo bin es el más importante. Con eso npx -y mcp-tu-nombre funciona sin install. El hook prepublishOnly asegura que dist/ se reconstruya antes de cada npm publish.

3. Poner shebang en src/index.ts

Para que npx pueda ejecutar tu script directamente, la primera línea de src/index.ts debe ser:

#!/usr/bin/env node

Solo eso. Sin línea en blanco delante, sin comentario. El shebang debe estar exactamente al inicio o el ejecutable no funciona.

4. tsconfig orientado al build

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "outDir": "dist",
    "rootDir": "src",
    "declaration": true,
    "sourceMap": true,
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "tests"]
}

declaration: true construye también los .d.ts. Importante si alguien usa tu paquete como librería. Menos crítico en MCP servers puros, no estorba.

5. Escribir el README (tres secciones)

Un buen README MCP tiene exactamente tres secciones obligatorias:

# mcp-tu-nombre

Una frase de qué hace.

## Install

\`\`\`json
{
  "mcpServers": {
    "tu-nombre": {
      "command": "npx",
      "args": ["-y", "mcp-tu-nombre"]
    }
  }
}
\`\`\`

Añade a la config de Claude Desktop o Claude Code, reinicia.

## Tools

- `tool_one(param)`: qué hace
- `tool_two(param)`: qué hace

## Prompts de ejemplo

> "Pregunta a mcp-tu-nombre por X"
> "Usa tool_one con parámetro Y"

Es todo lo necesario para el primer install. Se puede añadir más, no se puede quitar nada. Si alguien lee tu README y no está instalado en dos minutos, el README es demasiado largo.

6. Test local con npm pack

ANTES de publicar, simula el install localmente:

npm run build
npm pack
# Crea mcp-tu-nombre-0.1.0.tgz
cd /tmp
npm install /path/a/mcp-tu-nombre-0.1.0.tgz
ls node_modules/mcp-tu-nombre/dist/

Comprueba que dist/index.js está y el shebang está arriba. Si falta, tienes un problema de build que arreglas ahora, no tras el publish.

Un consejo: npm pack muestra la lista de ficheros que entran en el paquete. Si están tests/ o .env, definiste files: demasiado amplio. Corrige.

7. Cuenta npm + login

Si no tienes cuenta npm: npmjs.com/signup. Luego en local:

npm login
npm whoami

Si tienes 2FA activado (deberías): npm pide OTP al login Y al publish. Obligatorio para paquetes serios.

8. Primer publish

npm publish --access=public

El --access=public es obligatorio si tu nombre de paquete no está scoped (@org/paquete). Por defecto es privado, lo que no funciona en cuentas free y lanza un error críptico.

Verificación:

npm view mcp-tu-nombre
# Ahora muestra 0.1.0

Más: añadir a la config de Claude Desktop y reiniciar. claude mcp list tiene que mostrar tu server.

9. Repo en GitHub + tag

Push del source a GitHub:

git init
git add .
git commit -m "Initial commit: mcp-tu-nombre v0.1.0"
gh repo create tuusuario/mcp-tu-nombre --public --source=. --push
git tag v0.1.0
git push --tags

Crea un release en GitHub (gh release create v0.1.0 --notes "Initial release"). Eso da a tu paquete descubrimiento vía GitHub search y hace la version history rastreable.

Opcional pero recomendado: GitHub Actions para publish-on-tag automático con npm provenance. Patrón en los repos studiomeyer-io.

10. Distribución más allá de npm

npm es obligatorio, no es lo único. Tres plataformas más donde se encuentran MCP servers:

  • awesome-mcp-servers en GitHub: abres un PR, listas tu repo bajo la categoría correspondiente.
  • MCPize Marketplace (mcpize.com): crear listing, da descubrimiento para usuarios cloud.
  • Glama (glama.ai/mcp/servers): agregador, entrada gratis.

Estos tres gratis, una sola vez 30 minutos de trabajo, traen los primeros usuarios. Postear en Reddit r/ClaudeAI o r/mcp también funciona si tu server resuelve un pain específico.

Lo que no debes hacer: postear en grupos de principiantes "Hey he construido un MCP server, mira". Es spam y no llega. Postear solo funciona si tienes una historia de caso de uso concreta.

OAuth refresh patterns para servidores HTTP

Si tu server es HTTP en vez de stdio y usa OAuth, no hay forma de evitar el refresh de token. Los access tokens duran poco (típicamente 1 hora), y si tu usuario te golpea una vez por semana, el token expira entre sesiones.

En la práctica: en el primer OAuth flow tu server recibe access_token más refresh_token. Guardas ambos. Cuando llega la siguiente tool request y el access token ha expirado, haces un refresh call al OAuth provider (grant_type=refresh_token), recibes un nuevo access token (idealmente también un nuevo refresh token, best practice contra token replay), guardas ambos, y reintentas la tool request transparentemente.

Lo que vino como bug fixes en Claude Code v2.1.118 y debes saber como autor de MCP server:

  • Detección de expiry de token. Tu server debe realmente refrescar en un 401 o 403, no fallar silenciosamente. Claude Code ahora detecta de forma fiable cuándo un MCP server devuelve "401 token expired" y dispara el refresh del lado cliente.
  • Keychain race conditions. Cuando tu server recibe llamadas en paralelo (dos tool calls a la vez), no puede pasar que ambas disparen el refresh y se sobrescriban tokens. Mutex o updates atómicos de token son obligatorios.
  • Rotación de refresh token. Algunos OAuth providers (Google, GitHub) entregan un nuevo refresh token en cada refresh. Si sigues usando el viejo, tras unos refreshes tendrás un token inválido. Siempre guarda el nuevo.

Pseudo-código para tu tool handler:

async function callApi(userId: string, endpoint: string) {
  let token = await getToken(userId);
  let res = await fetch(endpoint, { headers: { Authorization: `Bearer ${token}` } });

  if (res.status === 401) {
    token = await refreshToken(userId);  // con mutex para no doble-refresh
    res = await fetch(endpoint, { headers: { Authorization: `Bearer ${token}` } });
  }

  return res;
}

Para la lógica del mutex en multi-tenant: por tenant un in-memory lock map (Promise-based en Node.js) o Redis lock si escalas horizontalmente. Para single-tenant un simple let refreshing: Promise<string> | null basta.

Lo que no debes hacer: guardar refresh tokens en frontend o localStorage del navegador. Los refresh tokens van server-side, siempre. En frontend solo queda el access token de vida corta.

Siguientes pasos

Después del primer publish viene el siguiente muro: mantenimiento de versiones. Patch releases (0.1.1) cuando arreglas bugs, minor (0.2.0) en tools nuevas, major (1.0.0) en cambios de API. Cíñete a SemVer, si no frustras a usuarios que tienen tu server en setup de producción.

Publicar un servidor MCP paso a paso — StudioMeyer Academy