Skip to content
Conduit

mcp server

datos-es-mcp

Servidor MCP (Model Context Protocol) que permite a los asistentes de IA (Claude, ChatGPT, Gemini, etc.) consultar, explorar y analizar datos del ecosistema de datos abiertos de España directamente de

hucara/datos-es-mcpcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 22, 2026

datos-es MCP Server

Licencia: MIT

Servidor MCP (Model Context Protocol) que permite a los asistentes de IA (Claude, ChatGPT, Gemini, etc.) consultar, explorar y analizar datos del ecosistema de datos abiertos de España directamente desde la conversación.

Model Context Protocol (MCP) server for interacting with Spanish open data (datos.gob.es, INE, Banco de España, AEMET, BOE, and more) via LLM chatbots

En lugar de navegar manualmente por portales gubernamentales, puedes simplemente preguntar cosas como «¿Cuál es la tasa de paro según el INE?» o «¿Cuánto gasta España en sanidad respecto a la media europea?» y obtener respuestas inmediatas respaldadas por fuentes oficiales.

Incluye una herramienta especializada de verificación de afirmaciones políticas (verify_claim) que enruta cualquier declaración económica o política a las fuentes de datos autorizadas y genera un plan de verificación paso a paso.

Este es un proyecto inspirado por el trabajo que puedes ver en:

¡Dales un vistazo y apóyales!


🌐 Conecta tu asistente de IA

Si tienes el servidor en ejecución, usa el endpoint /mcp. A continuación encontrarás la configuración para los clientes más habituales.

¡ATENCIÓN! Algunas de estas apis / datos sólo están accesibles desde España, así que si Claude hace la query es posible que no sea capaz de acceder a ello, sin embargo, siempre puedes montarte tú un cliente que haga estas llamadas.

Claude Code | Claude Desktop | Cursor | VS Code | Windsurf | OpenCode

Claude Code

claude mcp add --transport http datos-es http://127.0.0.1:8000/mcp

Si el comando falla (p.ej. por incompatibilidad con la versión de Node.js), puedes añadirlo manualmente a ~/.claude.json:

{
  "mcpServers": {
    "datos-es": {
      "type": "http",
      "url": "http://127.0.0.1:8000/mcp"
    }
  }
}

Extensión VS Code de Claude Code: añade lo siguiente a la configuración de usuario de VS Code (Cmd+Shift+P → Open User Settings (JSON)):

{
  "claude.mcpServers": {
    "datos-es": {
      "type": "http",
      "url": "http://127.0.0.1:8000/mcp"
    }
  }
}

Claude Desktop

Añade lo siguiente al fichero de configuración de Claude Desktop:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "datos-es": {
      "command": "uv",
      "args": [
        "run",
        "--directory",
        "/ruta/a/datos-es-mcp",
        "python",
        "main.py"
      ],
      "env": {
        "AEMET_API_KEY": "tu_clave_aqui"
      }
    }
  }
}

O si tienes el servidor ya levantado como HTTP:

{
  "mcpServers": {
    "datos-es": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "http://127.0.0.1:8000/mcp"
      ]
    }
  }
}

Cursor

  1. Abre la configuración de Cursor
  2. Busca «MCP» o «Model Context Protocol»
  3. Añade el servidor con la siguiente configuración:
{
  "mcpServers": {
    "datos-es": {
      "url": "http://127.0.0.1:8000/mcp",
      "transport": "http"
    }
  }
}

VS Code

Añade lo siguiente al fichero mcp.json de VS Code:

  • macOS: ~/Library/Application Support/Code/User/mcp.json
  • Windows: %APPDATA%\Code\User\mcp.json
  • Linux: ~/.config/Code/User/mcp.json

Puedes abrirlo con el comando MCP: Open User Configuration desde la paleta de comandos.

{
  "servers": {
    "datos-es": {
      "url": "http://127.0.0.1:8000/mcp",
      "type": "http"
    }
  }
}

Windsurf

Añade lo siguiente a ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "datos-es": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://127.0.0.1:8000/mcp"
      ]
    }
  }
}

OpenCode

Añade al fichero opencode.json (p.ej. ~/.config/opencode/opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "datos-es": {
      "type": "remote",
      "url": "http://127.0.0.1:8000/mcp",
      "enabled": true
    }
  }
}

🖥️ Ejecución local

Requisitos previos

  • Python 3.13+
  • uv (gestor de paquetes recomendado)
  • Clave API de AEMET (gratuita) para las herramientas meteorológicas — solicítala aquí

🐳 Con Docker (recomendado)

git clone <url-del-repo>
cd datos-es-mcp

# Copia y configura las variables de entorno
cp .env.example .env
# Edita .env y añade tu AEMET_API_KEY

# Inicia el servidor
docker compose up -d

# Comprueba que funciona
curl http://localhost:8000/health

# Detiene el servidor
docker compose down

⚙️ Instalación manual

  1. Instala las dependencias

    uv sync
    
  2. Prepara el fichero de entorno

    cp .env.example .env
    

    Edita .env y configura al menos:

    AEMET_API_KEY=tu_clave_de_aemet
    MCP_HOST=127.0.0.1
    MCP_PORT=8000
    MCP_ENV=local
    LOG_LEVEL=INFO
    

    Carga las variables:

    set -a && source .env && set +a
    
  3. Arranca el servidor

    uv run python main.py
    

El servidor arranca en http://localhost:8000. El endpoint MCP está en /mcp.

Comprobación de salud: curl http://localhost:8000/health


🚚 Transporte

El servidor está construido con el SDK oficial de Python para MCP y usa exclusivamente el transporte Streamable HTTP.

STDIO y SSE no están soportados.

Endpoints disponibles:

  • POST /mcp — mensajes JSON-RPC (cliente → servidor)
  • GET /health — sonda de salud JSON ({"status":"ok","version":"...","uptime_since":"..."})

🛠️ Herramientas disponibles (25)

⚡ Orden de prioridad al elegir herramienta

Siempre usa la herramienta más específica disponible antes de recurrir a las genéricas:

  1. Herramienta dedicada (get_employment_stats, query_ine_data, get_eurostat_data, get_bde_series, get_social_security_stats…) — devuelve datos directamente o referencias muy precisas.
  2. search_datasets — solo si no existe herramienta dedicada para la institución o tema.
  3. verify_claim — solo para verificar afirmaciones concretas con autoría y fecha; no como sustituto de las herramientas de datos.

Ejemplo correcto: «¿Cuál es la tasa de paro?» → query_ine_data(table_id="14506") Ejemplo incorrecto: «¿Cuál es la tasa de paro?» → verify_claim(...) → get_employment_stats(...) → query_ine_data(...) (tres saltos innecesarios)

Catálogo nacional — datos.gob.es

HerramientaDescripciónParámetros clave
search_datasetsÚltimo recurso. Busca en el catálogo de datos.gob.es por título de dataset. Los datasets están mal etiquetados y los resultados son ruidosos — devuelve referencias a ficheros, no valores. Úsalo solo para instituciones sin herramienta dedicada (CNMV, Tribunal de Cuentas, transferencias de Hacienda) o con publisher= para listar datasets de un organismo concreto.query, publisher (código organismo), page
get_dataset_infoMetadatos completos de un dataset: organismo, licencia, cobertura geográfica, frecuencia de actualización y lista de distribuciones.dataset_id
list_dataset_resourcesLista todos los ficheros descargables de un dataset con URL, formato, tamaño y fecha. Con include_data=True descarga y previsualiza CSV/JSON directamente (hasta max_file_size_mb, por defecto 10 MB).dataset_id, include_data, max_file_size_mb

Flujo si no existe herramienta dedicada: search_datasets(publisher='<código>') → list_dataset_resources(include_data=True)

INE — Instituto Nacional de Estadística

HerramientaDescripciónParámetros clave
get_ine_operationsLista las operaciones estadísticas del INE (IPC, EPA, PIB, Padrón, nacimientos…). Resultados servidos desde caché de 24 h tras la primera llamada.search, page
query_ine_dataObtiene series temporales de cualquier tabla o serie del INE. Tres modos: listar tablas de una operación, descargar tabla completa, o consultar serie específica.operation_code, table_id, series_code, last_n_periods, date_range

Flujo recomendado: get_ine_operations → query_ine_data(operation_code=...) → query_ine_data(table_id=...)

Banco de España

HerramientaDescripciónParámetros clave
get_bde_seriesSeries financieras del Banco de España: tipos BCE, EURIBOR, tipos de cambio, crédito bancario, agregados monetarios y balanza de pagos.series_codes, time_range (30M/60M/MAX/año), latest_only

AEMET — Meteorología

HerramientaDescripciónParámetros clave
get_weather_forecastPredicción de varios días para cualquier municipio (por código INE de 5 dígitos o por nombre). Temperatura, precipitación, viento y estado del cielo.municipality_code, detail (daily/hourly)
get_weather_observationsObservaciones actuales de las estaciones AEMET: temperatura, humedad, viento, presión y precipitación.station_id (omitir = todas)

BOE — Boletín Oficial del Estado y Legislación

HerramientaDescripciónParámetros clave
get_boe_summaryResumen diario del BOE o BORME: secciones, departamentos e identificadores de los documentos publicados.date (AAAAMMDD), gazette (BOE/BORME)
search_legislationBusca en la legislación consolidada por palabras clave o rango de fechas. Devuelve la norma, departamento y estado de consolidación.query, from_date, to_date, limit

Contratación pública

HerramientaDescripciónParámetros clave
search_public_contractsLicitaciones y contratos en PLACE (plataforma nacional). Modo datasets para históricos en bulk; modo feed para avisos recientes.query, source (datasets/feed)
search_regional_contractsContratación en Madrid, Cataluña y Valencia. Consulta primero el portal regional nativo (CKAN) y recurre a datos.gob.es si es necesario.query, region (madrid/cataluña/valencia/all), page

Empleo

HerramientaDescripciónParámetros clave
get_employment_statsEstadísticas de empleo del SEPE: paro registrado, contratos y demandantes, con desglose por provincia, sector, edad y sexo.stat_type (registered_unemployment/contracts/job_seekers), period, province

Transporte

HerramientaDescripciónParámetros clave
get_renfe_dataDatos abiertos de Renfe vía data.renfe.com (CKAN): horarios GTFS, estaciones y posiciones en tiempo real.data_type (schedules/stations/realtime), service_type (AVE/MD/cercanias)
get_traffic_statsEstadísticas de tráfico de la DGT: siniestralidad vial, víctimas, parque de vehículos, matriculaciones (EV vs ICE), permisos de conducción y controles de alcoholemia.stat_type (accidentes/victimas/parque_vehiculos/matriculaciones/carnet/alcoholemia/velocidad), period

Energía y mercados

HerramientaDescripciónParámetros clave
get_energy_dataDatos de Red Eléctrica (REData): mix de generación, capacidad instalada, balance energético, demanda y precios del mercado mayorista.data_type (generation_mix/installed_capacity/balance/demand/market_prices), start_date, end_date, time_trunc
get_cnmc_dataDatos regulados de la CNMC vía data.cnmc.es (CKAN): electricidad, gas, telecomunicaciones, correos y mercados de competencia.sector (electricity/gas/telecom/postal/audiovisual/competition), indicator, period

Hacienda y fiscalidad

HerramientaDescripciónParámetros clave
get_aeat_statsEstadísticas fiscales de la Agencia Tributaria: anuario estadístico (IRPF, IVA, Patrimonio, Sociedades) e informes de recaudación.stat_type (anuario_estadistico/recaudacion/irpf/iva/sociedades), query, page

Sanidad, educación y servicios públicos

HerramientaFuente principalDescripciónstat_type disponibles
get_health_statsMinisterio de Sanidad / SNSGasto sanitario, camas hospitalarias, profesionales sanitarios, listas de espera, mortalidad, vacunación, encuesta nacional de salud.gasto_sanitario, camas_hospitalarias, profesionales, listas_espera, mortalidad, enfermedades, salud_mental, vacunacion, encuesta_salud
get_education_statsMinisterio de Educación / MEFPAbandono escolar, matriculados, universitarios, profesorado, becas, gasto educativo, FP, resultados PISA.abandono_escolar, matriculados, universitarios, profesorado, becas, gasto_educativo, fp, pisa
get_housing_statsMinisterio de Vivienda + INEPrecios de vivienda (IPV), alquileres, hipotecas, visados de construcción, parque de viviendas, vivienda protegida, ejecuciones hipotecarias.precios_vivienda, alquileres, hipotecas, construccion, parque_viviendas, vivienda_protegida, ejecuciones_hipotecarias
get_social_security_statsINSS / Min. InclusiónPensiones, cotizantes, ratio sostenibilidad, prestaciones por desempleo, incapacidad temporal, accidentes laborales, afiliados extranjeros.pensiones, cotizantes, ratio_sostenibilidad, prestaciones_desempleo, incapacidad, accidentes_laborales, inmigracion
get_traffic_statsDGTSiniestralidad vial, víctimas, parque de vehículos, matriculaciones, permisos de conducción, alcoholemia, velocidad.accidentes, victimas, parque_vehiculos, matriculaciones, carnet, alcoholemia, velocidad
get_justice_statsMin. Justicia / CGPJCriminalidad, condenas, población penitenciaria, carga judicial, violencia de género, justicia de menores, corrupción.criminalidad, condenas, presos, juzgados, violencia_genero, menores, corrupcion

Todas las herramientas de esta sección aceptan además period (año o rango, p.ej. "2023", "2020-2023") y custom_query para búsquedas libres.

Comparativas europeas

HerramientaDescripciónParámetros clave
get_eurostat_dataDatos de Eurostat para comparar España con la UE-27: PIB, inflación HICP, desempleo, vivienda, renovables, deuda pública, salarios, desigualdad.topic, geo (por defecto ES,EU27_2020), since_year, until_year, dataset_code (para topic="custom")

Temas disponibles: gdp_growth, gdp_per_capita, inflation_hicp, inflation_annual, unemployment, employment_rate, house_prices, renewable_share, electricity_prices_households, electricity_prices_industry, government_debt, government_deficit, wages, poverty_inequality, fossil_fuel_imports

Verificación de afirmaciones

HerramientaDescripciónParámetros obligatorios
verify_claimClasifica una afirmación política o económica y devuelve un plan de verificación estructurado: qué herramientas llamar, con qué argumentos y en qué orden. No ejecuta las consultas directamente.claim_normalizado, fecha, afirmado_por, ambito_geografico, ambito_tematico, tipo_claim

Documentación detallada de verify_claim

El enrutamiento combina cuatro señales:

  • claim_normalizado: coincidencia de palabras clave sobre el texto
  • ambito_tematico: taxonomía temática (captura casos que los keywords no detectan)
  • entidad_mencionada + fuente_citada: sugerencias específicas por institución
  • ambito_geografico: añade portales regionales para afirmaciones sub-nacionales

Parámetros obligatorios:

ParámetroDescripción
claim_normalizadoLa afirmación en español normalizado. Los nombres y contexto deben ser explícitos (p.ej. «Santiago Abascal tiene 3 investigaciones» en vez de «Usted tiene 3 investigaciones»).
fechaSiempre requerida. Fecha en que se realizó la afirmación (AAAA, AAAA-MM o AAAA-MM-DD). Es el límite superior duro para todas las consultas: no se buscarán datos publicados después de esta fecha. No confundir con periodo_temporal.
afirmado_porQuién realizó la afirmación. Ejemplo: "Pedro Sánchez", "Partido Popular".
ambito_geograficoAlcance geográfico. Valores canónicos: 17 CCAA + "España" + "Europa" / "Unión Europea" + "Internacional".
ambito_tematicoCategoría temática. Acepta español e inglés: economía/economy, sanidad/health, educación/education, vivienda/housing, pensiones/pensions, trafico/traffic, criminalidad/crime, medio_ambiente/environment, empleo/employment, demografía/demographics, fiscalidad/taxation, banca/banking, empresas/business, justicia_y_corrupción/corruption, presupuestos/public_debt, contratacion_publica/procurement.
tipo_claimTipo estructural: estadistica_puntual, historico, ranking, tendencia, comparacion, proyeccion.

Parámetros secundarios:

ParámetroDescripción
claim_rawTexto verbatim original (con contexto, idioma original, interrupciones). Solo para trazabilidad.
entidad_mencionadaInstitución a la que se refiere la afirmación. Activa sugerencias específicas. Ejemplo: "INE", "Tribunal de Cuentas".
metricaLa métrica concreta afirmada. Ejemplo: "tasa de abandono escolar".
valor_afirmadoEl valor concreto afirmado. Aparece en el checklist. Ejemplo: "98%", "más baja de la historia".
periodo_temporalEl período al que se refiere la afirmación — distinto de fecha. Orienta las consultas pero nunca actúa como límite de datos. Ejemplo: "2022", "2018-2023", "actual".
fuente_citadaFuente mencionada por quien hace la afirmación. Ejemplo: "INE", "No citada".
idiomaCódigo ISO 639-1 del idioma del claim_raw (es, ca, gl, eu).
intervention_ordenPosición en la sesión (base 1). Solo para trazabilidad.
return_dataSi true, incluye una nota sobre la primera fuente recomendada. Por defecto false.

Estrategias por tipo de afirmación:

tipo_claimEstrategia aplicada
estadistica_puntualLocalizar el valor oficial exacto y comparar con valor_afirmado.
historicoBuscar el acto legislativo o administrativo en BOE/Diario de Sesiones.
rankingRecuperar la serie temporal más larga posible (since_year="2000" o MAX) para verificar el superlativo.
tendenciaObtener la serie completa del período afirmado y calcular dirección y magnitud.
comparacionUsar Eurostat para datos armonizados con el mismo año y metodología para todos los países.
proyeccionIdentificar la institución que generó la proyección y comparar con datos reales si el período ya ha pasado.

🤖 Guía para modelos de IA

Esta sección explica cómo usar el servidor de forma eficaz como modelo de IA.

Árbol de decisión: ¿qué herramienta usar?

¿Tengo una afirmación política/económica que verificar?
  → verify_claim(...)   # Genera un plan; luego ejecuta las herramientas sugeridas

¿Necesito series temporales macroeconómicas?
  ├─ España vs. UE           → get_eurostat_data(topic=..., geo="ES,EU27_2020")
  ├─ Solo España (INE)       → get_ine_operations → query_ine_data
  └─ Tipos de interés/EURIBOR/FX → get_bde_series(series_codes=..., time_range=...)

¿Necesito datos sectoriales del gobierno español?
  ├─ Energía eléctrica       → get_energy_data(data_type=..., start_date=..., time_trunc=...)
  ├─ Vivienda                → get_housing_stats(stat_type=...)
  ├─ Sanidad                 → get_health_stats(stat_type=...)
  ├─ Educación               → get_education_stats(stat_type=...)
  ├─ Seguridad Social        → get_social_security_stats(stat_type=...)
  ├─ Fiscalidad (AEAT)       → get_aeat_stats(stat_type=...)
  ├─ DGT / tráfico           → get_traffic_stats(stat_type=...)
  ├─ Justicia                → get_justice_stats(stat_type=...)
  └─ Empleo SEPE             → get_employment_stats(stat_type=...)

¿Necesito buscar legislación o el BOE?
  ├─ Ley en vigor (por nombre) → search_legislation(query=...)  ⚠️ puede dar 500
  └─ BOE de una fecha concreta → get_boe_summary(date="AAAAMMDD")

¿Necesito un fichero descargable de una institución sin API directa?
  └─ search_datasets(publisher="<código_organismo>") → list_dataset_resources(include_data=True)
     ⚠ search_datasets por keyword devuelve resultados poco fiables

¿Datos meteorológicos?
  ├─ Predicción              → get_weather_forecast(municipality_code=...)
  └─ Observaciones actuales  → get_weather_observations()

Limitaciones conocidas

APIProblemaMitigación
BOE /legislacion-consolidadaDevuelve errores 500 persistentes (fallo del servidor del BOE)Usa get_boe_summary con la fecha de publicación conocida
datos.gob.esBusca por título (una sola palabra clave); no es búsqueda de texto completoUsa la palabra más distintiva de tu consulta
EurostatDatos anuales con ~1 año de retraso; consultas de 2026 pueden devolver "No data"Usa until_year="2025" para datos anuales
BdE BIESTEl parámetro time_range debe coincidir con la frecuencia de la serie (diaria vs. mensual); una discordancia devuelve 412Usa latest_only=True primero para comprobar la frecuencia
REDatatime_trunc="year" acepta máx. 3 años; time_trunc="month" acepta máx. 2 años para algunos widgetsAjusta el rango de fechas al límite del widget

Consejos para search_datasets (último recurso)

Los datasets de datos.gob.es están mal etiquetados: la búsqueda por título devuelve resultados ruidosos e irrelevantes en la mayoría de casos. Usa siempre la herramienta dedicada de la fuente antes de recurrir a search_datasets.

Cuándo sí tiene sentido usarlo:

  • Con publisher= para listar todos los datasets de un organismo concreto (más fiable que keyword)
  • Para instituciones sin herramienta dedicada (CNMV, Tribunal de Cuentas, Hacienda transfers)
✅ Bien:  search_datasets(publisher="EA0028512")   → todos los datasets de AEAT
✅ Bien:  search_datasets(publisher="gobierno-vasco")  → datos abiertos del País Vasco
❌ Evitar: search_datasets(query="gasto sanitario")  → resultados aleatorios
❌ Evitar: cuando existe get_health_stats / get_eurostat_data / query_ine_data

Consejos para get_bde_series

Los códigos de series reales tienen formato D_XXXXXXX. Los códigos tipo TI_1_2_1 no existen.

# Tipos BCE (diarios) — usa time_range="12M" o "36M"
D_DTFK09A0  — tipo de refinanciación principal del BCE
D_DNBCEA72  — facilidad de crédito marginal
D_DNBCEB72  — facilidad de depósito

# EURIBOR (diarios) — usa time_range="12M"
D_DNBAF172  — EURIBOR 12 meses
D_DNBAD172  — EURIBOR 3 meses

# Tipos de cambio (mensuales) — usa time_range="60M"
D_1PFJ1001  — EUR/USD
D_1PFJ1004  — EUR/GBP

Consejos para get_energy_data (REData)

  • Para comparaciones de varios años: time_trunc="year" con rango máx. 3 años
  • Para evolución mensual: time_trunc="month" con rango máx. 2 años
  • Usa "installed_capacity" + time_trunc="year" para verificar crecimiento de renovables
  • Usa "generation_mix" + time_trunc="year" para ver el gas como precio marginal

🔍 Casos de uso

Verificación de afirmaciones políticas con verify_claim

Afirmación sobre nacimientos (estadística puntual, INE):

verify_claim(
    claim_normalizado="En España nacieron 328.704 niños en 2022",
    fecha="2025-10-14",
    ambito_geografico="España",
    ambito_tematico="demografía",
    entidad_mencionada="INE",
    metrica="número de nacimientos",
    valor_afirmado="328.704",
    periodo_temporal="2022",
    fuente_citada="INE",
    tipo_claim="estadistica_puntual",
)
# → query_ine_data(operation_code="MNP") limitado a datos anteriores a oct-2025

Afirmación de ranking — abandono escolar:

verify_claim(
    claim_normalizado="La tasa de abandono escolar es la más baja de la historia de España",
    fecha="2025-10-29",
    ambito_geografico="España",
    ambito_tematico="educación",
    metrica="tasa de abandono escolar temprano",
    valor_afirmado="más baja de la historia",
    periodo_temporal="actual",
    tipo_claim="ranking",
)
# → get_education_stats(stat_type="abandono_escolar")
# → get_eurostat_data(dataset_code="edat_lfse_14", since_year="2000") — serie completa para verificar superlativo

Afirmación sobre pensiones:

verify_claim(
    claim_normalizado="El ratio cotizantes/pensionistas ha caído por debajo de 2",
    fecha="2026-04-01",
    ambito_geografico="España",
    ambito_tematico="pensiones",
    metrica="ratio cotizantes por pensionista",
    tipo_claim="estadistica_puntual",
)
# → get_social_security_stats(stat_type="ratio_sostenibilidad")
# → get_social_security_stats(stat_type="cotizantes")

Afirmación histórica — voto parlamentario:

verify_claim(
    claim_normalizado="El Partido Popular votó a favor de establecer el impuesto al sol",
    fecha="2025-11-13",
    ambito_geografico="España",
    ambito_tematico="medio_ambiente",
    entidad_mencionada="Congreso de los Diputados",
    tipo_claim="historico",
)
# → search_legislation(query="impuesto sol autoconsumo energía renovable")
# → get_boe_summary con la fecha del RD correspondiente

Afirmación sobre tejido empresarial regional (Cataluña):

verify_claim(
    claim_normalizado="Las pymes suponen el 98% del tejido empresarial catalán",
    fecha="2026-02-17",
    claim_raw="el 98 % del teixit empresarial català",
    ambito_geografico="Cataluña",
    ambito_tematico="empresas",
    metrica="porcentaje de pymes sobre total empresas",
    valor_afirmado="98%",
    periodo_temporal="actual",
    idioma="ca",
    tipo_claim="estadistica_puntual",
)
# → search_datasets(query="directorio central empresas DIRCE INE")
# → search_regional_contracts(region="cataluña") — portal regional activado por ambito_geografico

Investigación de datos de ministerios

"¿Cuántos médicos por habitante tiene España respecto a la UE?"
→ get_health_stats(stat_type="profesionales")
→ get_eurostat_data("custom", dataset_code="hlth_rs_prshp", geo="ES,EU27_2020")

"¿Cuántos cotizantes hay por pensionista en España?"
→ get_social_security_stats(stat_type="ratio_sostenibilidad")

"¿Cuántos muertos en carretera hubo en 2023?"
→ get_traffic_stats(stat_type="victimas", period="2023")

"¿Ha bajado la tasa de criminalidad en los últimos cinco años?"
→ get_justice_stats(stat_type="criminalidad")

"¿Cuánto ha subido el precio del alquiler en los últimos años?"
→ get_housing_stats(stat_type="alquileres")
→ get_eurostat_data("house_prices", geo="ES,EU27_2020", since_year="2015")

Análisis de gasto público regional

"¿Cuánto gasta la Comunidad de Madrid en contratos de informática?"
→ search_regional_contracts(query="servicios informatica", region="madrid")

"Comparar licitaciones de sanidad entre comunidades"
→ search_regional_contracts(query="servicios sanitarios", region="all")

Investigación macroeconómica

get_eurostat_data("unemployment", geo="ES,EU27_2020,PT,IT", since_year="2019")
get_bde_series(series_codes="D_DNBCEB72,D_DTFK09A0", time_range="36M")  # tipos BCE
get_bde_series(series_codes="D_1PFJ1001", time_range="60M")              # EUR/USD
query_ine_data(table_id="50902")   # IPC mensual

🗂️ Fuentes de datos

InstituciónCoberturaAutenticación
datos.gob.es+90.000 datasets de todos los organismos públicosNo
INEDemografía, IPC, PIB, encuestas de empleo, padrónNo
Banco de EspañaTipos de interés, divisas, crédito, banca, agregados monetariosNo
AEMETPredicciones, observaciones y clima históricoClave gratuita
BOEBoletín Oficial, BORME, legislación consolidadaNo
PLACELicitaciones y contratos del sector público nacionalNo
Comunidad de MadridDatos abiertos y contratación regionalNo
Generalitat de CatalunyaDatos abiertos y contratación regionalNo
Generalitat ValencianaDatos abiertos y contratación regionalNo
SEPEParo registrado y contratos laboralesNo
RenfeHorarios, estaciones y posiciones en tiempo realNo
DGTSiniestralidad vial, parque de vehículos, matriculacionesNo
Ministerio de Sanidad / SNSGasto sanitario, profesionales, camas, listas de espera, mortalidadNo
Ministerio de Educación / MEFPAbandono escolar, matriculados, becas, gasto educativoNo
Ministerio de ViviendaPrecios de vivienda, hipotecas, construcción, desahuciosNo
INSS / Min. Seguridad SocialPensiones, cotizantes, prestaciones por desempleo, incapacidadNo
Ministerio de Justicia / CGPJCriminalidad, condenas, población penitenciaria, violencia de géneroNo
Red Eléctrica / REDataGeneración eléctrica, precios y demanda en tiempo realNo
CNMCElectricidad, gas, telecomunicaciones, competenciaNo
AEATRecaudación tributaria, IRPF, IVA, SociedadesNo
EurostatEstadísticas europeas para comparativas con la UENo

🧪 Tests

Tests automatizados con pytest

El proyecto tiene 73 tests unitarios (mocks HTTP) y 38 tests de integración (APIs reales).

# Tests unitarios (sin red)
uv run pytest

# Tests de integración contra APIs reales (requieren conexión)
uv run pytest -m integration -v

# Fichero concreto
uv run pytest tests/test_ine.py

Estado actual de integración: 34 pasan, 4 se omiten (BOE legislación-consolidada devuelve 500 de forma persistente en el servidor del BOE).

Pruebas interactivas con MCP Inspector

El MCP Inspector oficial permite probar las herramientas de forma interactiva desde el navegador.

Requisitos previos: Node.js con npx disponible.

  1. Arranca el servidor MCP (ver arriba)
  2. En otro terminal, lanza el inspector:
    npx @modelcontextprotocol/inspector --http-url "http://127.0.0.1:${MCP_PORT:-8000}/mcp"
    

🔧 Desarrollo

Linting y formateo

Este proyecto usa Ruff para linting y formateo, y ty para la comprobación de tipos.

# Lint (incluida ordenación de imports) y formateo
uv run ruff check --fix && uv run ruff format

# Comprobación de tipos
uv run ty check

Hooks de pre-commit

# Instalar el hook
uv run pre-commit install

El hook ejecuta automáticamente antes de cada commit:

  • Verificación de sintaxis YAML
  • Corrección de fin de fichero y espacios en blanco
  • Linting y formateo con Ruff

Variables de entorno

VariablePor defectoDescripción
MCP_HOST0.0.0.0Host en el que escucha el servidor. Usa 127.0.0.1 en desarrollo local
MCP_PORT8000Puerto del servidor HTTP
MCP_ENVlocalNombre del entorno reportado a Sentry (local, staging, production)
LOG_LEVELINFONivel de log de Python (DEBUG, INFO, WARNING, ERROR)
LOG_FORMATtextFormato de logs: text (legible por humanos) o json (para Loki/Datadog/CloudWatch)
AEMET_API_KEY—Requerida para las herramientas meteorológicas. Solicitar aquí
SENTRY_DSN—DSN de Sentry para monitorización de errores (desactivado si está vacío)
SENTRY_SAMPLE_RATE1.0Tasa de muestreo de Sentry (float 0.0–1.0)
MATOMO_URL—URL de la instancia Matomo para analíticas (desactivado si está vacío)
MATOMO_SITE_ID—ID del sitio en Matomo
MATOMO_AUTH_TOKEN—Token de autenticación de Matomo

Estructura del proyecto

datos-es-mcp/
├── main.py                          # App ASGI FastMCP + endpoint /health
├── pyproject.toml
├── Dockerfile
├── docker-compose.yml
├── .env.example
├── helpers/
│   ├── http.py                      # Fetch con retry y backoff exponencial (compartido)
│   ├── cache.py                     # Caché de metadatos con TTL de 24 h
│   ├── publishers.py                # Diccionario de publishers conocidos (60+ aliases)
│   ├── env_config.py                # URLs de APIs por entorno
│   ├── datos_gob_es_client.py       # API semántica de datos.gob.es (title/{keyword})
│   ├── ine_client.py                # API JSON del INE (Tempus3)
│   ├── bde_client.py                # API de estadísticas del Banco de España
│   ├── aemet_client.py              # AEMET OpenData (fetch en dos pasos)
│   ├── boe_client.py                # API REST del BOE/BORME/Legislación
│   ├── place_client.py              # Feed ATOM de PLACE + datos.gob.es
│   ├── regional_contracts_client.py # Portales Madrid / Cataluña / Valencia
│   ├── sepe_client.py               # Datos de empleo del SEPE
│   ├── renfe_client.py              # Portal de datos abiertos de Renfe
│   ├── cnmc_client.py               # Portal CKAN de la CNMC
│   ├── redata_client.py             # API REData de Red Eléctrica
│   ├── eurostat_client.py           # API de Eurostat (formato JSON-stat)
│   ├── aeat_client.py               # Datasets fiscales de la AEAT
│   ├── ministerios_client.py        # Cliente compartido para los 6 ministerios
│   ├── logging.py                   # Logging configurable (text/JSON)
│   ├── sentry.py
│   ├── matomo.py
│   └── user_agent.py
└── tools/
    ├── __init__.py                  # register_tools(mcp) — 25 herramientas
    ├── search_datasets.py
    ├── get_dataset_info.py
    ├── list_dataset_resources.py    # include_data=True para preview CSV/JSON
    ├── get_ine_operations.py        # Usa caché de 24 h
    ├── query_ine_data.py
    ├── get_bde_series.py
    ├── get_weather_forecast.py
    ├── get_weather_observations.py
    ├── get_boe_summary.py
    ├── search_legislation.py
    ├── search_public_contracts.py
    ├── search_regional_contracts.py
    ├── get_employment_stats.py
    ├── get_renfe_data.py
    ├── get_cnmc_data.py
    ├── get_energy_data.py
    ├── get_eurostat_data.py
    ├── get_aeat_stats.py
    ├── get_health_stats.py          # Ministerio de Sanidad / SNS
    ├── get_education_stats.py       # Ministerio de Educación / MEFP
    ├── get_housing_stats.py         # Ministerio de Vivienda + INE
    ├── get_traffic_stats.py         # DGT
    ├── get_social_security_stats.py # INSS / Seguridad Social
    ├── get_justice_stats.py         # Min. Justicia / CGPJ
    └── verify_claim.py

🤝 Contribuciones

Actualmente no se buscan contribuciones. Si quieres, siempre puedes crear un fork.


📄 Licencia

Este proyecto está licenciado bajo la Licencia MIT — consulta el fichero LICENSE para más detalles.

↑↓ navigate openesc close