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
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, 2026datos-es MCP Server
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
- Abre la configuración de Cursor
- Busca «MCP» o «Model Context Protocol»
- 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
-
Instala las dependencias
uv sync -
Prepara el fichero de entorno
cp .env.example .envEdita
.envy configura al menos:AEMET_API_KEY=tu_clave_de_aemet MCP_HOST=127.0.0.1 MCP_PORT=8000 MCP_ENV=local LOG_LEVEL=INFOCarga las variables:
set -a && source .env && set +a -
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:
- 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. search_datasets— solo si no existe herramienta dedicada para la institución o tema.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
| Herramienta | Descripción | Pará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_info | Metadatos completos de un dataset: organismo, licencia, cobertura geográfica, frecuencia de actualización y lista de distribuciones. | dataset_id |
list_dataset_resources | Lista 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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
get_ine_operations | Lista 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_data | Obtiene 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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
get_bde_series | Series 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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
get_weather_forecast | Predicció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_observations | Observaciones 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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
get_boe_summary | Resumen diario del BOE o BORME: secciones, departamentos e identificadores de los documentos publicados. | date (AAAAMMDD), gazette (BOE/BORME) |
search_legislation | Busca 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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
search_public_contracts | Licitaciones y contratos en PLACE (plataforma nacional). Modo datasets para históricos en bulk; modo feed para avisos recientes. | query, source (datasets/feed) |
search_regional_contracts | Contratació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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
get_employment_stats | Estadí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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
get_renfe_data | Datos 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_stats | Estadí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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
get_energy_data | Datos 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_data | Datos 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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
get_aeat_stats | Estadí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
| Herramienta | Fuente principal | Descripción | stat_type disponibles |
|---|---|---|---|
get_health_stats | Ministerio de Sanidad / SNS | Gasto 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_stats | Ministerio de Educación / MEFP | Abandono escolar, matriculados, universitarios, profesorado, becas, gasto educativo, FP, resultados PISA. | abandono_escolar, matriculados, universitarios, profesorado, becas, gasto_educativo, fp, pisa |
get_housing_stats | Ministerio de Vivienda + INE | Precios 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_stats | INSS / Min. Inclusión | Pensiones, cotizantes, ratio sostenibilidad, prestaciones por desempleo, incapacidad temporal, accidentes laborales, afiliados extranjeros. | pensiones, cotizantes, ratio_sostenibilidad, prestaciones_desempleo, incapacidad, accidentes_laborales, inmigracion |
get_traffic_stats | DGT | Siniestralidad vial, víctimas, parque de vehículos, matriculaciones, permisos de conducción, alcoholemia, velocidad. | accidentes, victimas, parque_vehiculos, matriculaciones, carnet, alcoholemia, velocidad |
get_justice_stats | Min. Justicia / CGPJ | Criminalidad, 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
| Herramienta | Descripción | Parámetros clave |
|---|---|---|
get_eurostat_data | Datos 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
| Herramienta | Descripción | Parámetros obligatorios |
|---|---|---|
verify_claim | Clasifica 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 textoambito_tematico: taxonomía temática (captura casos que los keywords no detectan)entidad_mencionada+fuente_citada: sugerencias específicas por instituciónambito_geografico: añade portales regionales para afirmaciones sub-nacionales
Parámetros obligatorios:
| Parámetro | Descripción |
|---|---|
claim_normalizado | La 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»). |
fecha | Siempre 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_por | Quién realizó la afirmación. Ejemplo: "Pedro Sánchez", "Partido Popular". |
ambito_geografico | Alcance geográfico. Valores canónicos: 17 CCAA + "España" + "Europa" / "Unión Europea" + "Internacional". |
ambito_tematico | Categorí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_claim | Tipo estructural: estadistica_puntual, historico, ranking, tendencia, comparacion, proyeccion. |
Parámetros secundarios:
| Parámetro | Descripción |
|---|---|
claim_raw | Texto verbatim original (con contexto, idioma original, interrupciones). Solo para trazabilidad. |
entidad_mencionada | Institución a la que se refiere la afirmación. Activa sugerencias específicas. Ejemplo: "INE", "Tribunal de Cuentas". |
metrica | La métrica concreta afirmada. Ejemplo: "tasa de abandono escolar". |
valor_afirmado | El valor concreto afirmado. Aparece en el checklist. Ejemplo: "98%", "más baja de la historia". |
periodo_temporal | El 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_citada | Fuente mencionada por quien hace la afirmación. Ejemplo: "INE", "No citada". |
idioma | Código ISO 639-1 del idioma del claim_raw (es, ca, gl, eu). |
intervention_orden | Posición en la sesión (base 1). Solo para trazabilidad. |
return_data | Si true, incluye una nota sobre la primera fuente recomendada. Por defecto false. |
Estrategias por tipo de afirmación:
tipo_claim | Estrategia aplicada |
|---|---|
estadistica_puntual | Localizar el valor oficial exacto y comparar con valor_afirmado. |
historico | Buscar el acto legislativo o administrativo en BOE/Diario de Sesiones. |
ranking | Recuperar la serie temporal más larga posible (since_year="2000" o MAX) para verificar el superlativo. |
tendencia | Obtener la serie completa del período afirmado y calcular dirección y magnitud. |
comparacion | Usar Eurostat para datos armonizados con el mismo año y metodología para todos los países. |
proyeccion | Identificar 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
| API | Problema | Mitigación |
|---|---|---|
BOE /legislacion-consolidada | Devuelve errores 500 persistentes (fallo del servidor del BOE) | Usa get_boe_summary con la fecha de publicación conocida |
| datos.gob.es | Busca por título (una sola palabra clave); no es búsqueda de texto completo | Usa la palabra más distintiva de tu consulta |
| Eurostat | Datos anuales con ~1 año de retraso; consultas de 2026 pueden devolver "No data" | Usa until_year="2025" para datos anuales |
| BdE BIEST | El parámetro time_range debe coincidir con la frecuencia de la serie (diaria vs. mensual); una discordancia devuelve 412 | Usa latest_only=True primero para comprobar la frecuencia |
| REData | time_trunc="year" acepta máx. 3 años; time_trunc="month" acepta máx. 2 años para algunos widgets | Ajusta 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ón | Cobertura | Autenticación |
|---|---|---|
| datos.gob.es | +90.000 datasets de todos los organismos públicos | No |
| INE | Demografía, IPC, PIB, encuestas de empleo, padrón | No |
| Banco de España | Tipos de interés, divisas, crédito, banca, agregados monetarios | No |
| AEMET | Predicciones, observaciones y clima histórico | Clave gratuita |
| BOE | Boletín Oficial, BORME, legislación consolidada | No |
| PLACE | Licitaciones y contratos del sector público nacional | No |
| Comunidad de Madrid | Datos abiertos y contratación regional | No |
| Generalitat de Catalunya | Datos abiertos y contratación regional | No |
| Generalitat Valenciana | Datos abiertos y contratación regional | No |
| SEPE | Paro registrado y contratos laborales | No |
| Renfe | Horarios, estaciones y posiciones en tiempo real | No |
| DGT | Siniestralidad vial, parque de vehículos, matriculaciones | No |
| Ministerio de Sanidad / SNS | Gasto sanitario, profesionales, camas, listas de espera, mortalidad | No |
| Ministerio de Educación / MEFP | Abandono escolar, matriculados, becas, gasto educativo | No |
| Ministerio de Vivienda | Precios de vivienda, hipotecas, construcción, desahucios | No |
| INSS / Min. Seguridad Social | Pensiones, cotizantes, prestaciones por desempleo, incapacidad | No |
| Ministerio de Justicia / CGPJ | Criminalidad, condenas, población penitenciaria, violencia de género | No |
| Red Eléctrica / REData | Generación eléctrica, precios y demanda en tiempo real | No |
| CNMC | Electricidad, gas, telecomunicaciones, competencia | No |
| AEAT | Recaudación tributaria, IRPF, IVA, Sociedades | No |
| Eurostat | Estadísticas europeas para comparativas con la UE | No |
🧪 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.
- Arranca el servidor MCP (ver arriba)
- 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
| Variable | Por defecto | Descripción |
|---|---|---|
MCP_HOST | 0.0.0.0 | Host en el que escucha el servidor. Usa 127.0.0.1 en desarrollo local |
MCP_PORT | 8000 | Puerto del servidor HTTP |
MCP_ENV | local | Nombre del entorno reportado a Sentry (local, staging, production) |
LOG_LEVEL | INFO | Nivel de log de Python (DEBUG, INFO, WARNING, ERROR) |
LOG_FORMAT | text | Formato 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_RATE | 1.0 | Tasa 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.