ha-mcp-readonly
Servidor MCP (Model Context Protocol) somente leitura para Home Assistant. Oferece aos assistentes de IA (Claude Desktop, LibreChat, Cline) visibilidade total da sua casa inteligente — estados de entidades, automações, scripts, dispositivos, logs, diagnósticos — sem qualquer acesso de escrita. Também gera snapshots estáticos de contexto de IA para sistemas RAG, Projetos ChatGPT, Qwen e outras ferramentas que aceitam arquivos de conhecimento personalizados. Desenvolvido em Python, funciona em qualquer lugar — localmente, em Docker ou como integração MCP.
Documentação
HA-MCP-Readonly
Servidor MCP (Model Context Protocol) somente leitura para Home Assistant. Dá aos assistentes de IA (Claude Desktop, LibreChat, Cline) visibilidade total da sua casa inteligente — estados de entidades, automações, scripts, dispositivos, logs, diagnósticos — sem qualquer acesso de escrita. Também gera snapshots estáticos de contexto de IA para sistemas RAG, ChatGPT Projects, Qwen e outras ferramentas que aceitam arquivos de conhecimento personalizados. Construído em Python, roda em qualquer lugar — localmente, em Docker ou como integração MCP.
Requisitos
- Python 3.11+ (para uso local) ou Docker
- Uma instância do Home Assistant com um token de acesso de longa duração
- Crie um no seu perfil do HA: Configurações → Segurança → Tokens de acesso de longa duração
- Acesso ao diretório de configuração do seu Home Assistant (para ferramentas de sistema de arquivos)
Início Rápido
1. Configure o ambiente
cp .env.example .env
Edite o .env com suas credenciais:
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: O arquivo .env contém seu token de acesso. Ele está no gitignore e nunca deve ser commitado.
2. Execute com Docker
Primeiro, configure suas credenciais. Use um arquivo .env (recomendado) ou passe as variáveis diretamente.
Opção A — com arquivo .env e docker compose:
cp .env.example .env
# edit .env with your HA_URL and HA_TOKEN
docker compose up -d
O docker-compose.yml incluído puxa a imagem do GitHub Container Registry e monta sua configuração do HA somente leitura:
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"]
Opção B — com docker run simples:
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
Compilando localmente:
docker build -t ha-mcp-readonly .
docker compose -f docker-compose.build.yml up -d
3. Execute localmente (Python 3.11+)
pip install -r requirements.txt
HA_URL=http://localhost:8123 HA_TOKEN=your_token python server.py
Portas
| Porta | Protocolo | Finalidade | Endpoint |
|---|---|---|---|
| 9091 | HTTP | Verificação de saúde | GET /health |
| 9092 | HTTP | MCP HTTP Streamable autenticado | /mcp |
| 9093 | HTTP | API REST autenticada opcional + Gerador de Contexto | /api/* |
Verifique
# 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.
Ferramentas Disponíveis (158 com ferramentas de desenvolvimento, 145 sem)
As ferramentas são organizadas por categoria (75 mostradas na tabela abaixo). Todas são somente leitura — sem mudanças de estado, sem chamadas de serviço, sem modificações.
| Categoria | Ferramentas principais |
|---|---|
| Estados | get_entity_state, get_states_grouped, search_entities, get_domains_summary, get_system_overview |
| Automações | list_automations, get_automation_code, get_automation_file_location, diagnose_automation, search_automations_by_entity, get_automation_conflicts, get_automation_entity_id |
| Scripts e Cenas | 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 e Áreas | get_device_details, search_devices, get_devices_by_area, get_area_devices_summary |
| Entradas de configuração | get_config_entry_details, search_config_entries, diagnose_config_entry, list_config_entry_domains |
| Integrações | get_integration_entities, get_integration_summary |
| Diagnósticos | diagnose_system_health, get_unavailable_entities_grouped, get_integration_health, diagnose_person_tracking |
| Logs | get_log_insights, analyze_log_errors, get_startup_errors, get_log_timeline, search_logs |
| Histórico | get_entity_state_history_summary, get_recent_state_changes |
| Contexto | entity_get_context_tree, get_entity_dependencies, get_entity_consumers, get_context_chain |
| Configuração | get_main_configuration, search_in_config, validate_yaml_syntax, read_config_file |
| Armazenamento | 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 |
| Composto | 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 |
| Ferramentas de desenvolvimento | test_template, compare_templates, diagnose_entity, check_entity_exists, validate_automation_trigger, diagnose_template |
Catálogo completo de ferramentas com schemas disponível em GET /api/tools
Novidades na v2.0.0
- Quebra — limpeza de transporte: Removido o transporte legado HTTP+SSE de dois endpoints. Os transportes MCP suportados agora são apenas stdio e Streamable HTTP;
MCP_TRANSPORT=sseé rejeitado. - Implantação de rede endurecida: Aplicação ASGI explícita com limites de tamanho de requisição/cabeçalho, política de Host confiável (
MCP_ALLOWED_HOSTS), CORS de origem exata, limites de conexão e seleção de modo stateless/stateful. - Redação recursiva de credenciais: Todas as respostas de ferramentas são sanitizadas na fronteira da operação — bearer tokens, JWTs, chaves de API, senhas e endereços IP são redigidos tanto nos payloads de resposta quanto na saída de logs.
- Descoberta de capacidades: A descoberta pública agora separa transportes/componentes suportados e ativos e reporta identidade do servidor, SDK, protocolo e perfil de implantação.
- Correções de confiabilidade: Correção de desempenho do
diagnose_automation_aliases(>120s para ~4.5s em uma instância com 131 automações); sondas de saúde do backend com novas tentativas na inicialização e reconciliação em segundo plano; corrotinas de armazenamento bloqueantes executadas através do executor de invocação limitado. - Verificação e evidência: O alinhamento com ai-skills usa um validador fixado e testes de cassete gravados em Home Assistant real. CI hospedada com head exato verifica 1.234 testes de unidade, 17 testes de protocolo, o wheel instalado e artefatos de contêiner amd64/arm64. Evidência de HA ao vivo vinculada a revisão é documentada separadamente em
docs/evidence-live-27d32c9b.mde se aplica apenas à revisão nomeada ali.
Também mantido da v1.6.0
- 5 ferramentas:
get_context_chain,resolve_blueprint_automation,get_cache_stats,compare_templates,get_automation_entity_id - Paginação de registros (
limit/offsetemget_entity_registry,get_device_registry,get_area_registry,get_config_entries) - Campo
data_qualityem ferramentas de diagnóstico compostas choose_analysisemdiagnose_automation(detail_level="full")
Configuração do cliente
Stdio local
Instale o wheel e configure o cliente para iniciar o servidor como um subprocesso. Este é o transporte padrão e não expõe uma porta de rede 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
Defina MCP_TRANSPORT=http, MCP_AUTH_TOKEN e um endereço de bind controlado. O endpoint é /mcp. O suporte legado a /sse foi removido e MCP_TRANSPORT=sse é rejeitado.
{
"mcpServers": {
"ha-mcp-readonly": {
"url": "http://127.0.0.1:9092/mcp",
"headers": {
"Authorization": "Bearer replace-with-a-high-entropy-caller-token"
}
}
}
}
O catálogo padrão contém 145 ferramentas somente leitura. Ferramentas exclusivas para desenvolvedores permanecem desabilitadas a menos que MCP_DEV_TOOLS_ENABLED=1 esteja definido.
Gerador de Contexto
O gerador de contexto cria um snapshot Markdown limitado para análise offline, sistemas de recuperação, conhecimento de projetos de IA, auditorias e solução de problemas.
| Modo | Acesso a dados |
|---|---|
offline | Apenas configuração local do Home Assistant e registros de armazenamento seguro. O acesso à rede é desabilitado por construção. |
online | APIs REST e WebSocket do Home Assistant. A falta de acesso de rede necessário falha a execução. |
hybrid | Fontes locais mais todas as fontes de API suportadas disponíveis para o token configurado. |
O artefato inclui as seções normais de análise e uma matriz de Proveniência e Completude de Fontes. Cada fonte tentada registra seu método, status, contagem de registros, contagem de bytes, contagem de redações, janela solicitada e motivo de falha ou omissão. O Snapshot Abrangente de Dados Seguros inclui todos os dados suportados e acessíveis dentro dos limites configurados:
- estados, serviços, componentes, eventos, configuração, histórico, logbook, log de erros, calendários e eventos de calendário;
- dados de entidade, dispositivo, área, piso, rótulo, categoria, entrada de configuração, energia, painel, recurso Lovelace, reparo, saúde do sistema e pipeline Assist expostos pelo Home Assistant;
- itens de tarefas e todos os tipos de previsão do tempo anunciados descobertos dinamicamente a partir dos estados das entidades;
- todos os registros seguros descobertos de
.storagemais dados de inventário YAML, JSON e arquivos sob a raiz configurada; - análise de automação, script, cena, blueprint, template, helper, pessoa, zona, energia, HACS, cache, dependência, painel e diagnóstico.
Armazenamentos de credenciais são excluídos. Campos sensíveis, bearer tokens, JWTs, parâmetros de consulta secretos e valores de !secret são redigidos. Mídia binária, streams de câmera, conteúdos de backup, bancos de dados e registros com credenciais não são copiados. Fontes indisponíveis devido a permissões, integrações ausentes, comandos não suportados, janelas configuradas ou limites de tamanho permanecem visíveis na proveniência em vez de serem omitidas silenciosamente.
Limites relevantes são HA_CONTEXT_HISTORY_HOURS, HA_CONTEXT_LOG_HOURS, HA_CONTEXT_CALENDAR_DAYS, HA_CONTEXT_MAX_SOURCE_BYTES e HA_CONTEXT_MAX_OUTPUT_BYTES.
Geração com orçamento consciente
O gerador pode limitar a saída na fonte em vez de emitir tudo e deixar os consumidores reduzirem. As opções estão disponíveis através do ambiente (HA_CONTEXT_PROFILE, HA_CONTEXT_SECTIONS, HA_CONTEXT_DETAIL, HA_CONTEXT_INCLUDE_FILES, HA_CONTEXT_INCLUDE_STORAGE, HA_CONTEXT_ON_BUDGET_EXCEEDED) e através da chamada REST de geração:
| Opção | Valores | Padrão | Efeito |
|---|---|---|---|
profile | full, agent, compact | full | Predefinição de seção. full renderiza tudo (comportamento histórico); agent remove as seções pesadas de snapshot bruto, log e mudanças recentes; compact renderiza apenas resumo, proveniência, saúde do sistema, topologia e referência rápida. |
maxBytes | inteiro ≥ 1024, ≤ 128 MiB | HA_CONTEXT_MAX_OUTPUT_BYTES (96 MiB quando não definido) | Orçamento de bytes de saída. Omitir maxBytes herda o valor de ambiente configurado. Seções que não cabem são omitidas inteiras e reportadas. |
sections | chaves de seção ou aliases | padrão do perfil | Seleção explícita que substitui o perfil. Aliases: runtime, health, provenance, logs. O resumo executivo e as seções de proveniência de fontes são sempre incluídos. |
repositoryFiles / include_files | booleano | true | Quando false, o snapshot bruto abrangente não coleta nem serializa corpos de arquivos de configuração. Seções de análise estruturada (registros, automações, dispositivos) permanecem como visualizações de metadados derivados e não são afetadas. |
storageRecords | booleano | true | Quando false, o snapshot bruto abrangente não coleta registros seguros de .storage. |
detail | full, compact | full | Alias que resolve para profile=compact quando nenhum perfil explícito é fornecido. |
onBudgetExceeded | auto, fail, truncate | auto | Política resolvida: auto se comporta como fail para o perfil full (preservando a execução histórica com falha fechada) e como truncate para agent/compact; fail/truncate explícitos sempre vencem. |
Os padrões das opções REST são resolvidos pela camada REST conforme mostrado; eles não herdam seus padrões não booleanos das variáveis de ambiente correspondentes — apenas maxBytes recorre ao seu valor de ambiente.
O resultado da geração reporta output_bytes, uncompressed_bytes, output_sha256, profile, requested_sections (a seleção original resolvida), selected_sections (a seleção efetiva incluindo o piso obrigatório), rendered_sections, omitted_sections (com tamanhos exatos de bytes por seção e motivos) e truncated. Desabilitar arquivos de repositório ou registros de armazenamento registra uma omissão explícita de policy: na matriz de proveniência — nada é omitido silenciosamente. O resumo executivo e as seções de proveniência de fontes são sempre renderizados, inclusive sob seleções explícitas de seção, para que todo artefato carregue seu registro de completude.
A identidade de origem e de runtime é transportada por campos de resultado dedicados: config_path identifica a raiz de configuração do Home Assistant auditada (identidade de origem), enquanto mode, profile_revision e generated_at identificam as condições de runtime que geraram o artefato (identidade de runtime); output_sha256 fixa os bytes exatos do artefato. Os consumidores podem, portanto, sempre atribuir um artefato ao estado da instância e à revisão do gerador que o produziu.
Instâncias vazias são um caso de sucesso: uma geração sobre uma instância válida, mas com zero registros, é concluída normalmente, renderiza seções com contagem zero e reporta contadores zerados com truncated: false. Apenas opções inválidas, violações de orçamento sob a política de falha ou dados obrigatórios indisponíveis fazem a execução falhar.
Duas decisões de design deliberadas, registradas para os consumidores da issue #33: agent é a visão operacional limitada destinada ao consumo por agentes, enquanto o padrão da API permanece o perfil histórico full para compatibilidade retroativa — os chamadores optam explicitamente pela visão limitada. A truncagem é aplicada na granularidade de seção inteira e reportada explicitamente; a truncagem parcial de conteúdo (no meio da seção) nunca é aplicada silenciosamente, então o contrato mapeia como included_sections → rendered_sections, truncated_sections → omitted_sections e bytes → output_bytes.
Nota de segurança: os exemplos acima são apenas de loopback. Quando o adaptador REST for exposto por meio de um proxy reverso remoto, encerre o TLS no proxy e exija HTTPS dos clientes — HTTP simples transmite o token de portador em 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
O adaptador de compatibilidade REST opcional está desabilitado por padrão. Quando habilitado, todas as rotas, exceto health, exigem um token de portador e usam a mesma política de manifesto, capacidade, prazo, concorrência, tamanho de resposta e erro que o 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
Desenvolvimento
Configuração
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
Executar testes
# 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
Testes dependentes do backend relatam pulos quando o ambiente Home Assistant necessário está ausente. A CI instala o wheel em um ambiente limpo, executa um subprocesso stdio real e verifica health, metadados REST, o ciclo de vida do contexto offline e Streamable HTTP autenticado contra contêineres de release construídos. O fluxo de trabalho de release separadamente constrói um candidato multi-plataforma em quarentena, testa o digest exato em amd64 e arm64 e promove apenas esse digest do publicador protegido.
Lint e formatação
ruff check .
ruff format --check .
Arquitetura
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)
Segurança
- Somente leitura por design — nenhuma operação de escrita no Home Assistant. Não pode modificar estados, executar serviços ou acionar automações.
- Restrições de sistema de arquivos — acesso limitado ao diretório
/config. Travessia de caminho (..,~) bloqueada. Tamanho máximo de arquivo 10MB. Profundidade máxima de diretório 20. - Dados de autenticação bloqueados — registros de
auth,auth_provider.*,onboardingnunca são retornados. - Redação de credenciais —
HA_TOKENnunca é registrado ou exposto nas saídas. JWTs, senhas, chaves de API e endereços IP são sanitizados da saída de log.
Notas
- O servidor pode expor 9091 (health), 9092 (Streamable HTTP MCP autenticado) e 9093 (adaptador REST/contexto autenticado opcional). Stdio permanece o transporte MCP padrão.
MCP_DEV_TOOLS_ENABLED=0desabilita a execução de templates e ferramentas de depuração para uso em produção.- Nota de segurança: As portas 9091-9093 não devem ser expostas publicamente. Use regras de firewall ou proxy reverso com autenticação, se necessário.
- Arquivos de registro (áreas, dispositivos, entidades, entradas de configuração) são armazenados em cache por 5 minutos para reduzir I/O do sistema de arquivos.
- Todas as respostas de ferramentas retornam JSON com um campo
success— sempre verifique isso antes de lerdata.
Solução de problemas
Para problemas comuns e soluções, consulte docs/documentation.md#troubleshooting.
Licença
MIT — consulte LICENSE para detalhes.