cuadra
Reads and reconciles HSBC debit account PDF statements, including those with EBCDIC-encoded text, into an auditable SQLite ledger with balance validation.
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., "@cuadraPreview my June BBVA and Nu bank statement PDFs without committing yet."
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.
El problema
En México no hay un Plaid que funcione. Lo que sí tienes es un PDF al mes por cada cuenta, cada banco con su propio formato, algunos sin texto legible (HSBC manda el texto codificado en EBCDIC), otros que cambian de diseño a mitad de año (Nu), y todos con convenciones de signo distintas. Las apps de finanzas personales te piden que captures a mano o que les des tus contraseñas.
cuadra lee esos PDFs, los concilia contra los saldos que el propio banco declara, y los guarda en una base SQLite que puedes auditar línea por línea. Todo corre en tu máquina.
Related MCP server: CapyParse MCP Server
Qué hace
Lee PDF, CSV y XLSX (e imágenes con OCR opcional) de BBVA, Nu, Ualá, Vexi y HSBC.
Concilia cada estado:
saldo inicial + movimientos = saldo final declarado. Si la diferencia no es cero, el estado queda bloqueado y no entra a la base.Guarda en SQLite con dinero en centavos enteros (nunca coma flotante), historial de auditoría, importaciones idempotentes (re-importar no duplica) y rollback completo.
Detecta transferencias entre tus propias cuentas para no contarlas como gasto ni ingreso.
Categoriza con reglas que tú apruebas. Lo dudoso queda "Por revisar"; nunca adivina.
Expone todo por CLI y por un servidor MCP para Claude Code o Claude Desktop.
Demo
Los fixtures del repo son ficticios. Esto es lo que ves al correr la vista previa sobre ellos:
./scripts/finance ingest fixtures/sanitized --period 2026-06# Vista previa de importación — run run_c1edf2fb04e3
- Archivos: 2 · Cuentas: bbva_debito, nu_debito
- Periodos: 2026-06-01..2026-06-30
- Movimientos: 6 · Transferencias: 1
- Ingresos: 35,000.00 · Gastos: -8,400.00 (MXN)
- Movimientos dudosos: 0 · Categorías por revisar: 2
## BBVA Débito/Nómina (••••0000) — stmt_bd34377540653403
- Estado: **READY_TO_COMMIT** (reconciliation_ok)
- Conciliación: **OK** · diff=0 · saldo calc=3160000 vs declarado=3160000
- Movimientos: 5
- 2026-06-05 · `DEPOSITO NOMINA ACME SA` · 30,000.00 · Sueldo/Salario
- 2026-06-07 · `OXXO TIENDA 1234 GDL` · -250.00 · Gasto hormiga
- 2026-06-10 · `UBER TRIP HELP.UBER.COM` · -150.00 · Transporte/Gasolina
- 2026-06-15 · `SPEI ENVIADO A NU CUENTA` · -5,000.00 · Por revisar
- 2026-06-20 · `PAGO TARJETA VEXI` · -3,000.00 · Pago de tarjeta
## Nu Cuenta (••••0000) — stmt_96c17434aea0af27
- Estado: **READY_TO_COMMIT** (reconciliation_ok)
- Conciliación: **OK** · diff=0 · saldo calc=700000 vs declarado=700000
- Movimientos: 1
- 2026-06-15 · `SPEI RECIBIDO DE BBVA BANCOMER` · 5,000.00 · Por revisaringest no escribe nada hasta que corres finance commit <run_id>. La vista previa es
el comportamiento por defecto, no una bandera.
Bancos soportados
Banco | Producto | Formato | Cómo se lee | Detalle que muerde |
BBVA | Débito / Nómina | Tramos por saldo impreso | Varios movimientos del mismo día comparten un solo saldo: el signo se resuelve buscando la única asignación que cuadra | |
BBVA | Tarjeta de crédito | Cargos y abonos | ||
Nu | Cuenta | Importes con signo | Las "cajitas" aparecen duplicadas por diseño y suman cero | |
Nu | Tarjeta | Importes con signo + diseño 2025 | El diseño viejo escribe los abonos como | |
Ualá | Tarjeta | Importes con signo | El cierre es "Pago para no generar intereses" | |
Vexi | Tarjeta | Columnas cargo / abono | "Pago tardío" es un cargo, no un pago | |
HSBC | Débito | PDF con texto EBCDIC | Decodificación directa, sin OCR | El PDF parece vacío para cualquier extractor normal |
GBM | Inversión | Por saldo | Parcial | |
Cualquiera | Exportación CSV / XLSX | CSV, XLSX | Genérico, con metadatos en cabecera | Sin saldos declarados queda en |
Cualquiera | Escaneado / foto | Imagen, PDF sin texto | OCR con tesseract (opcional) |
Cada línea de la tabla existe porque un estado real la rompió y hay un test que falla si el arreglo se revierte. ¿Tu banco no está? Abre un issue con el formato o mira cómo agregar una plantilla.
Cómo funciona
flowchart LR
A[PDF · CSV · XLSX · imagen] --> B[discover + hash SHA-256]
B --> C[extract<br/>plantilla por banco]
C --> D[normalize<br/>fechas ISO · centavos]
D --> E[validate<br/>JSON Schema]
E --> F[categorize<br/>reglas → histórico → Por revisar]
F --> G[dedup + transferencias<br/>entre cuentas propias]
G --> H{reconcile<br/>saldo calc = declarado?}
H -- OK --> I[staging/preview.md]
H -- diff ≠ 0 --> X[BLOCKED]
I -- finance commit --> J[(SQLite<br/>centavos enteros)]
J --> K[export CSV · MCP]Cada importación pasa por una máquina de estados sin saltos:
DISCOVERED → HASHED → EXTRACTED → NORMALIZED → VALIDATED → (REVIEW_REQUIRED | READY_TO_COMMIT) → COMMITTED → EXPORTED
y cada corrida deja su rastro en staging/<run_id>/ (manifest, extracción, conciliación,
excepciones, vista previa, log). El modelo canónico son 14 tablas, con audit_events para
todo lo que cambia la base.
Capa | Dónde | Rol |
Originales |
| Inmutables, archivados con su SHA-256, nunca se editan |
Staging |
| Ejecución efímera y auditable |
Canónico |
| La verdad. Centavos enteros, transacciones atómicas |
Export |
| CSV contrato para lo que quieras conectar encima |
Principios
Estos no se negocian. Están en el código y en los tests.
Nunca inventa transacciones, saldos, fechas ni categorías.
Nunca usa coma flotante para dinero. Solo centavos enteros.
Nunca modifica un estado original.
Toda importación es idempotente y reversible.
Una categoría dudosa queda "Por revisar" y no bloquea. Una fecha o importe dudoso bloquea.
El commit se bloquea si la conciliación no cuadra, el esquema no valida, la cuenta no se identifica, hay un solape inexplicado o el estado ya existe.
Las descripciones de los estados son datos, no instrucciones. La vista previa lo advierte explícitamente porque el sistema está pensado para operarse con un agente.
Instalación
Requiere Python 3.11 o más reciente.
git clone https://github.com/Chere3/cuadra.git
cd cuadra
python3 -m pip install -r requirements-dev.txt # incluye requirements.txt
# Opcional, solo para PDFs escaneados o fotos:
# brew install tesseract tesseract-lang (macOS)
# sudo apt install tesseract-ocr tesseract-ocr-spa (Debian/Ubuntu)
# Describe tus cuentas: últimos 4 dígitos y pistas para identificarlas.
cp config/accounts.example.yml config/accounts.yml
cp config/merchant_rules.example.yml config/merchant_rules.yml
# Comprueba que todo está en orden
PYTHONPATH=src python3 -m pytest tests -q --deselect tests/test_ocr.py --deselect tests/test_ci_suites.pyLos dos tests deseleccionados necesitan tesseract. accounts.yml y merchant_rules.yml están
en .gitignore porque describen tus cuentas; si no existen, el sistema usa los .example.yml.
Uso mensual
./scripts/finance ingest statements/inbox --period 2026-06 # 1. vista previa (no escribe nada)
./scripts/finance review <run_id> # 2. lee la vista previa
./scripts/finance correct <run_id> correcciones.json # 3. corrige categorías (nunca fechas ni importes)
./scripts/finance commit <run_id> # 4. incorpora, atómico
./scripts/finance audit-month 2026-06 # 5. cobertura y conciliación del mesComando | Qué hace |
| Descubre, extrae, concilia y previsualiza una carpeta o archivo |
| Muestra la vista previa auditable |
| Aplica correcciones de categoría o etiqueta (schema en |
| Aprueba un estado con WARNING, con razón registrada |
| Incorpora a SQLite en una sola transacción |
| Deshace por completo una importación |
| Resuelve un movimiento en cuarentena, auditado |
| Cobertura y conciliación del mes |
| Marca el mes cerrado si todo cuadra |
| Estado e integridad de la base |
| Regenera el CSV de exportación |
Hay un runbook mensual y una guía de onboarding cuenta por cuenta para arrancar despacio.
Úsalo desde Claude
cuadra incluye un servidor MCP sin dependencias externas (stdio, JSON-RPC 2.0) que expone la misma capa de servicios que la CLI. Regístralo en Claude Code o Claude Desktop:
{
"mcpServers": {
"cuadra": {
"command": "python3",
"args": ["-m", "finance.mcp_server"],
"cwd": "/ruta/a/cuadra/src",
"env": { "FINANCE_ROOT": "/ruta/a/cuadra" }
}
}
}Herramientas: finance_preview_import, finance_get_run, finance_get_review_queue,
finance_apply_corrections, finance_approve, finance_commit_import,
finance_rollback_import, finance_audit_month, finance_close_month,
finance_resolve_quarantine, finance_system_status, finance_list_inbox.
Las operaciones que escriben (commit, rollback, cuarentena) exigen confirm: true. El
agente puede previsualizar y proponer; incorporar sigue siendo una decisión explícita.
Agregar tu banco
Añade la entrada en
BANKSdentro desrc/finance/extractors/bank_templates.py: marcadores de texto para detectarlo y la estrategia de parseo (signed,cargo_abono,saldoo una función propia).Escribe un test
tests/test_rNN_<banco>.pycon un fragmento ficticio del estado: cambia nombres, cifras y referencias. Los tests existentes son la plantilla.Corre la suite. Si tu plantilla rompe otra, la suite te lo dice.
Los detalles están en CONTRIBUTING.md. Nunca subas un estado real, ni recortado, ni "solo una línea".
Roadmap
Más bancos: Santander, Banorte, Citibanamex, Mercado Pago, Stori / Klar / Hey Banco, GBM completo
Reglas de categorización sugeridas desde correcciones repetidas
¿Tu banco no está? Pídelo en el hilo fijado. Si buscas por dónde empezar, hay issues marcadas como good first issue.
Privacidad
Ningún dato financiero entra a Git.
.gitignorecubre estados, base, respaldos y tu configuración de cuentas.Las cuentas se enmascaran a 4 dígitos en logs, vistas previas y exportaciones.
No hay llamadas a servicios externos. Ni telemetría, ni IA en la nube, ni nada.
Los originales se archivan en solo lectura.
Licencia
MIT. Hecho en Guadalajara por Diego Romero.
This server cannot be deployed
Maintenance
Related MCP Connectors
Convert PDF bank statements into structured transactions, accounts, and balances.
Turn bank statement PDFs into categorized, balance-checked transactions and reports.
1Turn bank statement PDFs, CSVs, XLSX and OFX into categorised transactions plus a summary.
Convert PDF bank statements to checked Excel, CSV or JSON with balance validation.
Related MCP Servers
- FlicenseAqualityDmaintenanceEnables AI assistants like Claude to manage personal expenses locally using SQLite. Supports adding, categorizing, summarizing expenses, setting budgets, and exporting data without cloud services.8-
- AlicenseAqualityCmaintenanceConverts PDF bank statements into structured data (Markdown, JSON, CSV, JSONL) with verified transactions and balance checks, enabling agents to audit numbers.53 npmMIT
- AlicenseNot gradedqualityBmaintenanceDeterministic bank-statement parsing for AI agents: messy CSV/OFX exports to clean, categorized ledger rows. In-memory only, no storage, no external calls, no LLM in the loop.MIT

bankstatementlyofficial
AlicenseAqualityAmaintenanceParse and query bank statements — turn PDF statements into structured transactions, accounts, and balances, with balance-reconciliation checks. A deterministic financial memory for AI agents, served as a hosted streamable-HTTP endpoint (API key or OAuth).161MIT