Skip to main content
Glama
McpStorefront

Sneaker Carousel MCP App

README.md
# Sneaker Carousel MCP App

Demo portable de **MCP Apps** para mostrar en Claude: carrusel de zapatillas, selección de talle/cantidad y botón de pago simulado.

## Qué demuestra

- Un tool visible para el modelo: `show-sneaker-carousel`.
- Un recurso `ui://sneaker-drop/carousel.html` renderizado por el host.
- HTML, CSS y JavaScript empaquetados en un único archivo.
- Una llamada UI → host → servidor mediante `app.callServerTool()`.
- Un tool privado para la UI: `prepare-demo-checkout`.
- Validación autoritativa de producto, talle y total en el servidor.
- Adaptación al tema y tipografías del host.

> El pago es una simulación. No solicita tarjeta ni procesa dinero.

## Ejecutar localmente

Requisitos: Node.js 20 o superior.

```bash
npm install
npm run build
npm start
```

Endpoint MCP:

```text
http://localhost:3001/mcp
```

Health check:

```text
http://localhost:3001/
```

Vista previa del carrusel sin un host MCP:

```text
http://localhost:3001/preview
```

## Probar con el basic-host oficial

En otra carpeta:

```bash
git clone https://github.com/modelcontextprotocol/ext-apps.git
cd ext-apps
npm install
SERVERS='["http://localhost:3001/mcp"]' npm start
```

Abrí `http://localhost:8080`, elegí `show-sneaker-carousel` y ejecutá el tool.

## Deploy con Docker

```bash
docker build -t sneaker-mcp-app .
docker run --rm -p 3001:3001 sneaker-mcp-app
```

Podés desplegar el Dockerfile en Railway, Render, Fly.io, Cloud Run o ECS. El servicio debe quedar públicamente accesible por HTTPS.

Ejemplo final:

```text
https://tu-dominio.example/mcp
```

## Conectarlo a Claude

1. Desplegá el proyecto con HTTPS.
2. En Claude abrí **Customize / Connectors**.
3. Elegí **Add custom connector**.
4. Pegá `https://tu-dominio.example/mcp`.
5. Para esta demo, seleccioná conexión sin autenticación si Claude ofrece esa opción.
6. En un chat, activá el conector y escribí:

```text
Mostrame el carrusel de zapatillas y ayudame a elegir una.
```

Claude debería llamar `show-sneaker-carousel` y renderizar la MCP App dentro de la conversación.

## Checkout externo opcional

Si definís:

```bash
DEMO_CHECKOUT_URL=https://example.com/checkout
```

el servidor devolverá esa URL y la MCP App pedirá al host abrirla. Para una integración real, generá una URL única de checkout en el backend y confirmá el pago por webhook. No confíes en el monto enviado por la interfaz.

## Estructura

```text
.
├── main.ts              # servidor HTTP/stdio
├── server.ts            # tools y recurso MCP App
├── mcp-app.html         # entrada de la UI
├── src/
│   ├── mcp-app.ts       # comportamiento del carrusel y checkout
│   └── styles.css       # estilos responsivos
├── Dockerfile
└── render.yaml
```

## Solución de problemas

### `outputSchema` no acepta `z.object(...)`

Esta versión usa `@modelcontextprotocol/ext-apps` 1.7.4 junto con el SDK MCP 1.29.0. Los helpers del servidor terminan delegando en la API Zod del SDK 1.x, por lo que los schemas de salida se pasan como shapes:

```ts
outputSchema: StoreOutputSchema.shape
```

### `root is possibly null`

El elemento raíz se valida una vez y luego se guarda con tipo `HTMLElement`, de modo que TypeScript conserva el tipo dentro de callbacks.

### `Cannot find module dist/main.js`

`dist/main.js` se genera recién cuando `npm run build` termina correctamente. Ejecutá:

```bash
rm -rf dist
npm run build
npm start
```

### Avisos de `npm audit`

Los avisos de auditoría no causan los errores de compilación. Revisalos con:

```bash
npm audit
npm audit fix
npm run build
```

No ejecutes `npm audit fix --force` sin revisar los cambios, porque puede instalar actualizaciones mayores incompatibles.

## Compatibilidad con Claude

La UI primero lee `structuredContent`. Como fallback de compatibilidad, también puede recuperar el catálogo y la orden desde un payload JSON marcado dentro de `content`. Esto permite que la demo siga renderizando en hosts que no reenvían `structuredContent` al iframe.