Content
# HealthMirror MCP
**English** · [简体中文](./README.zh.md)
A local [MCP](https://modelcontextprotocol.io) server that exposes your own Apple
Health data — exported to iCloud Drive by the **HealthMirror** iOS app — to AI
tools running on your Mac (e.g. Claude).
It reads the JSONL files HealthMirror writes into its iCloud container and answers
structured queries (sleep, heart-rate metrics, workouts, a daily recovery summary).
Your health data never leaves your machine: the server runs locally, has no network
access, and only returns query results to the MCP client you connect.
- **iOS app:** [HealthMirror: Auto Sync on the App Store](https://apps.apple.com/app/id6779814305)
- **Privacy Policy:** [English](./PRIVACY.md) · [简体中文](./PRIVACY.zh.md)
- **Support:** [English](./SUPPORT.md) · [简体中文](./SUPPORT.zh.md)
## How it works
```
iPhone HealthKit
↓ HealthMirror iOS app (reads HealthKit, writes JSONL)
iCloud Drive container: iCloud.com.mlyz.HealthBridge
↓ macOS iCloud auto-sync
~/Library/Mobile Documents/iCloud~com~mlyz~HealthBridge/Documents/
↓ this MCP server (reads JSONL, runs queries)
Claude / any MCP client
```
The server is read-only over your data and makes no outbound network requests
(enforced by a sandbox profile — see [Security model](#security-model)).
## Requirements
- macOS (Apple Silicon or Intel).
- The [**HealthMirror**](https://apps.apple.com/app/id6779814305) iOS app installed on
your iPhone with iCloud sync enabled, so health data has synced down to this Mac.
Without the app there is no data to read.
- [uv](https://docs.astral.sh/uv/) — `brew install uv`.
- Python ≥ 3.12 (uv can install this for you).
## Install
```bash
git clone https://github.com/mlyxz/healthmirror-mcp.git
cd healthmirror-mcp
uv sync
```
Confirm your health data has actually synced to this Mac — this folder should exist
and contain per-metric subfolders:
```bash
ls ~/Library/Mobile\ Documents/iCloud~com~mlyz~HealthBridge/Documents/raw/
```
If it's missing or empty, open the HealthMirror app on your iPhone, let it finish
syncing, and make sure iCloud Drive is enabled on this Mac.
### Smoke test (no sandbox)
Confirm dependencies resolve and the server starts:
```bash
uv run health-bridge-mcp
```
It speaks the MCP protocol over stdio and waits for a client, so you'll see no
visible output. If it starts without an import error, you're good — press Ctrl+C
to exit.
## Register with Claude (recommended: sandboxed)
The repo ships `run-sandboxed.sh`, which launches the server inside a macOS
`sandbox-exec` profile that **denies all network access** and restricts writes to a
small allow-list. This is the recommended way to run it.
```bash
claude mcp add healthmirror /ABSOLUTE/PATH/TO/healthmirror-mcp/run-sandboxed.sh
```
Replace `/ABSOLUTE/PATH/TO/healthmirror-mcp` with the real path where you cloned the
repo. The wrapper resolves your home directory and the repo location automatically,
so you never have to edit absolute paths inside `sandbox.sb`.
To run **without** the sandbox (e.g. while debugging), register the plain command:
```bash
claude mcp add healthmirror -- uv run --directory /ABSOLUTE/PATH/TO/healthmirror-mcp health-bridge-mcp
```
Other MCP clients: launch `run-sandboxed.sh` as the server command; it communicates
over stdio.
> **`uv: command not found`?** GUI-launched MCP clients sometimes don't inherit your
> shell `PATH`. `run-sandboxed.sh` tries common install locations automatically; if it
> still fails, run `which uv` and use that full path. For **Claude Desktop**, point its
> MCP config JSON at `"command": "/ABSOLUTE/PATH/TO/healthmirror-mcp/run-sandboxed.sh"`.
## Tools
| Tool | What it does |
|---|---|
| `ping` | Liveness / connection check. |
| `get_sleep` | Sleep episodes (main sleep + naps), per-stage minutes, coverage. |
| `get_metric` | A quantity metric (`heart_rate`, `hrv_sdnn`, `resting_heart_rate`, `active_energy`, `steps`, `weight`) with aggregation, optional per-day buckets, and per-source breakdown. |
| `get_workouts` | Workout records with multi-source dedup, plus a per-type summary. |
| `get_daily_summary` | One-shot daily summary: recovery score, cycle phase, today's activity, last night's sleep. |
By default queries are limited to the last 30 days; pass `allow_historical=true` for
older data. Every tool call is appended as a line to
`~/Library/Application Support/HealthBridge/audit.log`, so you can see what the AI
queried (`tail -f` it). See [Security model](#security-model) for exactly what that
log records.
## Security model
- **No network.** The sandbox profile denies all network access; the server cannot
exfiltrate data. This is the primary protection.
- **Writes are allow-listed.** Only the HealthMirror app-support directory, the cloned
repo's own venv/bytecode cache, and Python temp are writable.
- **Reads are not sandbox-restricted** (macOS needs broad read access to load), but the
server code only reads your local HealthMirror data — and with the network blocked, a
read can't go anywhere.
- **Audit log.** Each call appends tool name, params, and a small result summary to a
local log — result counts and a few derived figures (e.g. the daily recovery score),
never the raw health samples.
`sandbox-exec` is marked deprecated by Apple but remains functional on current macOS.
## Why two names?
The product and this repository are named **HealthMirror**. The Python package and
module keep the original development codename **`health_bridge`** (distribution
`health-bridge-mcp`, import `health_bridge_mcp`), and the iCloud container ID is
`iCloud.com.mlyz.HealthBridge`. These identifiers were frozen early to avoid
disrupting a working data pipeline, so they intentionally differ from the product
name. Functionally it's all the same project.
## Maintainer
Developed by Xiao Zhang, publishing as [@mlyxz](https://github.com/mlyxz) on GitHub.
Contact: support@mlyz.me
## License
[MIT](./LICENSE)