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 o uvx baixa 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

FerramentaO que ela faz
vaultbeat_doctorDiagnosticar 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

FerramentaO que ela retorna
get_sleep_nights parceiroCada 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 parceiroUma 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 parceiroAmostras do ciclo e uma previsão da próxima menstruação. Sensível.
get_symptoms parceiroSintomas 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 parceiroNotas de texto livre em dias, com quem as escreveu. Sensível.
get_strength_logSessões de força: exercícios, séries × repetições, volume por sessão.
get_food_logRefeiçõ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_workoutsTreinos: tipo, duração, calorias, distância.
get_user_profileSexo, idade, data de nascimento e altura. Requer Vaultbeat para iOS 1.2.9 ou versões posteriores.

Números diários e análise

FerramentaO que ela retorna
get_metric parceiroValores 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_intradayAmostras 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 parceiroCada nome de série que as ferramentas acima e abaixo aceitam, com sua unidade e quantos dados a sustentam.
get_metric_trend parceiroInclinação de mínimos quadrados, pontos finais, média / mediana / mín / máx.
compare_metric_periods parceiroOs N dias mais recentes contra os N anteriores, ou duas janelas nomeadas.
correlate_metric_series parceiror 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.

FerramentaO que ela faz
log_food_append / log_strength_append / log_note_appendAdicionar 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_noteSubstituir todo aquele dia pelo que é passado e informar exatamente o que foi removido.
log_weight_entryRegistrar uma pesagem, mantendo a composição corporal daquele dia.
log_symptomRegistrar 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_symptomAlterar 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: true significa que registros mais antigos existem e seu limit parou antes deles (oldest_available diz 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_large com uma sugestão para restringir a solicitação (um limit menor, uma data since, uma série em vez de todas). get_metric e get_intraday retornam 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:

  1. 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;
  2. o chaveiro do sistema — o caso normal em um desktop;
  3. ~/.tether/mcp-local/identity.key, modo 0600 — 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.json para "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, execute bind novamente: 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).