ha-mcp-readonly
Servidor MCP (Protocolo de Contexto de Modelo) de solo lectura para Home Assistant. Proporciona a los asistentes de IA (Claude Desktop, LibreChat, Cline) visibilidad completa de tu hogar inteligente — estados de entidades, automatizaciones, scripts, dispositivos, registros, diagnósticos — sin ningún acceso de escritura. También genera instantáneas de contexto de IA estáticas para sistemas RAG, Proyectos ChatGPT, Qwen y otras herramientas que aceptan archivos de conocimiento personalizados. Construido en Python, funciona en cualquier lugar — localmente, en Docker o como una integración MCP.
Documentación
HA-MCP-Readonly
Servidor MCP (Model Context Protocol) de solo lectura para Home Assistant. Brinda a los asistentes de IA (Claude Desktop, LibreChat, Cline) visibilidad completa de tu hogar inteligente — estados de entidades, automatizaciones, scripts, dispositivos, registros, diagnósticos — sin ningún acceso de escritura. También genera instantáneas estáticas de contexto de IA para sistemas RAG, ChatGPT Projects, Qwen y otras herramientas que aceptan archivos de conocimiento personalizados. Desarrollado en Python, se ejecuta en cualquier lugar: localmente, en Docker o como integración MCP.
Requisitos
- Python 3.11+ (para uso local) o Docker
- Una instancia de Home Assistant con un token de acceso de larga duración
- Crea uno en tu perfil de HA: Configuración → Seguridad → Tokens de acceso de larga duración
- Acceso al directorio de configuración de Home Assistant (para herramientas del sistema de archivos)
Inicio rápido
1. Configurar el entorno
cp .env.example .env
Edita .env con tus credenciales:
HA_URL=http://your-ha-ip:8123
HA_TOKEN=your_long_lived_access_token_here
# HA_CONFIG_PATH=/config # optional, default shown
# MCP_DEV_TOOLS_ENABLED=1 # optional, default shown
# HEALTH_CHECK_PORT=9091 # optional, default shown
# MCP_PORT=9092 # Streamable HTTP port when enabled
# REST_API_PORT=9093 # optional, default shown
# RUN_TESTS_ON_STARTUP=0 # optional, default shown
# OUTPUT_PATH=/app/output/ha-ai-context.md # optional, default shown
IMPORTANTE: El archivo .env contiene tu token de acceso. Está en gitignore y nunca debe enviarse al repositorio.
2. Ejecutar con Docker
Primero, configura tus credenciales. Usa un archivo .env (recomendado) o pasa las variables directamente.
Opción A — con archivo .env y docker compose:
cp .env.example .env
# edit .env with your HA_URL and HA_TOKEN
docker compose up -d
El docker-compose.yml incluido extrae la imagen del GitHub Container Registry y monta tu configuración de HA en modo solo lectura:
services:
ha-mcp-readonly:
image: ghcr.io/paulomac1000/ha-mcp-readonly:latest
container_name: ha-mcp-readonly
env_file: .env
environment:
MCP_TRANSPORT: http
MCP_BIND_HOST: 0.0.0.0
MCP_AUTH_TOKEN: ${MCP_AUTH_TOKEN:?Set a strong MCP_AUTH_TOKEN}
ports:
- "127.0.0.1:9091:9091" # health
- "127.0.0.1:9092:9092" # authenticated Streamable HTTP MCP
volumes:
- /path/to/ha/config:/config:ro # Replace with your HA config path (e.g., /config, ~/.homeassistant)
tmpfs:
- /app/output:size=256m,mode=0750,uid=10001,gid=10001
restart: unless-stopped
read_only: true
cap_drop: ["ALL"]
security_opt: ["no-new-privileges:true"]
Opción B — con docker run simple:
docker run -d \
--name ha-mcp-readonly \
-p 127.0.0.1:9091:9091 \
-p 127.0.0.1:9092:9092 \
-e HA_URL=http://your-ha-ip:8123 \
-e HA_TOKEN=your_token \
-e MCP_TRANSPORT=http \
-e MCP_BIND_HOST=0.0.0.0 \
-e MCP_AUTH_TOKEN=replace-with-a-high-entropy-caller-token \
-v /path/to/ha/config:/config:ro \
ghcr.io/paulomac1000/ha-mcp-readonly:latest
Compilación local:
docker build -t ha-mcp-readonly .
docker compose -f docker-compose.build.yml up -d
3. Ejecutar localmente (Python 3.11+)
pip install -r requirements.txt
HA_URL=http://localhost:8123 HA_TOKEN=your_token python server.py
Puertos
| Puerto | Protocolo | Propósito | Endpoint |
|---|---|---|---|
| 9091 | HTTP | Verificación de salud | GET /health |
| 9092 | HTTP | MCP HTTP Streamable autenticado | /mcp |
| 9093 | HTTP | API REST autenticada opcional + Generador de contexto | /api/* |
Verificar
# Health check
curl http://localhost:9091/health
# Readiness
curl http://localhost:9091/ready
# MCP uses an official Streamable HTTP client at http://127.0.0.1:9092/mcp.
# REST/context routes on 9093 exist only when REST_API_ENABLED=1 and require a bearer token.
Herramientas disponibles (158 con herramientas de desarrollo, 145 sin ellas)
Las herramientas están organizadas por categoría (75 se muestran en la tabla a continuación). Todas son de solo lectura: sin cambios de estado, sin llamadas de servicio, sin modificaciones.
| Categoría | Herramientas clave |
|---|---|
| Estados | get_entity_state, get_states_grouped, search_entities, get_domains_summary, get_system_overview |
| Automatizaciones | list_automations, get_automation_code, get_automation_file_location, diagnose_automation, search_automations_by_entity, get_automation_conflicts, get_automation_entity_id |
| Scripts y escenas | list_scripts, get_script_code, list_scenes, get_scene_code |
| Blueprints | list_blueprints, get_blueprint_code, get_blueprint_instances, get_blueprint_usage_summary, resolve_blueprint_automation |
| Dispositivos y áreas | get_device_details, search_devices, get_devices_by_area, get_area_devices_summary |
| Entradas de configuración | get_config_entry_details, search_config_entries, diagnose_config_entry, list_config_entry_domains |
| Integraciones | get_integration_entities, get_integration_summary |
| Diagnósticos | diagnose_system_health, get_unavailable_entities_grouped, get_integration_health, diagnose_person_tracking |
| Registros | get_log_insights, analyze_log_errors, get_startup_errors, get_log_timeline, search_logs |
| Historial | get_entity_state_history_summary, get_recent_state_changes |
| Contexto | entity_get_context_tree, get_entity_dependencies, get_entity_consumers, get_context_chain |
| Configuración | get_main_configuration, search_in_config, validate_yaml_syntax, read_config_file |
| Almacenamiento | search_registries_batch, get_entity_registry, get_device_registry, get_area_registry, get_template_entity_code, get_cache_stats |
| Lovelace | get_lovelace_dashboards, get_lovelace_config, get_lovelace_resources, search_lovelace_config, get_lovelace_config_summary, diagnose_lovelace_setup |
| Lote | bulk_search_entities, compare_entities_state, validate_yaml_batch, get_automation_codes_batch |
| Compuesto | investigate_entity, get_area_diagnostic, get_entity_with_automations, audit_config_orphans |
| Grafo | graph_build_index, graph_find_references, graph_entity_impact, graph_get_neighbors, graph_detect_ghost_references, graph_detect_orphans, graph_export_mermaid |
| Herramientas de desarrollo | test_template, compare_templates, diagnose_entity, check_entity_exists, validate_automation_trigger, diagnose_template |
Catálogo completo de herramientas con esquemas disponible en GET /api/tools
Novedades en v2.0.0
- Cambio importante — limpieza de transporte: Se eliminó el transporte heredado HTTP+SSE de dos endpoints. Los transportes MCP compatibles ahora son solo stdio y Streamable HTTP;
MCP_TRANSPORT=ssese rechaza. - Despliegue de red reforzado: Aplicación ASGI explícita con límites de tamaño de solicitud/cabecera, política de Host de confianza (
MCP_ALLOWED_HOSTS), CORS de origen exacto, límites de conexión y selección de modo sin estado/con estado. - Redacción recursiva de credenciales: Todas las respuestas de herramientas se sanitizan en el límite de la operación: tokens de portador, JWT, claves de API, contraseñas y direcciones IP se redactan tanto de las cargas útiles de respuesta como de la salida de registros.
- Descubrimiento de capacidades: El descubrimiento público ahora separa los transportes/componentes compatibles y activos, e informa la identidad del servidor, SDK, protocolo y perfil de despliegue.
- Correcciones de fiabilidad: Corrección de rendimiento de
diagnose_automation_aliases(>120 s a ~4,5 s en una instancia con 131 automatizaciones); sondeo de salud del backend con reintentos al inicio y reconciliación en segundo plano; corrutinas de almacenamiento bloqueantes ejecutadas a través del ejecutor de invocación limitado. - Verificación y evidencia: La alineación con ai-skills utiliza un validador fijado y pruebas de cassette grabadas en Home Assistant real. CI alojado de cabecera exacta verifica 1.234 pruebas unitarias, 17 pruebas de protocolo, la rueda instalada y artefactos de contenedor amd64/arm64. La evidencia de HA en vivo vinculada a revisión se documenta por separado en
docs/evidence-live-27d32c9b.mdy se aplica solo a la revisión nombrada allí.
También heredado de v1.6.0
- 5 herramientas:
get_context_chain,resolve_blueprint_automation,get_cache_stats,compare_templates,get_automation_entity_id - Paginación de registros (
limit/offsetenget_entity_registry,get_device_registry,get_area_registry,get_config_entries) - Campo
data_qualityen herramientas de diagnóstico compuestas choose_analysisendiagnose_automation(detail_level="full")
Configuración del cliente
Stdio local
Instala la rueda y configura el cliente para iniciar el servidor como subproceso. Este es el transporte predeterminado y no expone un puerto de red MCP.
{
"mcpServers": {
"ha-mcp-readonly": {
"command": "ha-mcp-readonly",
"env": {
"HA_URL": "http://homeassistant.local:8123",
"HA_TOKEN": "replace-with-a-long-lived-access-token",
"HA_CONFIG_PATH": "/path/to/home-assistant/config"
}
}
}
}
Streamable HTTP autenticado
Establece MCP_TRANSPORT=http, MCP_AUTH_TOKEN y una dirección de enlace controlada. El endpoint es /mcp. Se eliminó la compatibilidad heredada con /sse y MCP_TRANSPORT=sse se rechaza.
{
"mcpServers": {
"ha-mcp-readonly": {
"url": "http://127.0.0.1:9092/mcp",
"headers": {
"Authorization": "Bearer replace-with-a-high-entropy-caller-token"
}
}
}
}
El catálogo predeterminado contiene 145 herramientas de solo lectura. Las herramientas solo para desarrolladores permanecen deshabilitadas a menos que se establezca MCP_DEV_TOOLS_ENABLED=1.
Generador de contexto
El generador de contexto crea una instantánea Markdown limitada para análisis sin conexión, sistemas de recuperación, conocimiento de proyectos de IA, auditorías y resolución de problemas.
| Modo | Acceso a datos |
|---|---|
offline | Solo configuración local de Home Assistant y registros de almacenamiento seguros. El acceso a la red está deshabilitado por construcción. |
online | APIs REST y WebSocket de Home Assistant. La falta de acceso de red requerido falla la ejecución. |
hybrid | Fuentes locales más todas las fuentes de API compatibles disponibles para el token configurado. |
El artefacto incluye las secciones de análisis normales y una matriz de Procedencia de fuentes y completitud. Cada fuente intentada registra su método, estado, número de registros, número de bytes, número de redacciones, ventana solicitada y motivo de fallo u omisión. La Instantánea integral de datos seguros incluye todos los datos compatibles y accesibles dentro de los límites configurados:
- estados, servicios, componentes, eventos, configuración, historial, logbook, registro de errores, calendarios y eventos de calendario;
- datos de entidad, dispositivo, área, piso, etiqueta, categoría, entrada de configuración, energía, panel, recurso Lovelace, reparación, salud del sistema y pipeline de Assist expuestos por Home Assistant;
- elementos de tareas pendientes y cada tipo de pronóstico meteorológico anunciado descubierto dinámicamente a partir de los estados de entidad;
- todos los registros seguros descubribles de
.storagemás datos de inventario YAML, JSON y archivos bajo la raíz configurada; - análisis de automatización, script, escena, blueprint, plantilla, helper, persona, zona, energía, HACS, caché, dependencia, panel y diagnóstico.
Los almacenes de credenciales están excluidos. Los campos sensibles, tokens de portador, JWT, parámetros de consulta secretos y valores de !secret se redactan. Los medios binarios, transmisiones de cámara, contenidos de copias de seguridad, bases de datos y registros con credenciales no se copian. Las fuentes no disponibles por permisos, integraciones faltantes, comandos no compatibles, ventanas configuradas o límites de tamaño permanecen visibles en la procedencia en lugar de omitirse silenciosamente.
Los límites relevantes son HA_CONTEXT_HISTORY_HOURS, HA_CONTEXT_LOG_HOURS, HA_CONTEXT_CALENDAR_DAYS, HA_CONTEXT_MAX_SOURCE_BYTES y HA_CONTEXT_MAX_OUTPUT_BYTES.
Generación consciente del presupuesto
El generador puede limitar la salida en el origen en lugar de emitir todo y dejar que los consumidores lo reduzcan. Las opciones están disponibles a través del entorno (HA_CONTEXT_PROFILE, HA_CONTEXT_SECTIONS, HA_CONTEXT_DETAIL, HA_CONTEXT_INCLUDE_FILES, HA_CONTEXT_INCLUDE_STORAGE, HA_CONTEXT_ON_BUDGET_EXCEEDED) y mediante la llamada de generación REST:
| Opción | Valores | Predeterminado | Efecto |
|---|---|---|---|
profile | full, agent, compact | full | Preajuste de sección. full renderiza todo (comportamiento histórico); agent elimina las secciones pesadas de instantánea sin procesar, registros y cambios recientes; compact renderiza solo resumen, procedencia, salud del sistema, topología y referencia rápida. |
maxBytes | entero ≥ 1024, ≤ 128 MiB | HA_CONTEXT_MAX_OUTPUT_BYTES (96 MiB si no se establece) | Presupuesto de bytes de salida. Omitir maxBytes hereda el valor de entorno configurado. Las secciones que no caben se omiten completas y se informan. |
sections | claves de sección o alias | perfil predeterminado | Selección explícita que anula el perfil. Alias: runtime, health, provenance, logs. El resumen ejecutivo y las secciones de procedencia de fuentes siempre se incluyen. |
repositoryFiles / include_files | booleano | true | Cuando false, la instantánea integral sin procesar no recopila ni serializa los cuerpos de archivos de configuración. Las secciones de análisis estructurado (registros, automatizaciones, dispositivos) permanecen como vistas de metadatos derivados y no se ven afectadas. |
storageRecords | booleano | true | Cuando false, la instantánea integral sin procesar no recopila registros seguros de .storage. |
detail | full, compact | full | Alias que se resuelve a profile=compact cuando no se proporciona un perfil explícito. |
onBudgetExceeded | auto, fail, truncate | auto | Política resuelta: auto se comporta como fail para el perfil full (preservando la ejecución histórica de cierre ante fallo) y como truncate para agent/compact; fail/truncate explícitos siempre ganan. |
Los valores predeterminados de las opciones REST se resuelven por la capa REST como se muestra; no heredan sus valores predeterminados no booleanos de las variables de entorno correspondientes — solo maxBytes recurre a su valor de entorno.
El resultado de la generación informa output_bytes, uncompressed_bytes, output_sha256, profile, requested_sections (la selección original resuelta), selected_sections (la selección efectiva incluido el mínimo obligatorio), rendered_sections, omitted_sections (con tamaños de bytes exactos por sección y motivos) y truncated. Deshabilitar archivos de repositorio o registros de almacenamiento registra una omisión explícita de policy: en la matriz de procedencia: nada se omite silenciosamente. El resumen ejecutivo y las secciones de procedencia de fuentes siempre se renderizan, incluso bajo selecciones de sección explícitas, por lo que cada artefacto lleva su registro de completitud.
La identidad de la fuente y del entorno de ejecución se transportan mediante campos de resultado dedicados: config_path identifica la raíz auditada de configuración de Home Assistant (identidad de la fuente), mientras que mode, profile_revision y generated_at identifican las condiciones del entorno de ejecución que las generan (identidad del entorno); output_sha256 fija los bytes exactos del artefacto. Por lo tanto, los consumidores siempre pueden atribuir un artefacto al estado de la instancia y a la revisión del generador que lo produjo.
Las instancias vacías son un caso de éxito: una generación sobre una instancia válida pero con cero registros se completa normalmente, muestra secciones con conteo cero e informa contadores a cero con truncated: false. Solo las opciones no válidas, las violaciones de presupuesto bajo la política de fallo o los datos requeridos no disponibles hacen fallar la ejecución.
Dos decisiones de diseño deliberadas, registradas para los consumidores del issue #33: agent es la vista operativa acotada destinada al consumo por agentes, mientras que el valor predeterminado de la API sigue siendo el perfil histórico full por compatibilidad con versiones anteriores; los llamadores optan explícitamente por la vista acotada. El truncamiento se aplica a nivel de sección completa y se informa explícitamente; el truncamiento parcial (a mitad de sección) nunca se aplica de forma silenciosa, por lo que el contrato se asigna como included_sections → rendered_sections, truncated_sections → omitted_sections y bytes → output_bytes.
Nota de seguridad: los ejemplos anteriores son solo de bucle local. Cuando el adaptador REST se expone a través de un proxy inverso remoto, termine TLS en el proxy y exija HTTPS a los clientes; el HTTP sin cifrar transmite el token de portador en texto claro.
curl -X POST http://127.0.0.1:9093/api/context/generate \
-H "Authorization: Bearer $REST_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"mode":"hybrid","profile":"agent","maxBytes":2097152}'
curl -X POST http://127.0.0.1:9093/api/context/generate \
-H "Authorization: Bearer $REST_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"mode":"offline","detail":"compact"}'
curl -H "Authorization: Bearer $REST_API_TOKEN" \
http://127.0.0.1:9093/api/context/status
curl -H "Authorization: Bearer $REST_API_TOKEN" \
http://127.0.0.1:9093/api/context/download > ha-ai-context.md
API REST
El adaptador de compatibilidad REST opcional está deshabilitado de forma predeterminada. Cuando está habilitado, todas las rutas excepto health requieren un token de portador y usan el mismo manifiesto, capacidades, plazo, concurrencia, tamaño de respuesta y política de errores que MCP.
curl -H "Authorization: Bearer $REST_API_TOKEN" \
'http://127.0.0.1:9093/api/tools?detail=full'
curl -X POST http://127.0.0.1:9093/api/tools/get_entity_state \
-H "Authorization: Bearer $REST_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id":"sun.sun"}'
curl -H "Authorization: Bearer $REST_API_TOKEN" \
http://127.0.0.1:9093/api/openapi.json
Desarrollo
Configuración
git clone https://github.com/paulomac1000/ha-mcp-readonly.git
cd ha-mcp-readonly
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Ejecutar pruebas
# Deterministic local gates
pytest tests/unit/ -q
pytest tests/protocol/ -q
# Backend-dependent suites; require an isolated Home Assistant and credentials
export HA_URL=http://your-ha:8123
export HA_TOKEN=your_token
pytest tests/smoke/ tests/integration/ tests/e2e/ -q
Las pruebas dependientes del backend informan omisiones cuando el entorno requerido de Home Assistant no está presente. CI instala el wheel en un entorno limpio, ejecuta un subproceso stdio real y verifica health, metadatos REST, el ciclo de vida del contexto sin conexión y Streamable HTTP autenticado contra los contenedores de lanzamiento compilados. El flujo de trabajo de lanzamiento compila por separado un candidato multiplataforma en cuarentena, prueba su digest exacto en amd64 y arm64, y promueve solo ese digest desde el publicador protegido.
Lint y formato
ruff check .
ruff format --check .
Arquitectura
server.py # Main entry point — FastMCP + REST API + health check
context_generator/
├── config.py # Immutable per-run configuration
├── constants.py # Legacy/static analyzer defaults and HA YAML loader
├── runtime.py # Context-local runtime and provenance scope
├── provenance.py # Completeness matrix and redaction
├── snapshot.py # Safe filesystem, REST, and WebSocket collectors
├── storage_policy.py # Positive allowlist for model-visible .storage data
├── core.py # Isolated generation entry points
├── analyzers.py # Domain analyzers
├── formatters.py # Atomic bounded Markdown output
└── utils.py # Runtime-aware registry and API adapters
ha_graph/
└── graph_builder.py # HA Semantic Graph: build, query, and export
tools/
├── automations.py # Automation analysis (17 tools)
├── batch_operations.py # Bulk entity operations (5 tools)
├── blueprints.py # Blueprint management (4 tools)
├── capabilities.py # Zero-I/O MCP introspection tool catalog (1 tool)
├── categories.py # Category management (automation, script, scene, helpers) (1 tool)
├── composite.py # Composite diagnostic tools (4 tools)
├── config.py # Configuration file tools (10 tools)
├── config_entries.py # Config entry diagnostics (4 tools)
├── devices.py, areas.py # Device and area tools (6+1 tools)
├── dev_tools.py # Template testing, validation (13 tools)
├── diagnostics.py # System health, energy dashboard (18 tools)
├── entity_context.py # Entity context tree (2 tools)
├── entity_dependencies.py # Entity dependency graph (2 tools)
├── filesystem_explorer.py # Secured filesystem browsing (3 tools)
├── graph_tools.py # HA entity graph tools (7 tools)
├── health_reporter.py # Health score and metrics (1 tool)
├── helpers_health.py # Helper entity health diagnostics (1 tool)
├── history.py # State history and recent changes (2 tools)
├── integrations.py # Integration entity analysis (2 tools)
├── logs.py # Log analysis and insights (8 tools)
├── manifests.py # TOOL_MANIFESTS, risk prefix injection
├── observability.py # request_id, invocation counters
├── scripts.py, scenes.py # Script and scene inspection (2+2 tools)
├── states.py # Entity state queries (12 tools)
├── storage.py # Registry dump and search tools (30 tools)
├── utils.py # Shared: HA API client, registry loader, log sanitizer
└── yaml_utils.py # HomeAssistantLoader for HA-specific YAML tags
tests/
├── unit/ # 39 test files, 1181 tests, fully mocked
├── integration/ # Real HA tests (requires HA_URL + HA_TOKEN)
├── smoke/ # REST API smoke tests (requires local server)
└── e2e/ # End-to-end pipeline tests (requires real HA)
Seguridad
- Solo lectura por diseño — sin operaciones de escritura en Home Assistant. No puede modificar estados, ejecutar servicios ni activar automatizaciones.
- Restricciones del sistema de archivos — acceso limitado al directorio
/config. El recorrido de rutas (..,~) está bloqueado. Tamaño máximo de archivo 10 MB. Profundidad máxima de directorio 20. - Datos de autenticación bloqueados — los registros de
auth,auth_provider.*yonboardingnunca se devuelven. - Redacción de credenciales —
HA_TOKENnunca se registra ni se expone en las salidas. Los JWT, contraseñas, claves de API y direcciones IP se sanean de la salida de registros.
Notas
- El servidor puede exponer 9091 (health), 9092 (Streamable HTTP MCP autenticado) y 9093 (adaptador REST/contexto autenticado opcional). Stdio sigue siendo el transporte MCP predeterminado.
MCP_DEV_TOOLS_ENABLED=0deshabilita la ejecución de plantillas y las herramientas de depuración para uso en producción.- Nota de seguridad: los puertos 9091-9093 no deben exponerse públicamente. Use reglas de firewall o un proxy inverso con autenticación si es necesario.
- Los archivos de registro (áreas, dispositivos, entidades, entradas de configuración) se almacenan en caché durante 5 minutos para reducir la E/S del sistema de archivos.
- Todas las respuestas de las herramientas devuelven JSON con un campo
success— verifique siempre este campo antes de leerdata.
Solución de problemas
Para problemas comunes y sus soluciones, consulte docs/documentation.md#troubleshooting.
Licencia
MIT — consulte LICENSE para más detalles.