comparador-luz-gas
comparador-luz-gas
El comparador de ofertas de energía de la CNMC es la única comparativa oficial de tarifas de luz y gas en España, pero solo se puede usar rellenando su formulario web. Por debajo hay una API pública sin autenticación que, para una consulta doméstica normal, pide 83 parámetros.
Esto es un proxy con una API clara por delante: tres datos entran, JSON ordenado por precio sale. Pensado para que lo llame un LLM o un script, sin pasar por la web.
from comparador_luz_gas import Consulta, comparar
r = comparar(Consulta(codigo_postal="28013", consumo_anual_luz=2600, potencia=3.45))
r.ofertas[0] # Oferta(comercializadora='CIDE HCENERGÍA S.A.U', importe_primer_anio=590.19, ...)comparador-luz-gas --cp 28013 --consumo 2600 --textoAdemás hace dos cosas que la web no: lee el QR de la factura para no tener que teclear nada, y dice en cada respuesta qué comercializadoras grandes faltan, que es la trampa principal de este comparador.
Instalación
Está en PyPI:
pip install comparador-luz-gas # solo la consulta
pip install "comparador-luz-gas[facturas]" # + leer el QR de un PDF o imagen
sudo apt install libzbar0 poppler-utils # lo que necesita ese extraCon uv, uv add comparador-luz-gas; o sin instalar nada,
uvx comparador-luz-gas --cp 28013 --consumo 2600 --texto.
Related MCP server: PVPC MCP Server
La API
Consulta — lo que preguntas
campo | por defecto | qué es |
| — | obligatorio, p. ej. |
|
| kWh/año |
|
| kWh/año |
|
| kW contratados |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
comparar(consulta, timeout=90) devuelve un Resultado. Es una sola petición HTTP:
tarda entre 3 y 8 segundos, que es lo que tarda la CNMC.
Resultado — lo que devuelve
r.ofertas viene ordenado de más barato a más caro. r.to_dict() es lo que imprime
el CLI en JSON:
{
"modo": "anual",
"importes": "importe_primer_anio / importe_segundo_anio son el coste estimado de 12 meses.",
"consulta": { "codigo_postal": "28013", "consumo_anual_luz": 2600.0, "reparto_franjas": [745, 639, 1216] },
"cobertura": {
"aviso": "El comparador de la CNMC solo incluye ofertas que...",
"comercializadoras_en_resultado": 28,
"comercializadoras": ["ADX RENOVABLES, S.L.", "..."],
"grandes_ausentes": ["ENDESA", "IBERDROLA", "TOTALENERGIES", "..."]
},
"ofertas": [
{
"comercializadora": "CIDE HCENERGÍA S.A.U",
"oferta": "Plan Estrella Dúo",
"importe_primer_anio": 590.19, // con el descuento de bienvenida
"importe_segundo_anio": 640.9, // ya sin él
"permanencia": false,
"servicios_adicionales": false,
"verde": false,
"validez": "Oferta válida solo para nuevos clientes",
"precio_unico": true,
"id_oferta": 7137
}
],
"alternativa_por_separado": null // con suministro="ambas": luz + gas sueltos
}Los importes no llevan desglose de impuestos: la CNMC no lo publica en esta respuesta. Antes de cambiarte, confirma con la comercializadora si son con IVA.
CLI
comparador-luz-gas --cp 28013 --consumo 2600 # JSON
comparador-luz-gas --cp 28013 --consumo 2600 --texto --top 5 # tabla legible
comparador-luz-gas --cp 28013 --consumo 2600 --sin-permanencia
comparador-luz-gas --cp 28013 --consumo 2600 --consumo-gas 6000 --suministro ambas
comparador-luz-gas --factura factura.pdf --texto # datos del QR
comparador-luz-gas --factura factura.pdf --mensual --texto # coste de esa factura
comparador-luz-gas --qr 'https://comparador.cnmc.gob.es/comparador/QRE?cp=...'
comparador-luz-gas --factura factura.pdf --solo-datos # lee el QR y nada másServidor MCP
comparador-luz-gas mcp sirve el comparador por stdio a Claude Desktop y cualquier
otro cliente MCP, sin dependencias extra. Herramientas:
comparar_ofertas: lo mismo que el CLI en JSON (ofertas + análisis a largo plazo). Bastaqr, ocp+consumo;max_ofertas(20 por defecto) recorta la lista.leer_factura_qr: los datos del QR de una factura, sin consultar la CNMC.leer_factura: lee el QR de un PDF o imagen del disco (necesita el extrafacturas).
{
"mcpServers": {
"comparador-luz-gas": { "command": "uvx", "args": ["comparador-luz-gas", "mcp"] }
}
}Para leer_factura: "args": ["--from", "comparador-luz-gas[facturas]", "comparador-luz-gas", "mcp"].
También hay Dockerfile (docker run -i --rm comparador-luz-gas). Está en el
registro oficial de MCP como
io.github.nuncaeslupus/comparador-luz-gas.
Leer la factura: el QR, no el texto
Desde la Resolución de la CNMC de 24/06/2021 (modificada por BOE-A-2022-16989) toda factura de electricidad lleva un QR que apunta al comparador con el suministro ya desglosado:
https://comparador.cnmc.gob.es/comparador/QRE?cp=28013&pP1=4.6&pP2=4.6
&caP1=740&caP2=660&caP3=757&cups=ES0000000000000000XX&imp=72.50&prE1=0.2288...Código postal, potencias, consumo anual por franja, consumo y fechas del periodo facturado, precios e importe: justo lo que pide el comparador. Como el formato lo fija la CNMC y no la comercializadora, sirve para cualquier compañía — no hace falta un parser por marca.
from comparador_luz_gas import comparar, desde_fichero, desde_qr
f = desde_fichero("factura.pdf") # PDF o imagen: localiza y decodifica el QR (~5 s)
f = desde_qr(texto_del_qr) # si la app ya lo escaneó: solo urllib.parse
r = comparar(f.consulta())desde_qr() no tiene dependencias, así que una app que escanee el QR con la cámara
puede mandar la cadena y saltarse el extra de imagen por completo.
Si la factura está escaneada, depende de a cuánto: el QR mide unos 3 px por módulo a 300 dpi, justo en el límite de los decodificadores. 400 dpi aguanta JPEG, giro y desenfoque; 300 dpi va bien salvo desenfoque; 200 dpi solo si está limpio; 150 dpi es imposible. Los números y el porqué, en docs/qr-escaneado.md.
Dos modos: anual y factura
Por defecto la CNMC estima el coste de doce meses a partir del consumo anual del
QR. Con --mensual (f.consulta(mensual=True)) calcula lo que habría costado ese
periodo de facturación concreto, con sus fechas y su consumo reales, así que sale
en la misma escala que el importe impreso en la factura:
Periodo 2026-07-14→2026-08-16: 146 kWh, pagaste 72.50 €.
periodo sin dto. comercializadora oferta
40.03 51.03 CIDE HCENERGÍA S.A.U Plan Estrella Dúo
47.20 47.20 TRACTAMENT I SELECCIÓ DE RESIDUS, S.A. TARIFA FIJA CLÁSICA - 2.0TDDos avisos al leerlo:
El importe de la factura incluye cosas que el comparador no cuenta: servicios adicionales, alquiler de equipos, bono social. El QR los desglosa (
impSA,finBS); réstalos antes de comparar.La segunda columna es el mismo periodo sin descuento de bienvenida, no un segundo año. En el PVPC sale 0 porque no hay promoción que quitar.
En JSON, "modo" e "importes" dicen cuál de los dos es, para que un LLM no lea un
mes como si fuera un año.
Valoración a largo plazo, sin LLM
interpretar(resultado, anios=3) (clave "analisis" del JSON de la CLI) es aritmética
sobre lo que ya devuelve la CNMC, pensada para que un LLM o una persona no lea mal el
ranking. El comparador ordena por importe_primer_anio y ese puesto lo gana casi
siempre una oferta de bienvenida, que solo se cobra una vez:
from comparador_luz_gas import comparar, Consulta, interpretar
a = interpretar(comparar(Consulta(codigo_postal="28013", consumo_anual_luz=2200)), anios=3)
print(a["resumen"])
for aviso in a["avisos"]:
print("-", aviso)Devuelve el coste a N años de cada oferta (primer_anio + (N-1) × siguientes) y, sobre
todo, separa las dos decisiones que el ranking mezcla:
opciones.todas_las_horas_igualvsopciones.con_discriminacion_horaria, con la diferencia ya calculada enpregunta— es lo que hay que preguntarle al usuario antes de recomendarle nada, porque una oferta por tramos solo compensa si va a mover consumo.Dentro de cada una,
sin_restriccion_de_nuevo_cliente: la mejor que también puede contratar quien ya es cliente de esa comercializadora.
Más avisos derivados de los datos: permanencia y su penalización estimada, servicios adicionales, y el PVPC frente a la mejor fija.
Un detalle que conviene no perder de vista: las ofertas por tramos se valoran con tu
reparto punta/llano/valle actual. Para saber si te compensaría mover consumo, repite la
consulta con el reparto que esperas tener (--franjas). En un caso real, mover 150 kWh al
año de punta a valle movía la mejor horaria de 660 € a 639 €: 8 € por debajo de la mejor
plana, después de reorganizar un año entero de lavadoras.
Lo que no hace, porque los datos no dan para ello: decir en qué mes del año conviene cambiar. El catálogo no lleva fechas de alta ni de caducidad de las ofertas, solo el tipo de cliente que admiten, y la CNMC no publica el histórico del comparador — hay una solicitud abierta en datos.gob.es desde septiembre de 2025, respondida con que esos datos no están en el catálogo de datos abiertos. El momento lo marca tu permanencia, no el mercado.
Consumo: la ventana importa
El QR trae los 12 meses rodantes, que arrastran lo que consumías hace un año. Con
varias facturas a mano, anualizar() extrapola una ventana más corta y más parecida a hoy:
from comparador_luz_gas import anualizar, desde_fichero
ultimas = [desde_fichero(p) for p in sorted(Path("facturas").glob("*.pdf"))[-6:]]
total, franjas = anualizar(ultimas)Cambia el importe estimado, no tanto el ranking: la CNMC solo usa tus kWh y les aplica su propio catálogo, así que lo que te haya subido tu comercializadora no entra en el cálculo.
Método y limitaciones
Todo lo que devuelve este proyecto sale de la API oficial de la CNMC (comparador.cnmc.gob.es): no hay estimación de precios propia, solo cuentas sobre lo que ella responde. Es, con diferencia, la fuente más transparente que hay — pero eso no la hace completa.
No es un censo del mercado
La CNMC solo publica ofertas que las comercializadoras le remiten y que sus técnicos validan una a una. Comprobado contra la API en vivo el 2026-09-23, sobre 20 códigos postales:
Presentes: Naturgy, Repsol, Galp, Octopus, Fenie, Nexus, Lumisa y ~45 más.
Iberdrola Clientes: una sola oferta, solo gas (
Plan Gas Hogar RL2 online).Endesa Energía: ninguna oferta, ni luz ni gas.
TotalEnergies, Plenitude, Holaluz, EDP: ninguna.
Endesa e Iberdrola aparecen solo como Comercializadora de referencia, que es el
PVPC/TUR regulado de sus filiales obligadas por ley (Energía XXI, Curenergía).
Por eso cada respuesta lleva el bloque cobertura. La respuesta correcta a "¿cuál es
la mejor tarifa?" es la mejor entre las verificadas por la CNMC, no la mejor que
existe.
Otras limitaciones
Sin desglose de impuestos: los importes no llevan IVA desglosado; confírmalo con la comercializadora antes de cambiarte.
Sin histórico: el catálogo no lleva fechas de alta ni caducidad de las ofertas, así que no se puede decir en qué mes conviene cambiar (más detalle en Valoración a largo plazo).
Las ofertas por tramos se valoran con TU reparto punta/llano/valle, sacado del QR o de
anualizar(). En Península, Illes Balears y Canarias, ese reparto asume los tramos 2.0TD que fija la Circular 3/2020, aplicables desde el 1/06/2021 (punta 10-14h y 18-22h, llano el resto del día laborable, valle 0-8h y festivos). Ceuta y Melilla usan horarios distintos. Si vienes de una tarifa de discriminación horaria anterior (p. ej. una "tarifa 8 horas" donde el valle lo elegías tú o lo fijaba la comercializadora, no el tramo 0-8h regulado), el reparto histórico de esas facturas no representa cómo caería ese consumo en los tramos actuales — la comparación de ofertas horarias hereda esa incertidumbre. Usa solo facturas posteriores al 1/06/2021 si puedes.El comparador aplica su catálogo de hoy a tus kWh: una subida de precio de tu comercializadora actual no distorsiona la estimación, pero un cambio en tu propio consumo sí.
Desarrollo
make sync && make lint && make test
make test-live # consulta la API real
make test-facturas # lee el QR de los PDFs de data/facturas/, si los hayLas capturas HAR (data/har/) y las facturas (data/facturas/) están en
.gitignore: llevan CUPS, dirección y consumos reales. Los tests versionados usan un
QR inventado.
Hecho con claude-arsenal
Este repositorio se desarrolla con claude-arsenal, un marketplace de plugins para Claude Code orientado a trabajar con especificaciones: primero la especificación, después los tests que fallan, y criterios de aceptación con números. Las skills incluidas están en claude-arsenal/.
Available Tools
3 toolscomparar_ofertasARead-only
Consulta el comparador oficial de la CNMC y devuelve las ofertas de luz y/o gas ordenadas por precio, con un análisis a varios años (rotar de oferta, permanencias, precio fijo vs. por tramos). Basta el QR de una factura, o código postal + consumo anual.
| Name | Required | Description | Default |
|---|---|---|---|
| cp | No | código postal, p. ej. 28013 | |
| qr | No | contenido del QR de la factura de luz, ya decodificado (la URL de comparador.cnmc.gob.es que lleva impresa) | |
| anios | No | horizonte del análisis a largo plazo (por defecto 3) | |
| consumo | No | consumo anual de luz en kWh | |
| empresa | No | suministro que no es vivienda | |
| franjas | No | consumo anual punta, llano y valle en kWh; por defecto se reparte con el perfil 2.0TD | |
| mensual | No | con qr, coste de ese periodo de facturación en vez del anual | |
| potencia | No | potencia contratada en kW (por defecto 3.45) | |
| suministro | No | ||
| consumo_gas | No | consumo anual de gas en kWh | |
| max_ofertas | No | ofertas a devolver, las más baratas (por defecto 20) | |
| sin_permanencia | No | excluir ofertas con permanencia |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover readOnly and openWorld, so the bar is lower; the description still adds real value by describing what comes back (offers sorted by price, multi-year analysis covering offer rotation, permanencias, fixed vs. time-band pricing). It does not address errors, auth, or latency, which keeps it out of the top band.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences that front-load the purpose and then the minimum-input rule; no filler. The parenthetical feature list is dense but every item earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter tool with no required fields and no output schema, the description usefully explains the return content and the two minimal input paths. Remaining gaps (gas-only behavior, defaults for potencia/consumo, error handling) are minor against the 92% schema coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 92%, so the schema already documents nearly every parameter. The description reinforces the QR-vs-cp+consumo choice and links the multi-year view to 'anios', but adds no syntax or format detail beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specifies the verb and resource precisely ('Consulta el comparador oficial de la CNMC y devuelve las ofertas de luz y/o gas ordenadas por precio') and names the analysis scope. It does not explicitly contrast with the invoice-reading siblings, but the purpose is unmistakably different.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the two viable invocation modes ('Basta el QR de una factura, o código postal + consumo anual'), which tells the agent the minimum inputs needed given that no parameter is required. It stops short of naming alternatives or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
leer_facturaARead-only
Lee el QR de una factura de luz en PDF o imagen del disco local y devuelve sus datos. Necesita el extra facturas (y poppler-utils para PDFs).
| Name | Required | Description | Default |
|---|---|---|---|
| ruta | Yes | ruta al PDF o imagen de la factura |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false. The description adds useful operational context beyond that: it operates on local disk files and requires the 'facturas' extra plus poppler-utils for PDF parsing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no wasted words. The core action is front-loaded, followed by the dependency requirement.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read tool, the definition covers the input and key dependencies, and annotations cover the safety profile. It is slightly incomplete because it does not describe the returned invoice data in any detail and does not disambiguate from the sibling tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the single 'ruta' parameter is already documented as the path to the PDF or image. The description adds only the minor clarification that the file is on local disk, which does not materially extend the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: reads the QR from an electricity invoice PDF or image on the local disk and returns its data. The scope is clear, but it does not distinguish itself from sibling leer_factura_qr, which appears to cover a very similar capability.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a dependency prerequisite (needs the extra 'facturas' and poppler-utils for PDFs) but no when-to-use guidance or criteria for choosing this tool over leer_factura_qr or comparar_ofertas.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
leer_factura_qrARead-only
Interpreta el QR de una factura de luz (ya decodificado): código postal, potencia, consumo por tramos del periodo y anual, fechas e importe. No consulta la CNMC.
| Name | Required | Description | Default |
|---|---|---|---|
| qr | Yes | contenido del QR de la factura de luz, ya decodificado (la URL de comparador.cnmc.gob.es que lleva impresa) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds that it operates on already-decoded content and does not contact the CNMC (consistent with openWorldHint=false), which is useful context. It still doesn't say what happens on a malformed QR or what the output shape is, so it goes only slightly beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence front-loads the core action and field list, then closes with a scoping exclusion. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only single-param tool with a fully documented schema and no output schema, the description covers purpose and a scoping exclusion. However, with no output schema, the return format is undocumented, and the relation to the sibling leer_factura — the most likely source of mis-selection — is not addressed. Adequate but with a clear gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter 'qr' is fully described in the schema (decoded QR content, the comparador.cnmc.gob.es URL). The description adds nothing beyond what the schema already conveys about the parameter. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (interpreta el QR de una factura de luz) and enumerates the exact fields it extracts (código postal, potencia, consumo, fechas, importe). The negative clarification 'No consulta la CNMC' helps distinguish it, but it doesn't explicitly route against sibling leer_factura (a near-synonym that likely parses the same bill differently), so the sibling differentiation is only partial.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage via 'ya decodificado' (input must already be a decoded QR string) and 'No consulta la CNMC', but never explicitly states when to use this vs leer_factura or comparar_ofertas. The agent must infer the QR-decoding precondition rather than being told it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
comparar_ofertas - First observed
leer_factura - First observed
leer_factura_qr
TDQS
Scored across 3 tools
comparar_ofertas is clearly the query/comparison tool, but leer_factura and leer_factura_qr are two adjacent invoice-reading steps that an agent could confuse. The descriptions clarify the distinction (file on disk vs. already-decoded QR), preventing real overlap but leaving some boundary ambiguity.
All three tools use consistent Spanish snake_case verb_noun naming (comparar_ofertas, leer_factura, leer_factura_qr). The leer_factura / leer_factura_qr prefix pairing is a predictable, readable convention.
Three tools is slightly lean but appropriate for a narrow comparison/reading domain; each tool earns its place covering extract, read, and compare. It is on the lower edge but not problematically thin.
The surface covers a full workflow: read a PDF/image invoice, parse its QR, and compare offers. A minor gap is that leer_factura/leer_factura_qr mention only electricity invoices while comparar_ofertas handles gas too, but agents can still work around this.
Maintenance
Related MCP Connectors
Real-time electricity price signals for AI agents. Spot prices, cheapest hours, and contract recommendations. 31 countries across Europe and Oceania. No authentication required.
Find AI model pricing, estimate token costs and compare offers. No API key required.
Fiscalidad, derecho laboral y finanzas de España: IRPF, autónomos (cuota RETA, modelos 130 y 303, gastos deducibles), nóminas de bruto a neto, despidos (indemnización, finiquito, paro), herencias y donaciones por comunidad autónoma, jubilación y pensiones, hipotecas y compraventa de vivienda. Incluye consultas de escenario que combinan varios cálculos a la vez, como haría una gestoría. Gratuito, sin registro ni API key.
Live US retail electricity plans, utility price-to-compare rates, ZIP-to-utility lookup. Read-only.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables natural language conversations with Spain's electrical grid data through Claude, providing real-time access to electricity demand, generation, prices, and emissions data from Red Eléctrica de España (REE).1811MIT
- AlicenseAqualityCmaintenanceFetches Spanish electricity prices (PVPC) from Red Eléctrica de España's API, providing hourly tariff data for different geographical areas and customizable date ranges.154 npmMIT
- FlicenseNot gradedqualityDmaintenanceEnables AI-powered analysis and prediction of household energy consumption through machine learning models, providing historical consumption breakdowns, price queries from Spanish electricity markets, and personalized energy optimization recommendations.-
- AlicenseAqualityCmaintenanceAI agent for Italian energy tariff comparison. Analyzes electricity and gas bills, compares 44+ offers from 13 providers, estimates savings with full ARERA regulated cost breakdown7MIT