Servidores Ecosistema

Servidor MCP local: analizamos mcp-supermercados-cl

Analizamos mcp-supermercados-cl, un servidor MCP local por stdio para supermercados de Chile: tools, adaptadores, carro vía navegador y pruebas propias.

Por

Datos a 15 de octubre de 2026

mcp-supermercados-cl es un servidor MCP local que ofrece a tu asistente herramientas para armar listas de compra en supermercados de Chile. NLACE-COM lo publica con licencia MIT; tu cliente MCP lo arranca en tu máquina y le habla por stdio.

MCP es el protocolo que permite a un asistente usar esas herramientas. El cliente MCP es la aplicación donde chateas con el modelo, también llamada host; stdio es la entrada y salida estándar del proceso. El servidor consulta el catálogo público mediante adaptadores para cinco cadenas y prepara una petición para el carro que se ejecutaría en tu navegador con sesión. Veremos cómo separa esas tareas y dónde queda la frontera.

Te basta con saber qué es una tool (una función con nombre que el modelo puede invocar) y qué hace un cliente MCP. Si no, empieza por la lección de Arquitectura o el glosario de MCP.

Cómo lo hemos hecho. El 15 de octubre de 2026 leímos el código del commit 3441cca, que corresponde al paquete 1.4.7. Lo compilamos y lo ejecutamos en local, sin cuentas ni claves. No llamamos a las webs de las tiendas ni ejecutamos ningún snippet en un navegador. Tampoco hemos hablado con el autor, así que las opiniones son nuestras.

Una compra de ejemplo, de la lista al carro

El servidor convierte una lista escrita a mano en productos concretos y, si quieres, prepara el cambio en el carro para que lo ejecutes tú. El recorrido que sigue es un ejemplo imaginado a partir del código. No lo hemos ejecutado contra ninguna tienda.

Imagina que le pides a tu asistente una lista con leche, arroz de 1 kg y café de grano en Jumbo, con un tope de gasto. El modelo llamaría a build_list con esos ítems en texto libre y el presupuesto en pesos chilenos. Según su definición, la tool elige por precio por unidad y ofertas vigentes y devuelve, por ítem, el producto elegido, hasta tres alternativas y el total estimado.

Después pides meter esos productos en el carro. Aquí el servidor no toca tu cuenta. La tool add_to_cart arma la petición exacta y un browserSnippet, un fragmento de JavaScript para ejecutar en una pestaña de jumbo.cl donde ya hayas iniciado sesión. En este commit solo admite Jumbo. Si todavía no le devuelves el resultado, responde con executed: false. Este es el código literal de esa rama:

      if (rawCartResult !== undefined) {
        const cart = parseCart(rawCartResult, store);
        return {
          content: [
            { type: "text", text: JSON.stringify({ executed: true, cart }, null, 2) },
          ],
        };
      }
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify({ executed: false, request }, null, 2),
          },
        ],
      };

Código de mcp-supermercados-cl: src/tools/cart.ts, líneas 75-90 del commit 3441cca.

Fíjate en ese executed: false. Quiere decir que la tool ha preparado la petición, pero no sabe si alguien la ha ejecutado en el navegador. Esa respuesta no acredita ningún cambio en el carro ni una compra.

Si le pasas el JSON que devolvió el navegador en rawCartResult, la tool responde executed: true con el carro normalizado. Tampoco comprobamos que ese JSON proceda de una operación real. La propia descripción de la tool avisa de que añadir al carro “no es una compra”.

La arquitectura: un proceso local por stdio

El servidor es un único proceso en tu máquina. Habla con el cliente por stdio y desde allí lee las webs de las tiendas.

Un transporte es el canal por el que cliente y servidor intercambian mensajes. En stdio el cliente lanza el servidor como subproceso y los dos se hablan por la entrada y la salida estándar. Cada línea es un mensaje JSON-RPC, el formato de petición y respuesta que usa MCP, y el servidor no puede escribir en stdout nada que no sea un mensaje MCP.

El proyecto lo cumple desde su punto de entrada. Crea un StdioServerTransport, conecta el servidor y manda su aviso de arranque a stderr, el canal de error separado de la salida estándar. La especificación de transportes permite los registros en stderr. Cómo configurar un servidor stdio en tu cliente lo explicamos en conectar un servidor MCP a Claude.

Detrás del transporte hay un único McpServer, la clase del SDK oficial de MCP, que registra todas las tools y los prompts. Las tools llegan a un registro de adaptadores, uno por cadena, y las lecturas públicas salen por un cliente HTTP común con colas y reintentos. Esas peticiones salen desde tu máquina.

Figura 1. Fronteras de mcp-supermercados-cl según index.ts, server.ts y cart.ts del commit 3441cca. Las flechas discontinuas muestran el camino previsto del carro, que pasa por la persona y su navegador; la tool no hace esa petición a la tienda.

La figura separa tres zonas de confianza. En el recorrido documentado para el carro, tu sesión vive en el navegador. No le pasas al servidor tus credenciales, pero sí puede recibir el JSON que devuelvas por stdio.

Las webs de las cadenas son terceros. Antes de ejecutar el snippet y devolver su resultado, conviene revisar ambos. Las instrucciones del servidor prohíben al modelo pedir usuario o clave. No hemos comprobado qué datos personales puede llevar ese JSON.

Listas y catálogo: tools con un objetivo

Las tools del proyecto se reparten en dos grupos. Una tool es una función con nombre y esquema de entrada que el modelo puede invocar. El proyecto separa las tools que resuelven una tarea de compra de las que solo leen el catálogo.

El registro en server.ts lo agrupa con comentarios. El núcleo arma la lista con build_list, suggest_swaps, get_frequent_purchases y get_saved_lists. La lectura de catálogo va aparte, con search_products, get_product y get_offers. Después vienen el carro, la comparación entre cadenas y el diagnóstico.

build_list es el ejemplo de tool orientada al resultado. Recibe hasta 30 ítems en texto libre, filtros de oferta y stock y un presupuesto máximo, y devuelve una lista decidida. Envolver el endpoint de búsqueda de cada cadena habría obligado al modelo a hacer ese trabajo llamada a llamada. search_products, en cambio, es una lectura de catálogo, y su esquema Zod, la declaración de parámetros con la librería Zod, acota limit entre 1 y 50 y filtra por precio. Es lo que pedimos en la lección de Herramientas y en Diseño de servidores MCP del nivel Avanzado.

El servidor añade cinco prompts, plantillas que la persona elige en su cliente, como armar_lista o conectar_sesion (prompts.ts). No registra resources, los datos que un servidor ofrece para que el cliente los lea, así que las capacidades que anuncia al cliente son solo tools y prompts.

Adaptadores por cadena y errores con siguiente paso

El proyecto usa un adaptador por cadena y devuelve errores con un siguiente paso. Como cada supermercado tiene su propia web, las tools piden el adaptador por nombre sin necesitar los detalles de cada tienda.

El registro es un mapa de cinco entradas. Jumbo y Santa Isabel comparten la implementación de Cencosud con configuraciones distintas. Unimarc, Tottus y Líder tienen la suya.

Figura 2. Registro de adaptadores de registry.ts en el commit 3441cca.

Nos gusta que no finja una cobertura igual para todas. La tabla del README dice qué cadena tiene búsqueda, precio de socio o carro, y solo Jumbo marca el ciclo completo. Describe el diseño y no garantiza que las cinco webs respondan hoy.

Los errores siguen la misma idea. Cada uno lleva una categoría, un mensaje y un campo action con el siguiente paso para la persona, como volver a iniciar sesión o reintentar (errors.ts). La tool los devuelve con isError, el indicador de MCP que marca un resultado como error. Así el modelo lo ve como resultado y puede actuar.

Cuando Líder o Tottus bloquean la búsqueda, search_products devuelve openUrl, browserSnippet y retryWith. Es el mismo patrón del carro aplicado a la lectura.

Ese bloque menciona además un puente con Playwright, una herramienta que automatiza un navegador, que se activa con una variable de entorno. No lo hemos probado.

Por qué local y cuándo deja de bastar

El autor explica en el README que el servidor no tiene URL de producción a propósito. Lo que necesita para funcionar está en tu máquina, y un despliegue en la nube lo perdería. Deja de bastar si quieres ofrecer un único servicio remoto compartido.

Sus razones son dos. Unimarc, Tottus y Líder bloquean, según ese apartado, el tráfico de centros de datos y necesitan tu IP residencial. Y el precio de socio, tus compras frecuentes y el carro viven en tu navegador con sesión, así que las credenciales no pasan por un servidor central. Lo primero es una afirmación del autor que no hemos comprobado. El propio README no la mantiene igual, porque más abajo, en su apartado sobre el antibot de Líder y Tottus, atribuye el bloqueo a la huella del cliente (TLS y un desafío JavaScript) y dice «No es tu IP». Lo segundo se ve en el código del carro.

Para stdio, la especificación recomienda no usar su autorización OAuth, el estándar para dar acceso a una cuenta sin compartir la clave, y tomar las credenciales del entorno. Este servidor ni siquiera las necesita, porque ante la tienda se autentica tu navegador.

El proceso local puede servir a cada persona por separado. Un servicio remoto compartido necesitaría un transporte como Streamable HTTP, el transporte de MCP sobre HTTP, además de autorización y aislamiento por usuario.

Si lo desplegaras en un centro de datos, el apartado de instalación del README dice que no funcionaría con esas tres cadenas, aunque su explicación de Líder y Tottus apunta a la huella del cliente y no a la IP.

También falta una pieza si el cliente ejecuta el snippet por su cuenta. Entonces la confirmación antes de cambiar el carro debe quedar en el cliente. Es el mismo debate de quién confirma una compra que tratamos en WebMCP en tiendas y pagos. Estas son propuestas nuestras a partir del diseño.

Qué probamos y qué no

Ejecutamos el proyecto en local con un entorno vacío, sin claves ni perfiles de navegador. Probamos la compilación y los tests sin red, y mantuvimos una conversación MCP con un cliente mínimo. No probamos tiendas ni compras.

npm ci --ignore-scripts y npm run build terminaron sin errores. npm test, que en este commit lanza vitest run tests/adapters, terminó con código 1. Estas son las dos últimas líneas del resumen, copiadas de nuestro registro:

 Test Files  1 failed | 24 passed (25)
      Tests  2 failed | 178 passed (180)

Los dos fallos están en offersCollection.test.ts, que simula la rotación de la colección de ofertas de Jumbo. Sus datos de prueba caducan en agosto de 2026, y el selector compara con Date.now() si no recibe un reloj. El 15 de octubre ya no queda ninguna colección vigente en los datos de prueba. Es un test que depende de la fecha, y no demuestra ningún fallo con la web real.

La integración continua solo ejecuta pruebas sin red, y las que tocan webs o sesiones reales van en scripts aparte. Nos parece buena práctica.

Después conectamos un cliente mínimo, escrito con el mismo SDK, a node dist/index.js. En la salida, capabilities es lo que el servidor anuncia al conectarse y get_cart la única tool que llamamos. Nuestro script imprimió esto, resumido por él mismo:

capabilities {"prompts":{"listChanged":true},"tools":{"listChanged":true}}
get_cart {"needsRawCart":true,"requestMethod":"GET","hasSnippet":true}
prompt {"messages":1,"role":"user"}

tools/list, la petición que pide al servidor sus tools, devolvió los 14 nombres y prompts/list los cinco prompts. prompts/get, con el ítem ficticio «arroz», devolvió un mensaje de usuario. Que aparezcan en la lista no prueba que las 14 tools funcionen.

Solo llamamos a get_cart sin datos de sesión, y devolvió las instrucciones para un GET sin consultar ningún carro. No probamos compras, cuentas, sesiones, snippets, webs de tiendas ni la calidad de las recomendaciones.

Queda la versión del protocolo. El curso enseña MCP 2026-07-28, y este análisis no evalúa esa versión.

package.json usa el SDK v1, y el que se instaló en nuestra prueba declara 2025-11-25 como versión más reciente. Solo comprobamos que un cliente del mismo SDK negocia con él. El proyecto no dice soportar 2026-07-28, así que no lo contamos como fallo.

Según la especificación, un cliente que solo hable 2026-07-28 no funciona con un servidor de versiones anteriores. Uno que hable ambas cae al saludo inicial antiguo, initialize. No lo hemos probado con este servidor. Ese paso lo explicamos en migrar un servidor MCP a 2026-07-28.

Qué mejoraríamos

Mejoraríamos tres cosas pequeñas: fijar el reloj de los tests, aclarar qué significa executed: true y documentar las versiones del protocolo. No hemos cambiado nada en el repositorio ajeno.

  1. Pasar un reloj fijo al selector en los dos tests de rotación de ofertas, ya que admite uno inyectado. Así la suite no dependería del día en que se ejecute.
  2. Dejar escrito en la documentación cuándo add_to_cart solo prepara la acción y que executed: true solo indica que la tool ha normalizado el JSON recibido, sea cual sea su procedencia. Una confirmación fiable dependería de comprobar en el navegador o en el cliente la respuesta de la tienda y el estado real del carro. La planteamos como mejora de experiencia de uso. No señalamos ninguna vulnerabilidad.
  3. Documentar con qué versiones del protocolo se ha probado el servidor y, si llega el momento, planificar la migración a 2026-07-28.

Si quieres comparar con otro servidor abierto revisado con los mismos criterios, lee los servidores MCP de Inditex por dentro.

Aprende esto en el curso

  • Básico Gratis Arquitectura · Host, cliente y servidor; JSON-RPC y los dos transportes
  • Básico Gratis Herramientas · Acciones que el modelo puede invocar, con esquemas y errores
  • Avanzado 10 € Diseño de servidores MCP · Tools bien dimensionadas, estado explícito y errores útiles

La lección 1 la puedes leer ya, sin registro. Las otras 13 del Básico son gratis con una cuenta.

Empieza gratis

Fuentes

  1. NLACE-COM/mcp-supermercados-cl, commit 3441cca analizado
  2. mcp-supermercados-cl: licencia MIT
  3. mcp-supermercados-cl: README, por qué se instala en local
  4. mcp-supermercados-cl: tools de carro (src/tools/cart.ts)
  5. MCP 2026-07-28: transportes
  6. MCP 2026-07-28: ciclo de vida y compatibilidad

Artículos relacionados