Tizón MCP Server
by Valdivia94x
README.md
# Tizón · Servidor MCP
Un servidor [Model Context Protocol](https://modelcontextprotocol.io) para operar
un restaurante, con un playground que enseña el JSON-RPC en vivo.
**Tizón es ficticio.** Es la tercera pieza del mismo restaurante inventado, junto
con [su sitio](https://github.com/Valdivia94x/tizon) y
[la app de pedidos](https://github.com/Valdivia94x/tizon-pedidos).
```bash
pnpm install
pnpm dev
```
## Instalarlo en un cliente MCP
En Claude Code:
```bash
claude mcp add tizon -- npx tsx bin/tizon-mcp.ts
```
Cualquier host MCP sirve — Claude Code, Cursor, VS Code, el tuyo. El servidor
también habla HTTP en `/api/mcp`, así que se puede consumir remoto.
La superficie es idéntica por los dos transportes: `crearServidor()` no sabe por
dónde lo están hablando. El transporte es detalle de despliegue, no de diseño.
## Las cinco herramientas
| Herramienta | Qué hace |
|---|---|
| `consultar_carta` | Platillos con precio, estación de cocina y si están agotados |
| `pedidos_activos` | Comandas en cocina, con minutos de espera y cuáles van retrasadas |
| `resumen_del_turno` | Entregadas, retrasadas, espera promedio, qué se cancela más |
| `marcar_disponibilidad` | Agotar un platillo o reponerlo |
| `avanzar_pedido` | Mover una comanda al siguiente estado |
## Las decisiones, que es de lo que va el proyecto
Que algo sea un servidor MCP no dice nada. Lo que dice algo es cómo está
diseñada la superficie.
**Cinco herramientas, no veinte.** Cada una responde a una pregunta o hace una
acción que alguien en el restaurante haría. Más herramientas no es más
capacidad: es más superficie donde el modelo puede elegir mal.
**No hay escotilla genérica.** No existe `ejecutar_consulta` ni nada que acepte
SQL o un filtro arbitrario. Es la omisión más importante del servidor: una
escotilla lo convierte en una API cruda, hace imposible razonar sobre qué puede
pasar, y traslada al modelo decisiones que le tocan al servidor. Hay una prueba
que verifica que no exista.
**Las descripciones dicen cuándo llamar**, no solo qué hace la herramienta. Es
lo que más mueve la aguja para que el modelo acierte a elegirla, y hay una
prueba que falla si alguna se queda demasiado corta.
**La salida es texto para leer, no un volcado de JSON.** El consumidor es un
modelo: un texto compacto y etiquetado cuesta menos tokens y se interpreta mejor
que un objeto anidado.
**Los errores enseñan.** Un folio inexistente devuelve los folios que sí
existen; un identificador de platillo inválido devuelve los válidos. Un error
que solo dice «no encontrado» obliga al modelo a adivinar otra vez; uno que dice
qué sí hay le permite corregirse en el mismo turno.
**Fallar claro antes que fingir éxito.** Avanzar una comanda ya entregada es un
error, no un no-op silencioso. Si el modelo cree que avanzó algo, seguirá
razonando sobre algo falso.
**Dos superficies sobre un mismo estado.** Las herramientas MCP devuelven texto
porque su consumidor es un modelo; `/api/tablero` devuelve JSON porque su
consumidor es una interfaz. Hacer que la interfaz parsee el texto pensado para
el modelo sería atarlas por el lado equivocado.
## El playground
`/` es un cliente MCP, no un chat. Pide `tools/list` al servidor, deja llamar
cada herramienta con argumentos reales y **enseña el JSON-RPC que va y viene**.
Al lado, el tablero que esas llamadas modifican.
No hay un modelo de por medio, a propósito. Un playground que enseña el
protocolo demuestra más sobre MCP que un chat donde un modelo hace de
intermediario y tapa el mecanismo. Para ver el agente de verdad está la
instalación por `stdio`, arriba.
El estado vive en memoria del servidor y se resiembra en cada arranque en frío,
así que nadie le arruina la demo a nadie.
## Pruebas
```bash
pnpm prueba:mcp
```
Diecisiete comprobaciones que **hablan el protocolo de verdad** — levantan el
servidor por `stdio` y le mandan JSON-RPC, sin mockear el SDK y sin llamar a
ningún modelo. Cubren descubrimiento, lectura, acción, idempotencia y los
errores que enseñan. Dos de ellas verifican decisiones de diseño y no
implementación: que las descripciones expliquen cuándo usar cada herramienta, y
que no haya aparecido una escotilla genérica.
## Notas de implementación
Contra la especificación **2026-07-28**, que pasó a ser **sin estado**: no hay
handshake de `initialize` ni sesión a nivel de protocolo. Por eso se construye
un servidor por petición y esto escala detrás de un balanceador normal, sin
sesiones pegajosas. SDK de TypeScript v2.
Tres cosas que solo salieron probando, por si le ahorran a alguien la tarde:
- `createMcpHandler` devuelve un **objeto** `{ fetch, notify, bus, close }`, no
una función. Exportarlo directo como route handler compila y revienta en
runtime.
- Su `.fetch` tampoco encaja como route handler de Next: recibe
`(request, options?)` y Next pasa `(request, context)`. Hay que envolverlo.
- En `ImageResponse`, satori exige `display` explícito en cualquier `div` con
más de un hijo — y `texto + <br/> + texto` son tres. El build falla.
## Capturas
`tools/shot.mjs` maneja Chrome por CDP, avisa si algo desborda a lo ancho y
guarda la página completa.
```bash
pnpm shot http://localhost:3000 capturas/playground.png
ESCALA=2 pnpm shot ... # doble resolución, para publicar
EVAL='...' pnpm shot ... # ejecuta y muestra lo que devuelva
```
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues