Skip to main content
Glama
Jaimegruiz

Datadis MCP Server

by Jaimegruiz
README.md
# Datadis MCP Server

Servidor MCP de producción que integra la [API de Datadis](https://datadis.es) con agentes IA (Claude, Copilot, Cursor, Open WebUI, etc.) mediante el Model Context Protocol.

## Arquitectura

```
Agente IA (Claude / Copilot / Cursor)
    │
    │  MCP (stdio o SSE)
    ▼
Datadis MCP Server (FastMCP 3.x)
    ├── Auth Layer          — ciclo de vida del token, nunca persiste en disco
    ├── Datadis Client      — httpx async, retry exponencial, excepciones tipadas
    ├── EnergyService       — cache-aside por namespace (supplies 24h, consumo 1h…)
    ├── AnalysisService     — análisis semántico, detención de anomalías, informes
    ├── MCP Tools (13)      — wrappers delgados sin lógica de negocio
    ├── MCP Resources (3)   — datos de catálogo en tiempo real
    └── MCP Prompts (3)     — plantillas de prompts para análisis energético
    │
    │  HTTPS
    ▼
Datadis API V2
```

## Estructura del proyecto

```
datadis-mcp/
├── server.py            ← punto de entrada FastMCP
├── config.py            ← Pydantic Settings (variables de entorno)
├── auth.py              ← gestor del ciclo de vida del token
├── datadis_client.py    ← cliente HTTP async para todos los endpoints V2
├── exceptions.py        ← jerarquía de excepciones tipadas
├── models/              ← modelos de dominio Pydantic v2
├── cache/               ← abstracción de cache TTL por namespace
├── utils/               ← utilidades transversales (seguridad, logging)
├── services/
│   ├── energy_service.py    ← wrapper con cache sobre DatadisClient
│   └── analysis_service.py  ← análisis semántico de alto nivel
├── tools/               ← 13 tools MCP (sin lógica de negocio)
├── resources/           ← 3 resources MCP (status, distributors, groups)
├── prompts/             ← 3 prompts MCP (analyse_supply, executive_report, compare_years)
├── tests/               ← 150 tests pytest (83.61% cobertura)
├── pyproject.toml
├── requirements.txt
├── Dockerfile
└── .env.example
```

## Quick Start

### Requisitos

- Python 3.12+
- Cuenta en Datadis con credenciales válidas

### Instalación local

```bash
cd datadis-mcp

# Instalar dependencias
pip install -r requirements-dev.txt

# Configurar credenciales
copy .env.example .env        # Windows
# cp .env.example .env        # Linux/macOS
# Editar .env: rellenar DATADIS_USERNAME y DATADIS_PASSWORD

# Iniciar el servidor (transporte stdio — para Claude Desktop / Cursor)
python server.py

# O con transporte SSE (HTTP — para clientes web)
$env:MCP_TRANSPORT="sse"; python server.py   # Windows
MCP_TRANSPORT=sse python server.py            # Linux/macOS
```

### Redes corporativas con proxy SSL

Si aparece `CERTIFICATE_VERIFY_FAILED`, añade esto a tu `.env`:

```dotenv
HTTP_SSL_VERIFY=false
```

## Conectar un agente IA

### VS Code (GitHub Copilot Agent)

El fichero [.vscode/mcp.json](.vscode/mcp.json) ya está incluido en el repositorio.
VS Code lo detecta automáticamente — abre el proyecto y el servidor aparecerá en
**Copilot Chat → Agent mode → herramientas disponibles**.

Las credenciales se leen del fichero `.env` del proyecto.

### Claude Desktop

Edita `%APPDATA%\Claude\claude_desktop_config.json` (créalo si no existe):

```json
{
  "mcpServers": {
    "datadis": {
      "command": "python",
      "args": ["C:\\ruta\\completa\\a\\datadis-mcp\\server.py"],
      "env": {
        "DATADIS_USERNAME": "TU_NIF",
        "DATADIS_PASSWORD": "TU_PASSWORD",
        "HTTP_SSL_VERIFY": "false"
      }
    }
  }
}
```

Reinicia Claude Desktop. Verás el ícono del servidor en la barra de herramientas.

### Cursor

Edita `%USERPROFILE%\.cursor\mcp.json` (créalo si no existe):

```json
{
  "mcpServers": {
    "datadis": {
      "command": "python",
      "args": ["C:\\ruta\\completa\\a\\datadis-mcp\\server.py"],
      "env": {
        "DATADIS_USERNAME": "TU_NIF",
        "DATADIS_PASSWORD": "TU_PASSWORD",
        "HTTP_SSL_VERIFY": "false"
      }
    }
  }
}
```

Ve a **Cursor Settings → MCP** para verificar que el servidor aparece activo.

### Docker

```bash
# 1. Build
docker build -t datadis-mcp .

# 2. Verificar que la imagen se construyó correctamente
docker images datadis-mcp
docker inspect datadis-mcp --format "Usuario: {{.Config.User}} | Puerto: {{.Config.ExposedPorts}}"

# 3. Arrancar en modo SSE (HTTP, puerto 8000)
docker run -d \
  --name datadis \
  -p 8000:8000 \
  -e DATADIS_USERNAME=TU_NIF \
  -e DATADIS_PASSWORD=TU_PASSWORD \
  -e HTTP_SSL_VERIFY=false \
  -e MCP_TRANSPORT=sse \
  datadis-mcp

# 4. Ver logs de arranque
docker logs datadis

# 5. Smoke test — el endpoint SSE debe responder
curl http://localhost:8000/sse          # Linux/macOS
Invoke-RestMethod http://localhost:8000/sse   # PowerShell

# 6. Verificar healthcheck
docker inspect datadis --format "Health: {{.State.Health.Status}}"

# 7. Parar y eliminar el contenedor
docker stop datadis && docker rm datadis
```

**Variables de entorno disponibles:**

| Variable | Descripción | Requerida |
|----------|-------------|-----------|
| `DATADIS_USERNAME` | NIF de la cuenta Datadis | Sí |
| `DATADIS_PASSWORD` | Contraseña de Datadis | Sí |
| `HTTP_SSL_VERIFY` | `false` en redes con proxy SSL | No |
| `MCP_TRANSPORT` | `sse` (Docker) o `stdio` (local) | No |
| `MCP_HOST` | Host de escucha (defecto `0.0.0.0`) | No |
| `MCP_PORT` | Puerto de escucha (defecto `8000`) | No |
| `LOG_LEVEL` | `DEBUG`\|`INFO`\|`WARNING` (defecto `INFO`) | No |

## Desarrollo

```bash
# Tests con cobertura
pytest

# Linter
ruff check .

# Tipos
mypy .

# Formateo
ruff format .
```

## Tools MCP disponibles

### Técnicas (acceso directo a la API)

| Tool | Descripción |
|------|-------------|
| `get_supplies` | Listado de puntos de suministro (CUPS) |
| `get_contract` | Detalle del contrato de un CUPS |
| `get_consumption` | Curva de carga horaria/cuarto-horaria |
| `get_max_power` | Potencia máxima registrada por periodo |
| `get_reactive_energy` | Energía reactiva por periodo (P1–P6) |
| `get_distributors` | Códigos de distribuidora vinculados a la cuenta |
| `get_groups` | Grupos de suministros definidos |

### Semánticas (análisis de alto nivel)

| Tool | Descripción |
|------|-------------|
| `get_supply_overview` | Resumen consolidado: suministro + contrato (auto-descubre distribuidor) |
| `get_energy_profile` | Perfil estadístico: total, media, máx, mín, desv. estándar |
| `compare_periods` | Comparación entre dos periodos: Δ kWh + % variación + tendencia |
| `detect_anomalies` | Detección de picos anómalos mediante Z-score configurable |
| `get_self_consumption_analysis` | Ratios de autoconsumo/excedentes para instalaciones CAU |
| `executive_energy_report` | Informe ejecutivo anual con recomendaciones autogeneradas |

## Resources MCP

| URI | Contenido |
|-----|----------|
| `datadis://status` | Estado del servidor: autenticación, cache, versión |
| `datadis://distributors` | Catálogo de distribuidoras (cacheado 24h) |
| `datadis://groups` | Grupos de suministro (cacheado 24h) |

## Prompts MCP

| Prompt | Descripción |
|--------|-------------|
| `analyse_supply` | Guía al agente: overview → perfil → potencia máx → informe |
| `executive_energy_report` | Plantilla de informe ejecutivo anual estructurado |
| `compare_years` | Comparación interanual con interpretación de tendencia |

## Seguridad

- Credenciales exclusivamente desde variables de entorno — nunca en código.
- Token bearer en memoria únicamente — nunca en disco ni en logs.
- NIF/NIE enmascarado en todos los logs (`4******0A`).
- TLS obligatorio para todas las comunicaciones con la API.
- Usuario non-root en Docker.
- `HTTP_SSL_VERIFY=false` disponible para proxies corporativos con inspección SSL.

## Licencia

MIT