Vaultbeat MCP Server
Let your own AI agent read your health data — without the cloud ever seeing it.
⚠️ Skip the
pip install vaultbeat-mcpbox PyPI puts at the top of this page. Every PyPI package page gets one automatically — it isn't a recommendation. Useuvxfrom Quick Start below: no separate install step, and with@latestit always runs the current release. A barepip install(or a bareuvxwithout@latest) gets pinned to whatever was current the moment you ran it and will not update itself.
This is the official local MCP server for Vaultbeat — AI Health Sync (formerly named Tether), the iOS app that syncs Apple Health data (sleep, heart rate, menstrual cycle, weight, water, symptoms) between partners and to your own AI — end-to-end encrypted.
Vaultbeat embeds no AI and runs no model on your phone. Intelligence lives where you control it: Claude Code, Claude Desktop, or any MCP-capable agent running on your own machine. This server is the bridge — it holds a private key that never leaves your computer, pulls ciphertext from the cloud, and decrypts only locally.
iPhone (Apple Health) ──E2EE──▶ cloud (ciphertext only) ──E2EE──▶ this server (your machine) ──▶ your AI agent
Requirements
- Vaultbeat — AI Health Sync on iOS, with a Pro subscription (the AI-agent interface is the Pro tier)
- Python 3.11+ on the machine where your agent runs (macOS / Linux / Windows)
Quick start
1. Install
With uv (recommended — no clone needed):
uvx vaultbeat-mcp@latest status
The @latest matters: without it, uvx only fetches the newest version the
first time you run the tool on a machine, then reuses its local cache on
every run after that — same as pip, which never updates once installed.
Keep @latest on every command below.
Or with pip (installs once, at whatever version is current right now — run
pip install --upgrade vaultbeat-mcp yourself to pick up new releases):
pip install 'vaultbeat-mcp[qr]'
Upgrading from the old
tether-mcppackage? Same code, new name — your existing binding and config carry over unchanged. Just swap the package name in your install command and MCP client config.
2. Bind your phone
uvx vaultbeat-mcp@latest bind
bind is the command that draws the QR code, and it waits while you scan.
serve (step 3) prints nothing at all — it is the stdio protocol loop — so
don't start that one first and sit waiting for a code.
(The [qr] extra was required until 0.3.10, which made qrcode a hard
dependency. The extra is still declared, empty, so older published commands
keep resolving; you no longer need it.)
This generates a keypair on your machine and prints a QR code. In the Vaultbeat iOS app, open Settings → Data & AI → Connect an AI server and scan it (or import a QR screenshot from Photos). The app authorizes this machine and starts sealing your health envelopes to its public key. The private key stays in ~/.tether/mcp-local/ (owner-only 0600 permissions, OS keychain where available) — it is never uploaded anywhere. (The directory keeps its original pre-rename path so existing bindings survive upgrades.)
3. Connect your agent
Claude Code (one line):
claude mcp add vaultbeat-health -- uvx vaultbeat-mcp@latest serve --transport stdio
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"vaultbeat-health": {
"command": "uvx",
"args": ["vaultbeat-mcp@latest", "serve", "--transport", "stdio"]
}
}
}
Any other MCP client: run uvx vaultbeat-mcp@latest serve --transport stdio, or --transport http for a loopback streamable-HTTP endpoint with bearer-token auth.
Claude Desktop note: it does not inherit your shell
PATH. Ifuvxisn't found, use the absolute path (which uvx) ascommand.
Debugging: npx @modelcontextprotocol/inspector uvx vaultbeat-mcp@latest serve --transport stdio
Then just ask your agent: “How did we sleep last night?”
MCP tools (26)
| Tool | Returns |
|---|---|
vaultbeat_status | Local binding state (never exposes keys or tokens) |
vaultbeat_doctor | Full self-diagnosis: install/binding chain plus which data types have data and which need a newer iOS build — call this before concluding data is missing |
vaultbeat_start_binding | A fresh QR binding payload for the iOS app to scan |
vaultbeat_poll_binding | One poll for the iOS authorization to complete binding |
vaultbeat_sync_sleep | Recent sleep sessions incl. heart-rate samples, per-day primary-session selection matching the iOS app |
get_sleep_detail | Per-night heart-rate + respiratory-rate + sleep-stage timeline |
get_water_intake | Daily water intake + computed daily average |
get_weight_trend | Daily weights + latest/avg/min/max + weekly trend rate, plus body composition (body_fat_percent 0–100, bmi, lean_body_mass_kg) when a smart scale wrote it into Apple Health |
get_menstrual_cycle | Cycle samples + next-period prediction (sensitive — explicit iOS opt-in required) |
get_symptoms | HealthKit symptom days grouped by data owner (sensitive) |
get_notes | Free-text day annotations with their writer (sensitive) |
get_activity | Daily activity rings: steps / energy / exercise minutes / stand hours / distance |
get_resting_hr | Resting heart-rate records + window mean |
get_workouts | Workout records: type / duration / calories / distance |
get_mindfulness | Mindful sessions and minutes per day |
get_hrv | Heart-rate variability (SDNN) records + window mean |
get_wrist_temp | Sleeping wrist-temperature baseline deviation |
get_hrv_hourly (via get_hrv(granularity="hourly")) | Hour-bucketed HRV averages over 30 days — the context-cheap default; granularity="raw" keeps minute-level spike precision |
get_vo2max | VO₂ max records + latest / peak / trough / window average |
get_basal_energy | Basal (resting) energy burned, per hour bucket |
get_total_energy_burned | TDEE — basal + active per day, measured rather than estimated, with today flagged partial and excluded from the average |
get_strength_log | Structured strength training: exercise, sets, reps, weight per day |
get_food_log | Meals as free text with optional portions and timing |
log_weight_entry | Write a weight entry (optionally mirrored into Apple Health when the user opts in). Carries over that day's existing body composition instead of erasing it — an agent cannot supply fat/BMI/lean mass, so a bare weight log must not wipe what the scale recorded |
log_strength_entry | Write a strength-training entry for a given day (merge=True to append) |
log_food_entry | Write a meal entry for a given day (merge=True to append) |
log_note | Write a mood or general note for a given day (merge=True to append) |
⚠️ The three
log_*write tools replace the WHOLE DAY by default. Passing only what you want to add will delete everything else recorded for that day. Passmerge=Trueto append instead — that is almost always what you want when adding to a day that already has data. Every write returns areplaced_*field naming exactly what it deleted, so an agent can notice and re-send. Since 0.2.4; before that the deletion was silent and there was no merge mode.
Every data tool accepts owner (a user-ID prefix) to filter to one person — the server may hold both your and your partner's shared records, and omitting owner mixes them into one pool, so per-person questions should always pass it. (Earlier releases named some tools get_partner_* / tether_*; they were renamed in the 16-tool and Vaultbeat releases.)
Reads are cache-first: decrypted records are cached locally (owner-only files, 600 s TTL, VAULTBEAT_MCP_CACHE_TTL to override — the pre-rename TETHER_MCP_* spellings still work) so repeat queries answer in ~0.2 s with zero network; pass fresh=true to force a cloud round trip. The same service layer backs a full CLI (uvx vaultbeat-mcp@latest sleep / water / weight / … — every data subcommand takes --owner too) if you prefer scripts over MCP.
Privacy & security model
- End-to-end encryption: Curve25519 ECDH + HKDF-SHA256 + AES-GCM. Every health record is sealed on-device to each authorized recipient's public key (your partner, and this server once bound).
- The cloud only ever holds ciphertext. Vaultbeat's backend cannot read your health data — architecturally, not just by policy.
- Decryption happens here, on hardware you own. The private key and server token are never exposed through any tool result.
- Sensitive kinds (menstrual cycle, symptoms, notes) reach this server only if explicitly opted in inside the iOS app, and are never re-exported by the server.
- HTTP transport binds to loopback by default and requires a bearer token; binding a non-loopback address fails closed unless explicitly allowed — front it with TLS if you must expose it.
You can audit all of the above in this repository — that is why it is open source.
Development
pip install -e '.[dev,qr]'
pytest
License
MIT. The Vaultbeat iOS app and cloud service are separate proprietary components; this repository covers the local MCP server only.
Website: vaultbeat.app · App Store: Vaultbeat — AI Health Sync · Bugs & feedback: vaultbeat-community