Luca MCP
Reads and writes the user's own Google Sheet (Movimientos, Categorías, Comercios, Ajustes) through their Apps Script Web App, allowing queries of monthly summaries, category breakdowns, top merchants, transaction lists and budget status, as well as registering new expenses with add_expense.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Luca MCPhow much did I spend on food this month and what's left in my budget?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Copia personal. Este repositorio es una copia de JosephRobles23/luca (lucaa.lat), creado por Joseph Robles y distribuido bajo licencia MIT. El historial de commits y el archivo
LICENSEoriginales se conservan sin cambios. Todo el crédito del trabajo original es de su autor.
Luca lee los correos de notificación de BCP y Yape que ya llegan a tu Gmail, los convierte en movimientos normalizados y categorizados dentro de una Google Sheet que es tuya, y te los muestra en un dashboard web. Opcionalmente captura los yapeos recibidos desde las notificaciones del iPhone y te deja consultar o registrar gastos desde Claude o ChatGPT mediante un servidor MCP.
Principio rector: los datos viven y se procesan en el Google del usuario. Luca no guarda transacciones, tokens de Google ni claves de API en su infraestructura. La web no tiene base de datos.
Demo en video
Related MCP server: ExpenseTracker MCP Server
Tabla de contenidos
Características
Ingesta automática desde Gmail: parsers deterministas para 9 tipos de correo de BCP y Yape (consumos con tarjeta, transferencias, pagos con QR, servicios, recargas, yapeos…), con escaneo cada 15 minutos e importación histórica reanudable.
Categorización en cascada: elección del usuario → reglas → caché de comercios aprendida → LLM opcional. Al LLM solo le llega
comercio + monto(ADR-004).Modelo de movimientos con tipos (
expense,income,transfer_in,internal_transfer…), P2P y multi-moneda PEN/USD (ADR-005).Web en lucaa.lat: resumen del mes, categorías, tendencias de 6 meses, comercios principales, recategorización, alta manual y gestión de conexiones. Lee y escribe la Sheet desde el navegador.
Dentro de Google Sheets: menú Luca, panel lateral, guía paso a paso y Dashboard con gráficos SVG.
iPhone (iOS 27): un atajo envía los yapeos recibidos directo a tu Apps Script, sin pasar por Luca (ADR-003).
Conector MCP para Claude y ChatGPT:
get_summary,category_breakdown,top_merchants,list_transactions,budget_statusyadd_expense(services/luca-mcp).Extractor LLM opt-in para correos no reconocidos, que recibe el texto enmascarado (ADR-008).
Cómo funciona
Cada usuario tiene su propia copia de una Sheet plantilla. Esa copia lleva un script ligado (el stub) que delega toda la lógica en una librería compartida de Apps Script (LucaLib). El script corre con la identidad del usuario y es el único componente que toca Gmail y los montos.
flowchart LR
subgraph Fuentes["Fuentes"]
G["Correos BCP / Yape<br/>(Gmail del usuario)"]
I["Notificación Yape<br/>(Atajo iOS)"]
W["Alta manual<br/>(web)"]
A["add_expense<br/>(Claude / ChatGPT)"]
end
subgraph GAS["Apps Script del usuario (stub + LucaLib)"]
P["Parsers deterministas<br/>correo · push"]
D["Deduplicación<br/>id + monto/minuto"]
C["Categorización<br/>usuario → reglas → caché → LLM"]
end
S[("Google Sheet del usuario<br/>Movimientos · Categorías · Comercios · Ajustes")]
G -->|trigger cada 15 min| P
I -->|POST /exec?events=1| P
A -->|Worker → POST /exec?mcp=1| D
P --> D --> C --> S
W -->|Sheets API desde el navegador| SArquitectura
Vista de componentes
flowchart TB
U(["Usuario"])
subgraph Google["Google del usuario"]
direction TB
SH[("Sheet 'Luca'<br/>copia de la plantilla")]
STUB["Stub ligado a la Sheet<br/>menú · triggers · doGet/doPost"]
LIB["LucaLib<br/>librería Apps Script compartida"]
GM["Gmail<br/>(gmail.readonly)"]
PROPS["UserProperties<br/>secretos del usuario"]
STUB --> LIB
LIB --> SH
LIB --> GM
LIB --> PROPS
end
subgraph Luca["Infraestructura de Luca (sin datos de usuario)"]
direction TB
WEB["Web Next.js<br/>lucaa.lat · Vercel<br/>Auth.js + Google"]
MCP["Worker luca-mcp<br/>mcp.lucaa.lat · Cloudflare<br/>OAuth 2.1 · D1 · KV"]
end
IA(["Claude / ChatGPT"])
IPH(["iPhone<br/>Atajos iOS 27"])
LLM(["Proveedor LLM<br/>(opcional, key del usuario)"])
U -->|navegador| WEB
WEB -->|"Sheets / Drive API<br/>token drive.file en el navegador"| SH
WEB -.->|GET /meta| MCP
IA -->|"MCP (Streamable HTTP)"| MCP
MCP -->|"POST /exec?mcp=1<br/>secreto por tenant"| STUB
IPH -->|"POST /exec?events=1<br/>token por dispositivo"| STUB
LIB -.->|"comercio + monto"| LLMComponente | Tecnología | Qué guarda |
LucaLib ( | Google Apps Script | Nada propio: escribe en la Sheet y en |
Stub ( | Apps Script ligado a la plantilla | Triggers y |
Web ( | Next.js 16, React 19, Auth.js v5, Tailwind 4 | Nada en servidor: tokens de Google solo en la cookie JWT cifrada |
Worker ( | Cloudflare Workers, |
|
Las decisiones de arquitectura están en docs/architecture/ (ADR-001…008).
Onboarding en tres pasos
sequenceDiagram
autonumber
actor U as Usuario
participant W as Web (lucaa.lat)
participant D as Google Drive
participant S as Sheet + Apps Script
U->>W: Entra con Google
W->>D: Picker sobre la plantilla y files.copy (drive.file)
D-->>W: Copia con appProperties {luca: ledger}
W-->>U: "Abre tu Sheet y autoriza"
U->>S: Menú Luca → Autorizar
S->>S: Consentimiento, trigger cada 15 min,<br/>importación del último mes
U->>W: Vuelve a la web
W->>D: files.list (localiza su Sheet)
W->>S: Lee Movimientos y Ajustes (Sheets API)
W-->>U: Dashboard
opt Paso 3 · conexiones
U->>S: Publica el Web App y conecta iPhone o IA
endConector MCP: pairing y llamada a una tool
El Worker es un relevo sin estado de datos: traduce MCP a una llamada al Web App del usuario y no ve ni guarda movimientos (ADR-001).
sequenceDiagram
autonumber
actor U as Usuario
participant S as Apps Script (/exec)
participant M as Worker luca-mcp
participant C as Claude / ChatGPT
U->>S: Sidebar → "Conectar IA"
S->>M: POST /enroll {webAppUrl, secret}
M->>S: Challenge HMAC contra /exec
S-->>M: Firma válida
M-->>S: Código de pairing (8 caracteres, un solo uso, 10 min)
U->>C: Añade el conector mcp.lucaa.lat/mcp
C->>M: OAuth 2.1 (DCR + PKCE) → /authorize
U->>M: Pega el código
M-->>C: Access token (props.tenantId, TTL 24 h)
C->>M: tools/call get_summary {month}
M->>S: POST /exec?mcp=1 {op, secret, args}
S-->>M: {ok: true, ...} calculado sobre la Sheet
M-->>C: Resultado de la toolPrivacidad y modelo de seguridad
Sin base de datos de usuarios. El vínculo usuario ↔ Sheet lo resuelve Drive (
appProperties); la web solo refresca tokens que viven en la cookie cifrada del usuario (ADR-006).Permisos mínimos. La web usa
drive.file(solo los archivos que Luca crea o que el usuario elige). El script del usuario usagmail.readonlypara leer notificaciones bancarias.Secretos por usuario en
PropertiesService.getUserProperties()de su propio script: API key del LLM, token del iPhone y secreto del conector MCP. Nunca en las Script Properties de la librería.El Worker no ve movimientos. Guarda solo
tenantId → {execUrl, secreto}y códigos de pairing que expiran.LLM opcional y acotado. Solo
comercio + monto; el extractor de correos desconocidos es opt-in y enmascara el texto antes de enviarlo.Sin analítica ni rastreadores.
¿Encontraste una vulnerabilidad? Repórtala en privado según SECURITY.md.
Empezar como usuario
Entra en lucaa.lat con tu cuenta de Google y pulsa Crear mi Sheet. Se copia la plantilla a tu Drive.
Abre la Sheet → menú Luca → Autorizar y acepta los permisos. Luca importa el último mes y queda escaneando cada 15 minutos.
Vuelve a la web para ver tu dashboard. Opcional: Activar conexiones para el iPhone (guía) y para tu IA (código de pairing → conector MCP).
No necesitas cuenta de GCP ni configurar ninguna nube.
Desarrollo
Requisitos
Node.js ≥ 20 y npm.
Para publicar LucaLib o el stub:
claspautenticado.Para el Worker:
wrangler(se instala con el paquete).Para la web en local: un cliente OAuth de Google y
apps/web/.env.local(copia deapps/web/.env.example). Guía:docs/guides/guia-dns-vercel-oauth.md.
Puesta en marcha
git clone https://github.com/JosephRobles23/luca.git
cd luca
npm install --prefix apps/web
npm install --prefix services/luca-mcp
npm test # tests Node: Apps Script (harness vm), lógica web y Worker
npm run web:dev # web en http://localhost:3000 (necesita apps/web/.env.local)
npm run dev:mock --prefix apps/web # web con datos simulados, sin Google (LUCA_MOCK=1)npm test no toca Google: las pruebas de Apps Script corren en un sandbox vm de Node con mocks de los servicios
(tests/gas-harness.mjs) y fixtures de correo sintéticos y anonimizados.
Comandos
Comando | Qué hace |
| Todos los tests unitarios (Apps Script, web y Worker) |
| E2E con Playwright sobre la web en modo mock |
|
|
| Build de producción de la web |
| Verifica que la versión de LucaLib coincide en los 4 sitios |
|
|
|
|
| Despliega el Worker |
Convenciones
Apps Script (
gas/): sinimport/export; funciones privadas con sufijo_; toda llamada de la UI pasa porlucaRun→dispatch(lista blanca). Un archivo nuevo engas/sharedse añade aRUNTIME_FILESentests/gas-harness.mjs.Web: lógica pura en
apps/web/src/lib/*.tscon tests.test.mjs; los componentes solo presentan.Parsers deterministas primero; el LLM es siempre opcional.
Fixtures sintéticos y anonimizados en
tests/fixtures. Los correos reales nunca se versionan.
El detalle está en CLAUDE.md (guía para agentes y colaboradores) y el vocabulario en CONTEXT.md.
Estructura del repositorio
gas/shared/ LucaLib: parsers, ledger, escaneo Gmail, categorización, LLM opcional, MCP, UI de la Sheet
gas/stub/ script ligado a la plantilla (bootloader delgado: menú, triggers, doGet/doPost)
apps/web/ web Next.js (lucaa.lat): login, onboarding, dashboard, conexiones; sin base de datos
services/luca-mcp/ Worker de Cloudflare (mcp.lucaa.lat): OAuth 2.1, pairing y tools MCP
scripts/ release-check, eml-check, build-previews
tests/ harness vm con mocks de Apps Script y fixtures sintéticos
spikes/ experimentos de validación (S1–S7) y sus resultados
docs/ arquitectura y ADRs, guías, research, discovery, estado del desarrolloReleases
Una release publica una versión nueva de LucaLib y repite su número en cuatro sitios (LUCA_VERSION, el manifiesto
del stub, wrangler.toml y .env.example). El procedimiento completo está en
.claude/skills/deploy-luca/SKILL.md.
Las copias existentes de los usuarios no se actualizan solas: la web y el panel de la Sheet avisan cuando hay una versión nueva y muestran cómo subirla (ADR-006 §5).
Documentación
Tema | Dónde |
Arquitectura base, ADRs y plan | |
Estado del desarrollo | |
Formatos reales de correos BCP/Yape | |
DNS, Vercel y clientes OAuth | |
Consola de GCP (operador) | |
Captura de yapeos en iPhone | |
Servidor MCP | |
Sistema de diseño | |
Investigaciones con fuentes |
Contribuir
Las contribuciones son bienvenidas. Lee CONTRIBUTING.md antes de abrir un PR. Las reglas que no se negocian: los datos se quedan en el Google del usuario, el usuario final no configura ninguna nube y los secretos nunca entran al repositorio.
Licencia
MIT © 2026 Joseph Robles.
Luca no está afiliado a BCP, Yape, Google, Anthropic, OpenAI ni Cloudflare. Las marcas pertenecen a sus dueños.
This server cannot be deployed
Maintenance
Related MCP Connectors
- Era ContextOAuthapp.era
Personal finance, bank account, and shared memory connector for Claude, ChatGPT, Gemini Spark & more
Log, query, and edit expenses, budgets, and accounts in Ledgy from any MCP-compatible AI assistant.
Ask Claude about your income and spending, and import bank statements. No bank login.
- ManiloOAuthapp.ledgy.api
Log, query, and edit expenses, budgets, and accounts in Manilo (formerly Ledgy) from any MCP-compatible AI assistant.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceEnables AI agents to manage personal expenses through natural language conversations. Supports adding, searching, and analyzing transactions with automatic categorization and financial insights.3MIT
- FlicenseCqualityDmaintenanceEnables AI assistants to manage personal finances by storing, analyzing, and exporting expense data using a persistent PostgreSQL database. Supports adding/editing expenses, generating spending summaries, detecting top categories, and creating monthly reports.12-
- AlicenseNot gradedqualityDmaintenanceProvides read-only access to Tiller Money financial data in Google Sheets, enabling natural language queries for accounts, transactions, categories, and budgets through Claude Desktop.10MIT
- AlicenseNot gradedqualityDmaintenanceEnables users to manage personal expenses through natural conversation with Claude, including adding, updating, deleting expenses, and viewing summaries by category or date range.3MIT