Leporello

MCP remoto para agendas de eventos de Ópera e Música Clássica

Documentação

Leporello

Leporello

Agenda remoto de eventos de ópera e música clássica via MCP.
Também disponível como aplicativo web em leporello.app.

Locais Suportados

Falta o seu local favorito? PRs são bem-vindos! Leia CONTRIBUTING.md para instruções passo a passo sobre como adicionar um novo scraper de local.

LocalCidade
Staatsoper StuttgartStuttgart
Stuttgarter PhilharmonikerStuttgart
Wiener StaatsoperViena
Metropolitan OperaNova York
Oper FrankfurtFrankfurt
San Francisco OperaSão Francisco
Gran Teatre del LiceuBarcelona
SemperoperDresden
Opéra National de ParisParis
Carnegie HallNova York
Teatro RealMadri
Staatsoper Unter den LindenBerlim
Sydney Opera HouseSydney
Philharmonie de ParisParis
Bayerische StaatsoperMunique
Berliner PhilharmonieBerlim
GewandhausLeipzig
Tonhalle-Orchester ZürichZurique
Lyric Opera of ChicagoChicago
Palau de la Música CatalanaBarcelona
Royal Opera HouseLondres
Teatro alla ScalaMilão
Auditorio Nacional de MúsicaMadri
Salzburger FestspieleSalzburgo
ElbphilharmonieHamburgo
Opernhaus ZürichZurique
ConcertgebouwAmsterdã
Kölner PhilharmonieColônia
MusikvereinViena
Wiener KonzerthausViena
Barbican HallLondres
Hamburgische StaatsoperHamburgo

Como funciona

Scrapers específicos de cada local buscam páginas de agenda (HTML ou JSON) de casas de ópera e salas de concerto, analisam-nas com Cheerio e armazenam os eventos em um banco de dados SQLite local. Um agendador node-cron re-executa a raspagem de todos os locais diariamente às 03:00 UTC, substituindo os eventos de cada local pelos dados mais recentes. O servidor expõe os dados por meio de um endpoint Model Context Protocol (MCP), para que qualquer assistente de IA compatível com MCP possa consultar as próximas apresentações. Um frontend estático em Astro lê o mesmo banco de dados no momento da compilação e serve uma listagem de eventos filtrável em leporello.app.

Ferramentas MCP

FerramentaDescrição
list_countriesTodos os países com contagens de cidades/locais
list_citiesTodas as cidades com locais, opcionalmente filtradas por país
list_venuesTodos os locais, opcionalmente filtrados por país ou cidade
list_eventsPróximos eventos filtrados por país, cidade ou local

Privacidade

A instância hospedada em leporello.app registra o uso agregado do MCP (nome da ferramenta, argumentos, tempo de resposta, User-Agent e um hash salgado rotativo diário do IP do cliente) para que eu possa ver o que está funcionando e o que não está. Sem IPs brutos, sem dados pessoais, sem tokens de autenticação.

Executar 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

Raspagem diária às 03:00 UTC. Execute npm run scrape para popular o banco de dados no primeiro uso.

Docker

Dois contêineres: web (servidor HTTP + MCP + frontend estático) e scraper (busca dados de locais no SQLite). Eles compartilham um volume de dados. A pilha web é docker-compose.yml; o scraper é um job de execução única em docker-compose.scrape.yml sob seu próprio projeto compose (leporello-scrape) para que seu contêiner encerrado nunca seja contabilizado na verificação de saúde da pilha web. Agende-o com um job cron no 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

O contêiner web reconstrói o frontend Astro a cada inicialização. Para executar scrapers em um agendamento, adicione um job cron no host que faça a raspagem e depois reinicie o 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