Acopia
FreeNot checkedMCP server for querying and simulating the dispatch plan of a solar PV + battery system in the Chilean electricity market, using deterministic optimization and
About
MCP server for querying and simulating the dispatch plan of a solar PV + battery system in the Chilean electricity market, using deterministic optimization and optional DRL.
README
Motor de optimización de despacho para plantas solares con batería (PV-BESS) en el mercado eléctrico chileno. Pronostica la generación PV y el costo marginal (CMg) nodal con incertidumbre explícita, y decide cuándo cargar/descargar la batería para arbitrar el diferencial de CMg y rescatar energía que se vertería por congestión. El núcleo es determinista predict-then-optimize: mismo forecast, misma semilla → el mismo plan, bit a bit, con el motivo de cada decisión explicable hora por hora.
El problema que ataca: Chile vertió 6.084 GWh de energía renovable en 2025 (+7,8% vs 2024); entre 2022 y mediados de 2025 el vertimiento acumulado ronda los 11.900 GWh ≈ US$562M perdidos, con el CMg colapsando a 0 a mediodía por sobreoferta solar y disparándose en la punta vespertina. Ese diferencial es exactamente lo que una batería bien despachada captura.
🔭 Observatorio en vivo — la cara pública de Acopia: vertimiento renovable de Chile con datos oficiales del Coordinador (ene–may 2026: 2.463 GWh vertidos), regenerado mensualmente, con el snapshot del dashboard demo incluido.
Arquitectura completa y decisiones (ADRs) en SAD_Acopia_energia.md · Contexto de trabajo en CLAUDE.md.
Resultados medidos
Todo número de abajo sale de backtests reproducibles sobre datos reales chilenos (CMg horario de la barra S.GREGORIO, año 2025, del Coordinador Eléctrico; generación PV TMY de Antofagasta, Explorador Solar):
| Qué se midió | Resultado |
|---|---|
| Forecast de CMg (backtest anual, 7 folds) | Seq2Seq-LSTM régimen-local: RMSE −23% vs baseline estacional-naïve (20.3k vs 26.2k mills/MWh) |
| Elección de ventana de entrenamiento | Sweep de 6 ventanas: curva en U con mínimo en 720 h — la config no es frágil (enmienda ADR-002.2) |
| Robustez del plan en ejecución | Optimización estocástica con 5 escenarios: ~100% de captura del ingreso foresight (vs 93% con escenario único) |
| Modo DRL (PPO) vs núcleo determinista | El DRL captura el 96.1% del LP — el determinista gana y queda medido, no asumido (ADR-005) |
| Honestidad del experimento | La primera corrida DRL "superó" al óptimo → se auditó el baseline y se encontró un bug real de cuantización que valía +8.9% de ingreso del LP (AUD-003, pagada) |
Cómo funciona
- Pronostica con incertidumbre (nunca un número pelado): estacional-naïve, SARIMAX y Seq2Seq-LSTM detrás de un mismo puerto producen escenarios probabilísticos deterministas.
- Optimiza el despacho: LP estocástico de dos etapas (cvxpy + HIGHS) que co-optimiza arbitraje de CMg + reserva de frecuencia (SSCC) en una sola función objetivo, respetando la física de la batería (SoC, eficiencias, throughput) como restricciones duras.
- Deja rastro auditable: cada plan persiste su snapshot as-seen (forecast, estado, política versionada, semilla, huella SHA-256 del histórico) — un auditor regenera el plan bit a bit.
- Se explica y se simula vía una capa MCP read-only:
consultar_despacho,explicar_despacho("¿por qué cargaste a mediodía?"),simular("¿y si el CMg colapsa en la punta?") ycomparar_modos— nada se ejecuta ni persiste. - Se corrige intradía: detección de desvío de generación + reoptimización desde el estado real de la batería, sin re-versionar la política.
El dominio es puro y stdlib-only (Clean Architecture con frontera verificada por import-linter): PyTorch, cvxpy y DRL viven en adaptadores, nunca en las firmas del núcleo.
Demo en 60 segundos
uv run uvicorn acopia.interfaces.rest.app:app # → http://127.0.0.1:8000/demo
python -m acopia.interfaces.mcp.servidor # servidor MCP (stdio) con el mismo día sembrado
¿Sin Python a mano? El mismo dashboard vive como snapshot estático en el Observatorio.
GET /demo sirve el dashboard del día típico chileno (ADR-011): el plan de despacho sobre la duck curve — CMg con anotaciones, PV y acciones de la batería, SoC — con el motivo de cada decisión en el tooltip, y el pipeline de datos que alimenta al motor. HTML autocontenido: sin CDN, sin framework de frontend, legible sin JavaScript, modo claro/oscuro. Es el mismo día que interroga la demo MCP.

Estado
Fases 0–4 cerradas — el alcance de portafolio del SAD está completo (sign-offs en docs/AUDIT.md):
- F0 — Cimientos: capas Clean Architecture, value objects enteros,
ModeloBateriapuro, property-tests (determinismo y factibilidad). - F1 — Despacho determinista: optimizador predict-then-optimize (cvxpy + HIGHS) con plan factible, ingreso auditable y API REST.
- F2 — Forecasting + escenarios: tres forecasters intercambiables, snapshot as-seen del forecast (huella SHA-256), pipeline de ingesta de datos chilenos reales.
- F3 — Robustez + backtest: optimizador estocástico de dos etapas, backtest de política contra el día real (esperado vs realizado vs foresight), reoptimización intradía.
- F4 — SSCC + MCP + DRL: co-optimización arbitraje + reserva de frecuencia (ADR-010), servidor MCP read-only, modo DRL medido contra el baseline (ADR-005).
La Fase 5 (potencia de suficiencia, multi-planta, nube) se reserva "solo con tracción" — no se construye a futuro sin señal real de demanda.
Estructura
src/acopia/
├── domain/ # núcleo puro (stdlib-only): value objects, entidades, servicios, puertos
├── application/ # casos de uso: planificar, backtest, reoptimizar, comparar modos
├── infrastructure/ # adaptadores: forecasters, solver LP, DRL, ingesta, repositorios
└── interfaces/ # REST (FastAPI), MCP (FastMCP), CLI (acopia-datos), dashboard demo
tests/ # pytest + hypothesis (204 tests)
Desarrollo
Requiere Python 3.12+ y uv.
uv venv
uv pip install -e ".[dev]"
uv run ruff check . # lint
uv run mypy # tipado estricto (mypy --strict)
uv run lint-imports # fronteras de arquitectura (import-linter)
uv run pytest # tests
uv run pip-audit # vulnerabilidades conocidas en dependencias
Extras opcionales: .[forecasting] (torch CPU, LSTM), .[ingesta] (openpyxl, XLSX del
Coordinador), .[mcp] (FastMCP, servidor MCP), .[drl] (stable-baselines3 + gymnasium).
Base de datos (TimescaleDB) para la fase de persistencia real:
docker compose up -d db
Datos reales (Chile)
El motor consume una serie horaria timestamp,generacion_w,cmg_mills_por_mwh
(la "planta modelo"), que se arma de dos fuentes:
- CMg por barra — Coordinador Eléctrico. Vía práctica: descargar el XLS
de Costo Marginal Real
filtrando una barra y un rango de fechas.
(La API existe —
costo-marginal-online/v4/findByDate, verMEMORY.md— pero no filtra por barra en el servidor y está rate-limited: inviable para un año de una barra.) - Generación PV — Explorador Solar (solar.minenergia.cl):
exportar la serie horaria de generación de la ubicación de la planta →
gen.csv.
Como el Explorador entrega un "año típico" (2004–2016) y el CMg es de otro año, no comparten calendario: se alinean por posición (hora a hora), con el timestamp del CMg. Los lectores toleran el formato real del Coordinador (XLSX ancho, celdas combinadas, coma decimal chilena):
acopia-datos alinear --por-posicion \
--cmg cmg.xlsx --col-ts-cmg Fecha --col-hora-cmg Hora --col-cmg "S.GREGORIO" --escala-cmg 1000 \
--generacion gen.csv --col-gen pv --escala-gen 1000 \
--salida planta.csv
Con la planta modelo armada, los backtests que respaldan la tabla de resultados:
acopia-datos backtest --planta datos/planta.csv --folds 7 \
--modelos naive,sarimax,lstm --ventana-entrenamiento 720 # error de forecast por modelo
acopia-datos backtest-politica --planta datos/planta.csv # ingreso esperado vs realizado vs foresight
acopia-datos comparar-modos --planta datos/planta.csv # ADR-005: DRL (PPO) vs baseline LP
Ingeniería a la vista
El proyecto se rige por un método explícito (SDD + documentación viva): la spec cambia antes que el código, toda decisión tiene su ADR, todo trade-off aceptado tiene su entrada numerada de deuda, y ninguna fase cierra sin auditoría.
- docs/AUDIT.md — sign-offs por fase y el registro de deuda
AUD-NNN(viva y pagada). - docs/CASES.md — los casos reales del dominio que calibraron cada heurística.
- docs/TROUBLESHOOTING.md — incidentes reales y cómo se resolvieron.
Install Acopia in Claude Desktop, Claude Code & Cursor
unyly install acopiaInstalls into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.
First time? Get the CLI: curl -fsSL https://unyly.org/install | sh
Or configure manually
Run in your terminal:
claude mcp add acopia -- uvx --from git+https://github.com/faborubio/acopia acopiaFAQ
Is Acopia MCP free?
Yes, Acopia MCP is free — one-click install via Unyly at no cost.
Does Acopia need an API key?
No, Acopia runs without API keys or environment variables.
Is Acopia hosted or self-hosted?
A hosted option is available: Unyly runs the server in the cloud, no local setup required.
How do I install Acopia in Claude Desktop, Claude Code or Cursor?
Open Acopia on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectCompare Acopia with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
