Skip to main content
Glama

mcp-worker-starter

Un servidor Model Context Protocol mínimo para Cloudflare Workers. Cero dependencias, un archivo, POST simple.

Tengo un servidor MCP en producción que expone datos comerciales en vivo a Claude mediante herramientas autenticadas. Este es ese servidor con la lógica de negocio extraída y el tejido cicatricial dejado dentro.

El camino feliz de un servidor MCP es de unas cuarenta líneas. Las partes que merece la pena publicar son las tres trampas siguientes, porque cada una es silenciosa, y una de ellas tumbó dos de mis productos.


El 405 que te cuesta una caída

Los clientes MCP abren un GET con Accept: text/event-stream para escuchar mensajes enviados por el servidor. Si tu servidor no habla SSE, el protocolo dice que respondas 405. Ese estado es la señal de no vuelvas a abrir esto.

En su lugar respondí 200 con un cuerpo JSON amigable, porque un 200 parecía más útil que un error.

El cliente interpretó ese 200 como una transmisión que había muerto y se reconectó. Inmediatamente. Sin backoff y sin que apareciera ningún error en ningún lugar donde estuviera mirando.

201 936 solicitudes en un día. Quemó la cuota diaria de solicitudes de toda la cuenta de Cloudflare, lo que tumbó un segundo producto, completamente no relacionado, que compartía esa cuenta. El propio servidor MCP nunca registró un solo error, porque desde su lado no había nada malo. Estaba respondiendo a cada solicitud correctamente, 201 936 veces.

Un 200 donde el protocolo espera un 405 no es una respuesta más amable. Es un bucle infinito con buenos modales.

if ((request.headers.get("accept") ?? "").includes("text/event-stream")) {
  return new Response(JSON.stringify({ error: "This server does not expose an SSE stream. Use POST." }), {
    status: 405,
    headers: { "content-type": "application/json; charset=utf-8", allow: "POST" },
  });
}

Related MCP server: Remote MCP Server (Authless)

Las notificaciones no tienen id y no deben recibir cuerpo

Una notificación JSON-RPC es de lanzar y olvidar. Llega sin un id y el emisor no espera una respuesta. Responder con {"jsonrpc":"2.0","result":{}} y los clientes estrictos tratan el intercambio como malformado, porque respondiste algo que nadie preguntó.

202 con un cuerpo vacío es la forma correcta de decir «recibido, no hay nada que decir».

if (id === undefined || id === null) return new Response(null, { status: 202 });

Haz eco del protocolVersion del cliente

En initialize, devuelve el protocolVersion que ofreció el cliente en lugar de fijar el tuyo por código. Fijarlo por código te da un handshake que funciona hoy y deja de funcionar silenciosamente la semana en que el cliente se actualiza. Recurre a un valor predeterminado solo cuando el cliente no indique ninguno.


Úsalo

npm install
npx wrangler dev
curl -s http://localhost:8787 \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq

Despliega:

npx wrangler deploy

Después añade la URL desplegada como servidor MCP en tu cliente. Habla mediante POST.

Añade tus propias herramientas

Edita el array TOOLS en src/index.ts. Dos reglas que importan más de lo que parecen:

  • description es el prompt. El modelo elige herramientas al leerlo. Escríbelo para un lector que no puede ver tu código y no leerá el esquema dos veces.

  • Devuelve datos, no prosa. El modelo es mejor describiendo tu JSON que tú adivinando lo que quiere decir sobre él.

Autenticación y límite de peticiones

Ambos están desactivados por defecto para que el starter funcione sin configuración.

La autenticación por token se activa cuando defines MCP_TOKEN. Las solicitudes deben presentar entonces Authorization: Bearer <token>.

npx wrangler secret put MCP_TOKEN

El límite de peticiones por hora se activa cuando vinculas un espacio de nombres KV como RATE_LIMIT. El límite predeterminado es de 300 solicitudes por hora. En producción limito por tenant en lugar de globalmente, con clave basada en lo que identifique al llamante.

[[kv_namespaces]]
binding = "RATE_LIMIT"
id = "your-kv-namespace-id"

Un límite de peticiones no es paranoia aquí. La trampa uno es exactamente la forma de fallo que un tope habría detectado en minutos en lugar de en un día.

Lo que esto no es

No es un SDK, ni un framework, ni pretende serlo. Si quieres pilas incluidas, usa el TypeScript SDK oficial o el Agents SDK de Cloudflare.

Esto es para el caso en el que quieres leer todo el servidor de una sentada y saber exactamente lo que hace.

Pruebas

npm test

Cubre el handshake, el viaje de ida y vuelta de las herramientas y cada una de las tres trampas, porque una regresión en cualquiera de ellas es invisible hasta que resulta cara.

Licencia

MIT

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    Allows deploying a Model Context Protocol server on Cloudflare Workers without authentication, enabling AI assistants to access custom tools through the MCP standard.

View all related MCP servers

Related MCP Connectors

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.

  • A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/andressalame/mcp-worker-starter'

If you have feedback or need assistance with the MCP directory API, please join our Discord server