Leporello

MCP remoto para horarios de eventos de ópera y música clásica

Documentación

Leporello

Leporello

Ópera y música clásica: programación de eventos remota MCP.
También disponible como aplicación web en leporello.app.

Sedes compatibles

¿Falta tu sede favorita? ¡Se aceptan PRs! Lee CONTRIBUTING.md para instrucciones paso a paso sobre cómo añadir un nuevo scraper de sedes.

SedeCiudad
Staatsoper StuttgartStuttgart
Stuttgarter PhilharmonikerStuttgart
Wiener StaatsoperVienna
Metropolitan OperaNew York
Oper FrankfurtFrankfurt
San Francisco OperaSan Francisco
Gran Teatre del LiceuBarcelona
SemperoperDresden
Opéra National de ParisParis
Carnegie HallNew York
Teatro RealMadrid
Staatsoper Unter den LindenBerlin
Sydney Opera HouseSydney
Philharmonie de ParisParis
Bayerische StaatsoperMünchen
Berliner PhilharmonieBerlin
GewandhausLeipzig
Tonhalle-Orchester ZürichZürich
Lyric Opera of ChicagoChicago
Palau de la Música CatalanaBarcelona
Royal Opera HouseLondon
Teatro alla ScalaMilano
Auditorio Nacional de MúsicaMadrid
Salzburger FestspieleSalzburg
ElbphilharmonieHamburg
Opernhaus ZürichZürich
ConcertgebouwAmsterdam
Kölner PhilharmonieKöln
MusikvereinWien
Wiener KonzerthausWien
Barbican HallLondon
Hamburgische StaatsoperHamburg

Cómo funciona

Los scrapers específicos de cada sede obtienen las páginas de programación (HTML o JSON) de los teatros de ópera y salas de conciertos, las analizan con Cheerio y almacenan los eventos en una base de datos SQLite local. Un programador node-cron vuelve a rastrear todas las sedes diariamente a las 03:00 UTC, reemplazando los eventos de cada sede con los datos más recientes. El servidor expone los datos a través de un endpoint Model Context Protocol (MCP), de modo que cualquier asistente de IA compatible con MCP pueda consultar las próximas actuaciones. Un frontend estático de Astro lee la misma base de datos en el momento de la compilación y sirve un listado de eventos filtrable en leporello.app.

Herramientas MCP

HerramientaDescripción
list_countriesTodos los países con recuentos de ciudad/sede
list_citiesTodas las ciudades con sedes, opcionalmente filtradas por país
list_venuesTodas las sedes, opcionalmente filtradas por país o ciudad
list_eventsPróximos eventos filtrados por país, ciudad o sede

Privacidad

La instancia alojada en leporello.app registra el uso agregado de MCP (nombre de la herramienta, argumentos, tiempo de respuesta, User-Agent y un hash salado rotativo diario de la IP del cliente) para que pueda ver qué funciona y qué no. Sin IPs sin procesar, sin datos personales, sin tokens de autenticación.

Ejecutar localmente

npm install
npm test          # run scraper tests

npm run scrape                       # one-off scrape all venues
#or
npm run scrape -- wiener-staatsoper  # scrape a single venue

npm run dev       # start server on http://localhost:3000
# or
npm run dev:fresh # scrape, then serve

Rastrea diariamente a las 03:00 UTC. Ejecuta npm run scrape para poblar la base de datos en el primer uso.

Docker

Dos contenedores: web (servidor HTTP + MCP + frontend estático) y scraper (obtiene datos de las sedes en SQLite). Comparten un volumen de datos. La pila web es docker-compose.yml; el scraper es un trabajo de una sola ejecución en docker-compose.scrape.yml bajo su propio proyecto compose (leporello-scrape) para que su contenedor finalizado nunca se cuente contra la salud de la pila web. Prográmalo con un trabajo cron del host.

# Start the web server
docker compose up -d

# Run all scrapers (one-off, container stops when done)
docker compose -f docker-compose.scrape.yml run --rm scraper

# Scrape a single venue
docker compose -f docker-compose.scrape.yml run --rm scraper node dist/scrape.js wiener-staatsoper

# Rebuild the Astro frontend (e.g. after a manual scrape)
docker compose exec web node -e "
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
await promisify(execFile)('npm', ['run', 'build', '--prefix', 'web'], { cwd: '/app', timeout: 60000 });
console.log('done');
"

# Tail logs
docker compose logs -f web

El contenedor web reconstruye el frontend de Astro en cada inicio. Para ejecutar los scrapers de forma programada, añade un trabajo cron del host que rastree y luego reinicie web:

0 3 * * * cd /home/phil/docker/lep && docker compose -f docker-compose.scrape.yml build && docker compose -f docker-compose.scrape.yml run --rm scraper && docker compose restart web