Vaultbeat — Apple Health MCP
Dados do Apple Health criptografados de ponta a ponta para seu próprio agente de IA — sono, VFC, frequência cardíaca, treinos, ciclo. Sincronização em segundo plano do iPhone, descriptografados localmente.
Documentação
Servidor MCP Vaultbeat Apple Health
Seus dados do Apple Health — estágios do sono, ciclo, VFC, frequência cardíaca em repouso, treinos, peso, VO₂ máx, refeições, levantamentos, notas, sintomas — legíveis e graváveis pelo seu próprio agente de IA (Claude Code, Claude Desktop, Codex, Hermes, OpenClaw, qualquer coisa que fale MCP), criptografados de ponta a ponta para que apenas sua máquina veja o texto simples.
O aplicativo para iPhone Vaultbeat lê o HealthKit e criptografa cada registro no telefone. Este pacote é o servidor local com o qual seu agente conversa: ele baixa o texto cifrado, descriptografa na sua máquina e o serve via MCP.
iPhone (HealthKit → Vaultbeat app, encrypts) ──► cloud (ciphertext only) ──► this server (decrypts locally) ──MCP──► your agent
A nuvem armazena texto cifrado que não consegue ler. A chave que o abre é gerada na sua máquina quando você faz o pareamento e nunca sai dela.
Requisitos
- O aplicativo iOS Vaultbeat, versão 1.2.3 ou mais recente, conectado — App Store
- uv (para
uvx). O servidor precisa de Python 3.11+ e ouvxbaixa um interpretador adequado por conta própria se o Python do seu sistema for mais antigo. - Vaultbeat Pro para acesso do agente. Parear uma máquina inicia um teste de 3 dias da interface de IA; depois disso, leituras e gravações precisam do Pro, comprado no aplicativo iOS (Configurações → Assinatura). Quando o acesso expira, nada é excluído, e comprar o Pro retoma esta máquina sem precisar parear novamente.
A quantidade de histórico que este servidor pode ler é decidida pelo que o aplicativo envia. Com o Pro, é todo o seu histórico. Um teste envia todo o seu histórico no aplicativo 1.2.9 e versões posteriores, e seus últimos 7 dias nas versões 1.2.8 e anteriores. Sem nenhum dos dois, o aplicativo 1.2.8 e versões anteriores envia seus últimos 7 dias e o aplicativo 1.2.9 e versões posteriores não envia nada. Portanto, um histórico curto geralmente é um limite do plano, não um atraso de sincronização — o vaultbeat_doctor distingue as causas.
Início rápido
1. Pareie esta máquina com seu iPhone.
uvx vaultbeat-apple-health@latest bind
Ele imprime um código QR e aguarda. No aplicativo Vaultbeat, abra aba MCP → Conectar um servidor de IA (aplicativo 1.2.8 e versões anteriores: Configurações → Dados e IA) e escaneie-o. O comando aguarda 5 minutos (--timeout para alterar); depois de escaneado, há 10 minutos para concluir.
2. Adicione o servidor ao seu cliente MCP.
Claude Code:
claude mcp add vaultbeat-health -- uvx vaultbeat-apple-health@latest serve --transport stdio
Claude Desktop — adicione a claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json) e reinicie-o:
{
"mcpServers": {
"vaultbeat-health": {
"command": "uvx",
"args": ["vaultbeat-apple-health@latest", "serve", "--transport", "stdio"]
}
}
}
O Claude Desktop não herda o PATH do seu shell. Se ele informar que uvx não pode ser encontrado, coloque o caminho absoluto de which uvx em "command".
Qualquer outro cliente MCP: execute uvx vaultbeat-apple-health@latest serve --transport stdio como um servidor stdio. O @latest importa — sem ele, o uvx continua executando a versão que armazenou em cache primeiro.
3. Verifique se funciona. Peça ao seu agente para chamar vaultbeat_doctor, ou execute:
uvx vaultbeat-apple-health@latest doctor
Ele verifica a configuração, a chave privada, a acessibilidade da nuvem, o pareamento e um ciclo real de busca e descriptografia, e lista quais tipos de dados ainda não têm nada para ler. Logo após o pareamento, o telefone ainda está selando seu histórico para a nova máquina, então alguns tipos podem ficar vazios por um tempo; aba MCP → Ressincronizar todos os dados de saúde para a IA no aplicativo (aplicativo 1.2.8 e versões anteriores: Configurações → Dados e IA) acelera isso.
Experimente sem um iPhone
uvx vaultbeat-apple-health@latest --demo doctor
uvx vaultbeat-apple-health@latest --demo serve --transport stdio # wire this into a client
--demo é um sinalizador global — ele vai antes do subcomando — e serve um conjunto de dados sintéticos fixo: sem pareamento, sem nuvem, sem chave. Cada resultado diz demo_mode: true e carrega um banner [SYNTHETIC DEMO DATA], e as ferramentas de gravação log_* recusam.
Ferramentas MCP
26 ferramentas. As leituras retornam seus próprios dados — da conta que pareou esta máquina. As ferramentas marcadas como parceiro também aceitam partner=true para ler o que seu parceiro escolheu compartilhar com você no aplicativo dele — sono, água e peso, e ciclo, sintomas e notas somente se ele ativou isso. As duas pessoas nunca são misturadas em um único resultado. Toda ferramenta de leitura aceita fresh=true para ignorar o cache local.
Diagnóstico
| Ferramenta | O que ela faz |
|---|---|
vaultbeat_doctor | Diagnosticar esta instalação de ponta a ponta, informar quais tipos de dados não têm dados e os motivos prováveis, e mostrar o estado do pareamento. A ferramenta a chamar antes de dizer a alguém que os dados dele estão faltando. |
Registros de saúde
| Ferramenta | O que ela retorna |
|---|---|
get_sleep_nights parceiro | Cada noite como uma linha compacta: horário de deitar e acordar, sono, profundo / REM / core / desperto, despertares, maior período ininterrupto de sono, frequência cardíaca e respiratória durante o sono, cochilos. Um ano cabe em uma única chamada; since="YYYY-MM-DD" para uma janela de calendário. |
get_sleep_detail parceiro | Uma ou duas noites em detalhes: intervalos de estágios com frequência cardíaca e respiratória por estágio. As noites mais recentes, ou qualquer noite por data (since / until). |
get_menstrual_cycle parceiro | Amostras do ciclo e uma previsão da próxima menstruação. Sensível. |
get_symptoms parceiro | Sintomas do Apple Health e, ao lado deles, os episódios que uma pessoa relatou (tipo, gravidade, início e fim, local, possíveis gatilhos). Sensível. |
get_notes parceiro | Notas de texto livre em dias, com quem as escreveu. Sensível. |
get_strength_log | Sessões de força: exercícios, séries × repetições, volume por sessão. |
get_food_log | Refeições e itens por dia, com kcal / proteína / gordura / carboidratos opcionais. Os 14 dias mais recentes que têm um registro por padrão (não uma quinzena de calendário), ou uma janela since / until. |
get_workouts | Treinos: tipo, duração, calorias, distância. |
get_user_profile | Sexo, idade, data de nascimento e altura. Requer Vaultbeat para iOS 1.2.9 ou versões posteriores. |
Números diários e análise
| Ferramenta | O que ela retorna |
|---|---|
get_metric parceiro | Valores por dia para uma série, várias ou todas: duração do sono, horário e estágios, FC em repouso, VFC, temperatura do pulso, VO₂ máx, peso e composição corporal, água, passos, energia ativa / basal / total, minutos de exercício e em pé, distância, atenção plena. aggregation (avg / sum / min / max / latest) e granularity (day / week / month / weekday) são calculados no lado do servidor; since / until para uma janela de calendário. Hoje em uma série acumulada é marcado como parcial e mantido fora dos agregados. |
get_intraday | Amostras dentro de um dia, para VFC: uma linha por hora que tem amostras (granularity="hourly") ou uma por amostra ("raw"). Cerca de 8–14 linhas por dia; limit conta as linhas. |
list_metric_series parceiro | Cada nome de série que as ferramentas acima e abaixo aceitam, com sua unidade e quantos dados a sustentam. |
get_metric_trend parceiro | Inclinação de mínimos quadrados, pontos finais, média / mediana / mín / máx. |
compare_metric_periods parceiro | Os N dias mais recentes contra os N anteriores, ou duas janelas nomeadas. |
correlate_metric_series parceiro | r de Pearson entre duas séries ao longo dos dias que têm ambas; lag_days pareia um dia com um posterior. |
As ferramentas de análise retornam apenas números — sem pontuações, notas ou veredictos — e recusam em vez de ajustar uma linha a dois pontos.
Gravações — todas na conta que pareou esta máquina, e em nenhum outro lugar.
| Ferramenta | O que ela faz |
|---|---|
log_food_append / log_strength_append / log_note_append | Adicionar a um dia. Não pode excluir nada — o padrão seguro quando um dia pode já ter registros. |
log_food_entry / log_strength_entry / log_note | Substituir todo aquele dia pelo que é passado e informar exatamente o que foi removido. |
log_weight_entry | Registrar uma pesagem, mantendo a composição corporal daquele dia. |
log_symptom | Registrar um sintoma que a pessoa relata, como campos estruturados que uma leitura posterior pode comparar com sono, comida e frequência cardíaca. |
update_symptom / delete_symptom | Alterar um sintoma relatado (geralmente seu horário de término) ou apagar um registrado por engano. |
log_note e log_note_append aceitam partner=true para registrar uma nota sobre seu parceiro. Ela fica na sua própria conta, nunca é enviada a ele e é mantida separada das suas próprias notas.
Lendo os resultados
- Toda leitura carrega um bloco
coverage.days_coveredé quantos dias distintos a resposta se baseia — cite-o ao lado de qualquer média ou tendência.more_available: truesignifica que registros mais antigos existem e seulimitparou antes deles (oldest_availablediz até onde eles vão); nunca é um sinal de dados ausentes. - Os resultados são limitados. Um resultado maior que cerca de 60 KB não é enviado; a ferramenta retorna
result_too_largecom uma sugestão para restringir a solicitação (umlimitmenor, uma datasince, uma série em vez de todas).get_metriceget_intradayretornam suas linhas como uma tabela compacta (columns+rows). - Argumentos desconhecidos são rejeitados. Um parâmetro com erro de digitação ou descontinuado é um erro, nunca ignorado silenciosamente.
Prompts MCP
O servidor também serve oito prompts via prompts/list — daily_brief, sleep_review, energy_balance, training_block_review, cycle_aware_read, partner_check_in, log_from_conversation e why_is_this_empty. Cada um nomeia as ferramentas a chamar e carrega as mesmas duas regras: diga o que os dados cobrem antes de concluir e trate um resultado vazio como algo a explicar (tem várias causas possíveis), nunca como um zero. Todo argumento é opcional.
Privacidade e segurança
- A descriptografia acontece apenas nesta máquina. A nuvem guarda texto cifrado e chaves embrulhadas por destinatário; a chave privada que as abre é gerada aqui quando você pareia.
- Os dados de saúde saem deste pacote apenas via MCP. Os subcomandos de linha de comando pareiam uma máquina, relatam sobre esse pareamento e iniciam o servidor; nenhum deles imprime dados de saúde.
- Categorias sensíveis. Seu ciclo e os sintomas que o Apple Health registra chegam a este servidor somente depois que você os ativa, por categoria, no aplicativo iOS — eles ficam desativados por padrão. Suas notas e os sintomas que você mesmo relata (no aplicativo, ou via
log_symptom) são sempre legíveis pelo seu próprio agente. Nenhum deles chega ao agente do seu parceiro a menos que você ative o compartilhamento com ele. - Desfaça o pareamento a qualquer momento na aba MCP do aplicativo (aplicativo 1.2.8 e versões anteriores: Configurações → Dados e IA); a máquina então não pode descriptografar nada novo.
- Os resultados das ferramentas nunca contêm a chave privada ou o token do servidor.
Onde a chave privada vive
Não em config.json. Ela é procurada nesta ordem:
- a variável de ambiente
VAULTBEAT_PRIVATE_KEY, se definida (lida, nunca gravada de volta) — para operadores que a injetam de um cofre de segredos; - o chaveiro do sistema — o caso normal em um desktop;
~/.tether/mcp-local/identity.key, modo0600— o fallback automático em uma máquina sem chaveiro.
~/.tether/mcp-local/config.json (modo 0600) guarda o token do servidor emitido pela nuvem e sua chave pública. .tether é o nome anterior do aplicativo e o caminho é mantido de propósito: instalações existentes encontram sua chave através dele.
Nunca exclua
config.jsonpara "começar do zero". A chave privada não está nele, então excluir não limpa uma chave ruim — isso cria uma nova identidade, e todo registro já criptografado para a antiga se torna permanentemente ilegível. Para reparar um pareamento, executebindnovamente: ele re-pareia esta máquina no lugar e mantém o que já está criptografado para ela.
Servidores headless. Se o chaveiro estiver inacessível, deixe o fallback identity.key lidar com isso — ele se ativa sozinho. Não defina PYTHON_KEYRING_BACKEND para o backend nulo: ele aceita gravações e não armazena nada, então apenas esconde um chaveiro que você talvez consiga alcançar. Se uma sessão D-Bus existir, mas este processo não puder vê-la (comum quando o servidor é iniciado por um framework de agente, systemd ou cron), passe DBUS_SESSION_BUS_ADDRESS explicitamente — resolva-o primeiro (echo "unix:path=/run/user/$(id -u)/bus") e coloque o resultado literal no bloco env do cliente, já que esse bloco é JSON, não um shell.
Telemetria
O servidor envia eventos de uso para o PostHog (UE): qual ferramenta foi chamada, se teve sucesso,
uma faixa de duração e as versões do cliente de IA e do pacote — vinculados à conta à qual esta máquina está
pareada. Argumentos de ferramentas, resultados e dados de saúde nunca são enviados. Defina VAULTBEAT_TELEMETRY=0
(ou DO_NOT_TRACK=1) para desativar. Detalhes: vaultbeat.app/privacy.
Solução de problemas
Comece com doctor. uvx vaultbeat-apple-health@latest doctor imprime uma lista [OK] / [FAIL] com uma correção para a primeira coisa que está quebrada; doctor --json é o mesmo relatório para um agente. Código de saída 0 significa saudável.
Uma leitura retorna curta ou vazia. Leia coverage.more_available primeiro: true significa que seu limit foi o limite — peça mais. false com um histórico curto é o limite do plano descrito em Requisitos, ou um pareamento que ainda está sendo preenchido. vaultbeat_doctor lista os tipos sem dados e as possíveis razões para cada um.
O código QR parece errado (mojibake ou linhas irregulares — geralmente Windows com uma página de código não UTF-8). O pareamento ainda está aguardando, então não execute novamente bind: isso substitui o código na tela. Em vez disso, renderize o payload JSON impresso logo acima do código como uma imagem (qrencode -o pair.png '<payload>'), envie para seu telefone e use importar de Fotos no scanner do aplicativo; ou execute chcp 65001 em um terminal novo; ou use bind --no-qr para o payload como texto.
Leituras falham com uma mensagem de acesso. A assinatura de teste ou Pro expirou. Nada foi excluído; comprar Pro no aplicativo iOS (Configurações → Assinatura) retoma esta máquina sem re-parear.
Transporte HTTP
Para clientes que se conectam por rede em vez de iniciar um subprocesso:
vaultbeat-apple-health serve --generate-token # mint and store a bearer token, print client config
vaultbeat-apple-health serve --transport http # 127.0.0.1:8000/mcp, bearer token required
O token é lido de VAULTBEAT_MCP_HTTP_TOKEN (preferido, mantém fora do histórico do shell) ou da configuração armazenada, e os clientes o enviam como Authorization: Bearer <token>. --show-token imprime o armazenado. --no-token serve loopback sem autenticação.
Vincular além do loopback (--host 0.0.0.0 para LAN ou VPS) falha de forma segura: requer tanto um token quanto --allow-remote. O token atravessa a rede em texto claro, então coloque TLS na frente dele (Caddy, nginx, Cloudflare). Outras flags: --sse-response para respostas estilo SSE, --stateful-http para clientes que precisam de sessões.
Exemplo mcp.json (estilo VS Code / Cursor):
{
"servers": {
"vaultbeat-health": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}
Um cliente que só fala stdio pode alcançar o servidor HTTP através de mcp-remote: npx -y mcp-remote http://127.0.0.1:8000/mcp --header "Authorization: Bearer <token>".
Relatando problemas
Este repositório aceita problemas tanto para o servidor MCP quanto para o aplicativo iPhone Vaultbeat —
falhas de instalação, erros de ferramentas, pareamento que nunca completa, doctor relatando
algo errado, e também problemas do aplicativo (UI, assinaturas, prompts de permissão do HealthKit,
sincronização que não aparece no telefone).
Abra um problema
e escolha o modelo que se encaixa. Perguntas e ideias podem ir em
Discussões.
Este é um repositório público: nunca cole dados de saúde, códigos de pareamento ou detalhes de conta.
Desenvolvimento
A linha de comando tem seis subcomandos, e nenhum deles lê dados de saúde:
vaultbeat-apple-health bind # pair this machine with the iOS app (QR)
vaultbeat-apple-health status # local pairing state
vaultbeat-apple-health doctor # self-diagnosis
vaultbeat-apple-health init # generate a keypair and config without pairing
vaultbeat-apple-health poll # poll once for a pending pairing
vaultbeat-apple-health serve # run the MCP server (stdio or http)
Registros descriptografados são armazenados em cache por tipo de dados em ~/.tether/mcp-local/cache/ (arquivos 0600, diretório 0700) por 600 segundos; VAULTBEAT_MCP_CACHE_TTL substitui isso (0 desativa). Após a primeira leitura, uma atualização baixa apenas os registros que mudaram. Parear com uma identidade de servidor diferente limpa o cache.
Execute as verificações a partir de um clone:
uv sync --frozen --all-extras
uv run --frozen pytest -q tests
uv run --frozen ruff check src tests
uv run --frozen mypy src
vaultbeat-mcp e vaultbeat-mcp-local permanecem como aliases de script de console para instalações de antes do pacote ser renomeado vaultbeat-apple-health (0.6.2).