health-export-mcp 1.7.2 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +22 -17
- package/README.md +66 -58
- package/events.mjs +267 -17
- package/glama.json +3 -3
- package/health-export.mcpb +0 -0
- package/healthstore.mjs +379 -29
- package/llms.txt +5 -4
- package/manifest.json +14 -6
- package/package.json +17 -54
- package/prompts.mjs +1 -1
- package/server.json +48 -8
- package/server.mjs +76 -20
- package/test/integration.mjs +18 -5
package/AGENTS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Copy-paste setup for every supported agent. The server is a single Node script (`server.mjs`,
|
|
4
4
|
zero dependencies). Point `HEALTH_DATA_DIR` at the folder that holds your exported
|
|
5
|
-
`.health-cache.json
|
|
5
|
+
`.health-cache.json` (on a Mac, since 1.7.3, the server finds the app's iCloud folder by itself when it's unset), by default the [MetricBridge](https://www.healthexport.dev) iOS app
|
|
6
6
|
([App Store](https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e)) writes it to your iCloud Drive container:
|
|
7
7
|
|
|
8
8
|
```
|
|
@@ -17,33 +17,38 @@ After configuring, restart the client and ask: **"Use health-export: what's my H
|
|
|
17
17
|
|
|
18
18
|
## Claude Code
|
|
19
19
|
|
|
20
|
-
One command, no clone:
|
|
20
|
+
One command, no clone, no environment variable on a Mac (1.7.3 finds the app's iCloud Drive folder itself):
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
claude mcp add --
|
|
24
|
-
--env "HEALTH_DATA_DIR=$HOME/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents" \
|
|
25
|
-
-- npx -y health-export-mcp
|
|
23
|
+
claude mcp add health-export -- npx -y health-export-mcp
|
|
26
24
|
```
|
|
27
25
|
|
|
28
|
-
|
|
26
|
+
Windows, Linux, or an export outside iCloud Drive:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
claude mcp add health-export --env "HEALTH_DATA_DIR=/path/to/folder" -- npx -y health-export-mcp
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Keep the double quotes if the path has a space. Add `--scope user` to use it in every project. No export yet: `claude mcp add health-export-demo -- npx -y health-export-mcp --demo` serves synthetic data. If Agent pairing is on, do not pass `PAIRING_SECRET` on the command line (shell history, `ps`); add it to the entry's `env` in the config file.
|
|
29
33
|
|
|
30
34
|
## Claude Desktop
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
Easiest: download [`health-export.mcpb`](https://github.com/PhilipAD/health-export-mcp/releases/latest/download/health-export.mcpb) and open it, or drag it into **Claude Desktop → Settings → Extensions**. Desktop runs it with its own Node, so there's no JSON and nothing to put on your PATH.
|
|
37
|
+
|
|
38
|
+
Or edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
33
39
|
|
|
34
40
|
```json
|
|
35
41
|
{
|
|
36
42
|
"mcpServers": {
|
|
37
43
|
"health-export": {
|
|
38
|
-
"command": "
|
|
39
|
-
"args": ["
|
|
40
|
-
"env": { "HEALTH_DATA_DIR": "~/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents" }
|
|
44
|
+
"command": "npx",
|
|
45
|
+
"args": ["-y", "health-export-mcp"]
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
48
|
}
|
|
44
49
|
```
|
|
45
50
|
|
|
46
|
-
|
|
51
|
+
On a Mac the server reads the app's iCloud Drive folder when `HEALTH_DATA_DIR` isn't set (1.7.3+). If Desktop logs `spawn npx ENOENT`, its PATH can't see Node (common with nvm or Homebrew): set `"command"` to the full path from `which npx`, or use the `.mcpb`. To pin a vetted local checkout instead, use `"command": "node", "args": ["/ABSOLUTE/PATH/TO/health-export-mcp/server.mjs"]`.
|
|
47
52
|
|
|
48
53
|
## Cursor
|
|
49
54
|
|
|
@@ -55,7 +60,7 @@ Run `node gen-deeplinks.mjs` and open the generated VS Code link, or add the ser
|
|
|
55
60
|
|
|
56
61
|
## opencode
|
|
57
62
|
|
|
58
|
-
`opencode.json` (project root) or `~/.config/opencode/opencode.json`:
|
|
63
|
+
`opencode.json` (project root) or `~/.config/opencode/opencode.json`. Drop the `environment` line on a Mac using iCloud Drive; for a pinned checkout use `["node", "/ABSOLUTE/PATH/TO/server.mjs"]`:
|
|
59
64
|
|
|
60
65
|
```json
|
|
61
66
|
{
|
|
@@ -63,9 +68,9 @@ Run `node gen-deeplinks.mjs` and open the generated VS Code link, or add the ser
|
|
|
63
68
|
"mcp": {
|
|
64
69
|
"health-export": {
|
|
65
70
|
"type": "local",
|
|
66
|
-
"command": ["
|
|
71
|
+
"command": ["npx", "-y", "health-export-mcp"],
|
|
67
72
|
"enabled": true,
|
|
68
|
-
"environment": { "HEALTH_DATA_DIR": "
|
|
73
|
+
"environment": { "HEALTH_DATA_DIR": "/path/to/folder" }
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
76
|
}
|
|
@@ -73,15 +78,15 @@ Run `node gen-deeplinks.mjs` and open the generated VS Code link, or add the ser
|
|
|
73
78
|
|
|
74
79
|
## OpenClaw
|
|
75
80
|
|
|
76
|
-
Add the `health-export` block (same shape as Claude Desktop's `mcpServers` entry) to your OpenClaw MCP servers config, then reload.
|
|
81
|
+
Add the `health-export` block (same shape as Claude Desktop's `mcpServers` entry: command `npx`, args `["-y", "health-export-mcp"]`, plus `HEALTH_DATA_DIR` off a Mac) to your OpenClaw MCP servers config, then reload.
|
|
77
82
|
|
|
78
83
|
## Hermes
|
|
79
84
|
|
|
80
|
-
Add the `health-export` block to your Hermes agent's MCP servers config, then restart the daemon.
|
|
85
|
+
Add the same `health-export` block to your Hermes agent's MCP servers config, then restart the daemon.
|
|
81
86
|
|
|
82
87
|
## Non-MCP clients, ChatGPT · Gemini · Grok · n8n · Home Assistant
|
|
83
88
|
|
|
84
|
-
|
|
89
|
+
ChatGPT connects only to remote MCP servers (OpenAI's help centre: "Can I connect to a local MCP server? Not directly", checked 2026-10-27), and the others don't run local MCP servers either, so they don't use this one. Instead, the [MetricBridge](https://www.healthexport.dev) app **POSTs your data to a webhook** (or your own endpoint) and your automation/agent reads that JSON. Every delivery is token-authenticated.
|
|
85
90
|
|
|
86
91
|
---
|
|
87
92
|
|
package/README.md
CHANGED
|
@@ -1,45 +1,51 @@
|
|
|
1
1
|
# health-export-mcp
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**An MCP server for your own Apple Health data.** 194 metrics, 18 tools (16 read-only, plus two that log events to their own file) and 22 prompts over local stdio, with zero dependencies, no account and no server of ours in the path. Your agent gets JSON with units, date ranges and coverage, and answers from your numbers.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/health-export-mcp"><img alt="npm" src="https://img.shields.io/npm/v/health-export-mcp?color=cb3837" /></a>
|
|
7
|
+
<a href="https://github.com/PhilipAD/health-export-mcp/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/PhilipAD/health-export-mcp/actions/workflows/ci.yml/badge.svg" /></a>
|
|
8
|
+
<a href="SECURITY.md"><img alt="npm provenance" src="https://img.shields.io/badge/npm-provenance-2ea44f" /></a>
|
|
9
|
+
<img alt="dependencies: 0" src="https://img.shields.io/badge/dependencies-0-2ea44f" />
|
|
10
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue" /></a>
|
|
11
|
+
<a href="https://glama.ai/mcp/servers/PhilipAD/health-export-mcp"><img alt="Glama score" src="https://glama.ai/mcp/servers/PhilipAD/health-export-mcp/badges/score.svg" /></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
Docs and per-client config: **[healthexport.dev/mcp](https://www.healthexport.dev/mcp/)** · agents can run the setup from **[SKILL.md](https://www.healthexport.dev/SKILL.md)** · privacy: the server reads a local file and makes no network requests, so your health data never reaches us or a cloud AI through it.
|
|
6
15
|
|
|
7
|
-
|
|
16
|
+
## Install: one command
|
|
8
17
|
|
|
9
18
|
```bash
|
|
10
|
-
claude mcp add --
|
|
11
|
-
--env "HEALTH_DATA_DIR=$HOME/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents" \
|
|
12
|
-
-- npx -y health-export-mcp
|
|
19
|
+
claude mcp add health-export -- npx -y health-export-mcp
|
|
13
20
|
```
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
On a Mac that is the whole install: since 1.7.3 the server finds the MetricBridge app's iCloud Drive folder by itself. On Windows or Linux, or for an export in another folder, add `--env "HEALTH_DATA_DIR=/path/to/folder"` before the `--`. Needs Node.js 18 or later. **Claude Desktop:** open [`health-export.mcpb`](https://github.com/PhilipAD/health-export-mcp/releases/latest/download/health-export.mcpb) instead (no JSON, no Node on your PATH). Cursor, VS Code, opencode, OpenClaw, Hermes: [AGENTS.md](AGENTS.md).
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
Then ask *"Use health-export: how did my HRV this week compare with last week?"* The agent calls `get_trends` and gets numbers that carry their own provenance: unit, exact date ranges, whether each window was complete, and how much history the export holds. This is the real output on 1.7.3 (from the built-in `--demo` dataset, which is synthetic so it can be published; a real export answers with the same fields and without the watermark):
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
[SYNTHETIC DEMO DATA] {"metric":"heart_rate_variability","unit":"ms","window":7,"recent":50.859,"prior":51.306,
|
|
28
|
+
"change":-0.447,"changePercent":-0.871,"direction":"flat","recentRange":{"from":"2026-08-12","to":"2026-08-18"},
|
|
29
|
+
"recentDays":7,"priorDays":7,"windowSatisfied":true,"coverage":{"firstDate":"2025-07-15","lastDate":"2026-08-18","days":400}}
|
|
19
30
|
```
|
|
20
31
|
|
|
21
|
-
|
|
32
|
+
**No iPhone yet?** `claude mcp add health-export-demo -- npx -y health-export-mcp --demo` serves that watermarked synthetic dataset, so you can try every tool in 30 seconds before installing anything on a phone.
|
|
22
33
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue" />
|
|
29
|
-
<img alt="works with Claude, Cursor, ChatGPT, OpenClaw, Hermes" src="https://img.shields.io/badge/works_with-Claude_·_Cursor_·_opencode_·_VS_Code_·_OpenClaw_·_Hermes-111" />
|
|
30
|
-
</p>
|
|
34
|
+
## Use your real data (about 5 minutes the first time, needs an iPhone)
|
|
35
|
+
|
|
36
|
+
1. **Export.** Install [MetricBridge](https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e) on the iPhone, allow Health read access and tap **Export now**. It writes `.health-cache.json` to iCloud Drive (or a folder, or your LAN). The app has a 7-day free trial, then one purchase ($24.99), no subscription. This server is MIT and free.
|
|
37
|
+
2. **Connect.** The one command above (Claude Code), the `.mcpb` (Claude Desktop), or the block for your client in [AGENTS.md](AGENTS.md).
|
|
38
|
+
3. **Check it arrived.** `npx -y health-export-mcp --doctor` prints the folder it chose and why, each file's age, and freshness. iCloud can take a few minutes to bring a new export to the Mac.
|
|
31
39
|
|
|
32
40
|
<p align="center">
|
|
33
|
-
<img src="assets/architecture.svg" alt="Apple Health exports to iCloud, a folder, or your LAN; health-export-mcp reads it and serves
|
|
41
|
+
<img src="assets/architecture.svg" alt="Apple Health exports to iCloud, a folder, or your LAN; health-export-mcp reads it and serves 18 tools to your AI agent" width="100%" />
|
|
34
42
|
</p>
|
|
35
43
|
|
|
36
|
-
> Ask your agent: *"Compare my HRV this week vs last week and tell me if I'm recovering."*, it calls the tools and answers from your **actual numbers**.
|
|
37
|
-
|
|
38
44
|
---
|
|
39
45
|
|
|
40
46
|
## What is health-export-mcp?
|
|
41
47
|
|
|
42
|
-
It's an MCP server that turns your Apple Health export into
|
|
48
|
+
It's an MCP server that turns your Apple Health export into tools your AI agent can query in natural language: HRV, sleep, resting heart rate, steps, workouts, VO₂ max and 180+ more.
|
|
43
49
|
|
|
44
50
|
- **Who it's for:** anyone who wants their AI to reason over their *real* health data instead of a stale CSV.
|
|
45
51
|
- **What it isn't:** a cloud service. There's no developer server in the path, your data goes only where *you* point it.
|
|
@@ -55,7 +61,7 @@ It's an MCP server that turns your Apple Health export into a tool your AI agent
|
|
|
55
61
|
|
|
56
62
|
---
|
|
57
63
|
|
|
58
|
-
## Connect Apple Health to your AI agent
|
|
64
|
+
## Connect Apple Health to your AI agent: quickstart
|
|
59
65
|
|
|
60
66
|
### 1. Get your Apple Health data flowing
|
|
61
67
|
|
|
@@ -76,12 +82,12 @@ The companion iOS app **[MetricBridge](https://www.healthexport.dev)** exports y
|
|
|
76
82
|
**Fastest, one command (Claude Code):**
|
|
77
83
|
|
|
78
84
|
```bash
|
|
79
|
-
claude mcp add --
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
claude mcp add health-export -- npx -y health-export-mcp
|
|
86
|
+
# Windows, Linux, or an export outside iCloud Drive:
|
|
87
|
+
claude mcp add health-export --env "HEALTH_DATA_DIR=/path/to/folder" -- npx -y health-export-mcp
|
|
82
88
|
```
|
|
83
89
|
|
|
84
|
-
Everything before `--` is an option for `claude mcp add`, everything after it is the command that starts the server.
|
|
90
|
+
Everything before `--` is an option for `claude mcp add`, everything after it is the command that starts the server. On a Mac the server reads the app's iCloud Drive folder when `HEALTH_DATA_DIR` is unset (1.7.3+); if you set it to that folder by hand, double-quote it (the folder name contains a space) and use `$HOME`, because a quoted `~` is not expanded by the shell. Add `--scope user` to make the server available in every project (the default scope is the current project only). Check it with `claude mcp list`.
|
|
85
91
|
|
|
86
92
|
**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`), and any client that takes an `mcpServers` block:
|
|
87
93
|
|
|
@@ -90,14 +96,13 @@ Everything before `--` is an option for `claude mcp add`, everything after it is
|
|
|
90
96
|
"mcpServers": {
|
|
91
97
|
"health-export": {
|
|
92
98
|
"command": "npx",
|
|
93
|
-
"args": ["-y", "health-export-mcp"]
|
|
94
|
-
"env": { "HEALTH_DATA_DIR": "~/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents" }
|
|
99
|
+
"args": ["-y", "health-export-mcp"]
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
}
|
|
98
103
|
```
|
|
99
104
|
|
|
100
|
-
> `npx -y` fetches the published package at run time without an install prompt (npm verifies package integrity), so it runs anywhere with no clone or absolute path. The server expands a leading `~` in `HEALTH_DATA_DIR` itself, so the JSON form can keep it. Prefer to pin a vetted local checkout instead? Use `"command": "node", "args": ["REPLACE_WITH_ABSOLUTE_PATH/server.mjs"]`, get the path with `node -e "console.log(process.cwd()+'/server.mjs')"` inside the repo.
|
|
105
|
+
> Off a Mac, or for another folder, add `"env": { "HEALTH_DATA_DIR": "/path/to/folder" }` to the entry (a leading `~` is expanded by the server). `npx -y` fetches the published package at run time without an install prompt (npm verifies package integrity), so it runs anywhere with no clone or absolute path. The server expands a leading `~` in `HEALTH_DATA_DIR` itself, so the JSON form can keep it. Prefer to pin a vetted local checkout instead? Use `"command": "node", "args": ["REPLACE_WITH_ABSOLUTE_PATH/server.mjs"]`, get the path with `node -e "console.log(process.cwd()+'/server.mjs')"` inside the repo.
|
|
101
106
|
> Or skip JSON entirely, drag **`health-export.mcpb`** into **Claude Desktop → Settings → Extensions**.
|
|
102
107
|
|
|
103
108
|
**Auto-configure from a clone:**
|
|
@@ -137,25 +142,27 @@ Restart the client and try:
|
|
|
137
142
|
|
|
138
143
|
---
|
|
139
144
|
|
|
140
|
-
## The
|
|
145
|
+
## The 18 MCP tools
|
|
141
146
|
|
|
142
147
|
Full reference with request/response examples: **[healthexport.dev/mcp](https://www.healthexport.dev/mcp/#tools)**.
|
|
143
148
|
|
|
144
149
|
| Tool | What it does |
|
|
145
150
|
|---|---|
|
|
146
151
|
| `get_mcp_status` | Health check: source, metric/workout counts, which context files exist, latest data date, and a `freshness` summary. **Call first.** |
|
|
147
|
-
| `get_freshness` | How current the export is: `stale` against a stated threshold (26 h by default, `HEALTH_STALE_AFTER_HOURS`, or `maxAgeHours`), `age_hours`, `as_of`, `last_data_date`, per-file write times. Same rule as the `status --max-age` cron gate. |
|
|
152
|
+
| `get_freshness` | How current the export is: `stale` judged on the core files (daily cache, sleep sessions) against a stated threshold (26 h by default, `HEALTH_STALE_AFTER_HOURS`, or `maxAgeHours`), `age_hours`, `as_of`, `last_data_date`, per-file write times. `state: "stale_copy"` (with a `stale_copy` list) when the phone's `.health-manifest.json` or iCloud says this Mac holds an older copy of a core file than the phone wrote. Same rule as the `status --max-age` cron gate. |
|
|
148
153
|
| `list_metrics` | Every available metric with unit, day count, and date range. |
|
|
149
|
-
| `get_health_metrics` | Daily values for a metric (or all) over a date range + an aggregate (avg/sum/min/max/latest). Supports `filterDays` (restrict to days covered by logged events, with `negate`). |
|
|
154
|
+
| `get_health_metrics` | Daily values for a metric (or all) over a date range + an aggregate (avg/sum/min/max/latest). Supports `filterDays` (restrict to days covered by logged events, with `negate`). Blood pressure at day granularity also lists the individual `readings` (`health-readings.json`). |
|
|
150
155
|
| `get_trends` | Recent N-day window vs the prior N days: change, % change, direction. Supports `excludeTravelDays`. |
|
|
151
156
|
| `compare_periods` | A metric across two arbitrary date periods (A vs B), or around a logged event via `anchor: {eventId, days}` (the event day excluded from both sides). |
|
|
152
157
|
| `get_structured_export` | Clean JSON for chosen metrics/range, paginated with a cursor. |
|
|
153
|
-
| `get_intraday` |
|
|
158
|
+
| `get_intraday` | The hour-by-hour window from the app's hourly automations (`health-intraday.json`, app 1.4+): yesterday and today, replaced each run, with each hour's `Min`/`Max` for discrete metrics when the app writes them. |
|
|
154
159
|
| `query_health_data` | Natural-language convenience: *"average HRV last month"* routed to structured results. |
|
|
155
|
-
| `list_events` | Logged context events (medication, habit, visit, life, shift, episode, travel) with type/tag/date filters
|
|
160
|
+
| `list_events` | Logged context events (medication, habit, visit, life, shift, episode, travel) with type/tag/date filters, from the app and from `add_event`, each labelled `source: "app"` or `"agent"`. |
|
|
161
|
+
| `add_event` | Log an event the user states (a medication start, a trip) into `health-events-agent.json`, the one file this server writes. Idempotent by `clientEventId`. |
|
|
162
|
+
| `remove_event` | Remove an event logged with `add_event`. Events logged in the iOS app are edited there. |
|
|
156
163
|
| `get_profile` | Opted-in context fields (conditions, medications, goals, allergies, notes) plus `presentFields`. Absent fields were withheld, never "none". |
|
|
157
164
|
| `get_workouts` | Workouts by activity/date with pagination; includes heart rate, running dynamics, cycling power, intervals and `hasRoute` when exported. |
|
|
158
|
-
| `get_sleep_sessions` | Clustered sleep sessions attributed to the waking day; split nights returned as
|
|
165
|
+
| `get_sleep_sessions` | Clustered sleep sessions attributed to the waking day; split nights returned as separate sessions, duplicate copies of one night collapsed (`collapsedDuplicates`). |
|
|
159
166
|
| `get_cycle_context` | Day-in-cycle and coarse phase derived from logged period starts. Never predictive. |
|
|
160
167
|
| `correlate_metrics` | Pearson correlation between two metrics with a 0..3 day lag. Association, not causation, always stated. |
|
|
161
168
|
| `resolve_metric` | Canonical name and unit for any spelling (`steps`, `StepCount`, `Body Weight`, `hrv`), unit variants with exact formulas, an optional `{value, unit}` conversion, and whether the export holds it. Ambiguous words come back with candidates, never guessed. The data tools accept the same aliases and report `resolvedFrom`. When the export carries per-source attribution (app builds that write `src`/`by` on daily points and a `health-sources.json`, cache schema minor 2), the answer adds a `sources` block naming the devices that fed the export, which one won each metric and the priority rules, and `sourceMerge` reports disagreement as visible; older exports report it as not available. |
|
|
@@ -164,9 +171,9 @@ Full reference with request/response examples: **[healthexport.dev/mcp](https://
|
|
|
164
171
|
|
|
165
172
|
### Data files
|
|
166
173
|
|
|
167
|
-
The daily cache (`.health-cache.json`) and workouts cache are joined by optional context files, all
|
|
174
|
+
The daily cache (`.health-cache.json`) and workouts cache are joined by optional context files, all optional: `health-events.json` (the logging surface), `health-profile.json` (opt-in context), `health-sessions.json` (sleep sessions), `health-cycles.json` (observed cycle starts), `health-days.json` (timezone change log), `health-readings.json` (individual blood pressure readings) and `.health-manifest.json` (what the phone last wrote, for the stale-copy check). The server reads all of them and writes only `health-events-agent.json` (events logged with `add_event`). An absent file is reported as `available:false` with a note, never as "no data". Formats: [docs/SCHEMA-CONTRACTS.md](docs/SCHEMA-CONTRACTS.md).
|
|
168
175
|
|
|
169
|
-
Two patterns worth knowing: [query a parent's Apple Health from your own AI](docs/caregiver-setup.md) (consent-first, the parent's phone is the authority) and [logging data into Apple Health via Shortcuts](docs/shortcuts-write-bridge.md) (the server
|
|
176
|
+
Two patterns worth knowing: [query a parent's Apple Health from your own AI](docs/caregiver-setup.md) (consent-first, the parent's phone is the authority) and [logging data into Apple Health via Shortcuts](docs/shortcuts-write-bridge.md) (the server never writes to Apple Health).
|
|
170
177
|
|
|
171
178
|
### MCP prompts
|
|
172
179
|
|
|
@@ -180,7 +187,7 @@ The server ships 22 prompts over `prompts/list` / `prompts/get`: daily brief, we
|
|
|
180
187
|
|
|
181
188
|
```bash
|
|
182
189
|
node server.mjs --doctor # diagnostics: files, sizes, schema, freshness, pairing
|
|
183
|
-
node server.mjs status --max-age 24 # exit 0 if data is fresh, 1 if stale (cron gate)
|
|
190
|
+
node server.mjs status --max-age 24 # exit 0 if data is fresh, 1 if stale or a stale iCloud copy (cron gate)
|
|
184
191
|
node server.mjs receive # standalone LAN receiver (binds 127.0.0.1 by default)
|
|
185
192
|
node server.mjs --help
|
|
186
193
|
```
|
|
@@ -201,11 +208,11 @@ node server.mjs --help
|
|
|
201
208
|
|
|
202
209
|
## Use cases
|
|
203
210
|
|
|
204
|
-
- **AI health coach
|
|
205
|
-
- **Training-load analysis
|
|
206
|
-
- **Sleep correlations
|
|
207
|
-
- **Quantified-self dashboards
|
|
208
|
-
- **Personal research & experiments
|
|
211
|
+
- **AI health coach:** let an agent reason over your real HRV, resting heart rate, and sleep to suggest when to push and when to recover, grounded in your actual numbers instead of generic advice.
|
|
212
|
+
- **Training-load analysis:** pull workouts, VO₂ max, and heart-rate trends so your agent can flag overreaching, plot fitness progression, and pace a training block.
|
|
213
|
+
- **Sleep correlations:** have your agent correlate deep-sleep duration against steps, caffeine, late workouts, or screen time to see what tends to go with your better nights (associations, not causes).
|
|
214
|
+
- **Quantified-self dashboards:** feed clean JSON for any metric set and date range straight into a notebook, spreadsheet, or LLM-built dashboard for your own self-tracking.
|
|
215
|
+
- **Personal research & experiments:** run n-of-1 experiments (supplement, routine, or protocol changes) and let an agent compare before/after periods across 194 metrics to see what changed.
|
|
209
216
|
|
|
210
217
|
---
|
|
211
218
|
|
|
@@ -231,7 +238,7 @@ Wellness-scoped and end-user-directed; no clinical or HIPAA work.
|
|
|
231
238
|
<img src="assets/screenshot-destinations.png" alt="Export to iCloud, folder, LAN, or webhook" width="240" />
|
|
232
239
|
</p>
|
|
233
240
|
|
|
234
|
-
<p align="center"><sub><a href="https://www.healthexport.dev">MetricBridge</a
|
|
241
|
+
<p align="center"><sub><a href="https://www.healthexport.dev">MetricBridge</a> exports your Apple Health to your agent, automatically.</sub></p>
|
|
235
242
|
|
|
236
243
|
<p align="center"><a href="https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e"><b>Download on the App Store →</b></a></p>
|
|
237
244
|
|
|
@@ -244,12 +251,12 @@ with exactly two shapes: `{"state": "trial", "daysRemaining": N}` or `{"state":
|
|
|
244
251
|
export from a trial adds one sentence to `get_freshness` naming when the trial ends; an unlocked export
|
|
245
252
|
adds nothing. No network call is involved and nothing is sent anywhere.
|
|
246
253
|
|
|
247
|
-
- **
|
|
254
|
+
- **Reads your export, never Apple Health.** The server never touches HealthKit. Its only write is `health-events-agent.json`, the events an agent logs with `add_event` / `remove_event`; it never modifies a file the app writes. Both tools are refused in demo mode and on a read-only folder, and the file is sealed like the rest of an encrypted export.
|
|
248
255
|
- **Local-first.** It runs on your machine over stdio. There is **no developer server** in the path.
|
|
249
256
|
- **Optional pairing.** Set `PAIRING_SECRET` to the code the iOS app shows (Settings → Agent pairing) to gate access.
|
|
250
257
|
- **Encrypted exports (optional).** If you switch on Export encryption in the iOS app, set `HEALTH_EXPORT_PASSPHRASE` (or `HEALTH_EXPORT_PASSPHRASE_FILE`) to the same passphrase and the server decrypts on your machine. See [Encrypted exports](#encrypted-exports).
|
|
251
258
|
- **No telemetry.** The server makes no network requests. `get_mcp_status` always includes one static link to the companion app's website (and its App Store page), so the bridge is attributable back to install. Both links carry fixed campaign labels (`utm_source=mcp`, `utm_medium=agent-tool`, `utm_campaign=mcp-unlock`; `ct=mcpserver`, `ppid=…`) that are identical for every user and contain nothing about you or your data; they only count if you choose to open one.
|
|
252
|
-
- **Auditable.** Zero dependencies and
|
|
259
|
+
- **Auditable.** Zero runtime dependencies, about 4,000 lines of plain ES modules and no build step: what's on npm is what's in this repo, and npm provenance links each tarball to the commit and workflow that built it.
|
|
253
260
|
- **Signed releases.** Hosted artifacts are minisign-signed and checksummed, see [Verifying releases](#verifying-releases).
|
|
254
261
|
|
|
255
262
|
---
|
|
@@ -312,7 +319,7 @@ curl -fsSL https://healthexport.dev/mcp/server.mjs -o server.mjs
|
|
|
312
319
|
shasum -a 256 --ignore-missing -c SHA256SUMS || { echo "checksum mismatch, do not run"; exit 1; }
|
|
313
320
|
```
|
|
314
321
|
|
|
315
|
-
The pinned, checksum-verified download above is the locked-down path. `npx -y health-export-mcp` instead resolves the latest version published to npm at run time (npm provides its own package integrity).
|
|
322
|
+
The pinned, checksum-verified download above is the locked-down path. `npx -y health-export-mcp` instead resolves the latest version published to npm at run time (npm provides its own package integrity). GitHub releases carry a `SHA256SUMS` file and a CycloneDX SBOM (`*.cdx.json`); a `SHA256SUMS.minisig` made with the same key is attached once the maintainer has signed that release locally, so check for it before relying on it. Full policy, including npm provenance and how to report a vulnerability privately: **[SECURITY.md](SECURITY.md)**. Security overview: <https://healthexport.dev/security>.
|
|
316
323
|
|
|
317
324
|
---
|
|
318
325
|
|
|
@@ -336,15 +343,17 @@ Not to us. The MCP server runs locally and reads only the export files or endpoi
|
|
|
336
343
|
Any MCP client, Claude Desktop, Cursor, opencode, OpenClaw, Hermes, VS Code, natively. ChatGPT, Gemini, Grok, n8n, and Home Assistant consume the same data via webhook.
|
|
337
344
|
|
|
338
345
|
**Do I need the iOS app?**
|
|
339
|
-
|
|
346
|
+
For your own data, yes: the server reads the file the MetricBridge app writes and never talks to HealthKit itself. To evaluate first, `--demo` serves a watermarked synthetic dataset with no app and no iPhone.
|
|
340
347
|
|
|
341
348
|
---
|
|
342
349
|
|
|
343
350
|
## Troubleshooting
|
|
344
351
|
|
|
345
|
-
- **"No metrics found"
|
|
346
|
-
- **Server not visible in the client
|
|
347
|
-
- **
|
|
352
|
+
- **"No metrics found":** run `npx -y health-export-mcp --doctor`. It prints the folder the server chose and why (`HEALTH_DATA_DIR`, the iCloud default on a Mac, or the current directory) and whether `.health-cache.json` is there. Confirm the app has exported at least once; `get_mcp_status` shows the same source and the latest date.
|
|
353
|
+
- **Server not visible in the client:** run `npx -y health-export-mcp --doctor` in a terminal. If it works there, the client can't find `npx` (common for Claude Desktop with Node from nvm or Homebrew): use the `.mcpb`, or set `"command"` to the full path from `which npx`. Then fully quit and reopen the client.
|
|
354
|
+
- **Exports stopped after a week:** the app's free trial ended. `get_freshness` reports the export as stale and links the unlock page; once the app is unlocked, exports resume with no change on this side.
|
|
355
|
+
- **Answers miss last night, or `state: "stale_copy"`:** this Mac's iCloud Drive has an older copy of the export than the phone wrote. Wait a few minutes, or open the MetricBridge folder in iCloud Drive in Finder and choose Download Now on the file (Remove Download drops only this Mac's local copy, and it downloads again). `--doctor` lists each stale copy.
|
|
356
|
+
- **Locked data error:** the export file is protected until first unlock after reboot; unlock your device once.
|
|
348
357
|
|
|
349
358
|
---
|
|
350
359
|
|
|
@@ -364,7 +373,7 @@ stdio transport (newline-delimited JSON-RPC 2.0), the universal MCP transport. O
|
|
|
364
373
|
|
|
365
374
|
## How it works
|
|
366
375
|
|
|
367
|
-
The iOS app reads Apple Health (read-only) and writes a compact `.health-cache.json` (plus optional context files) to the destination you choose. This server reads those files and exposes the
|
|
376
|
+
The iOS app reads Apple Health (read-only) and writes a compact `.health-cache.json` (plus optional context files) to the destination you choose. This server reads those files and exposes the 18 tools above over MCP. No bridge, no Docker, no database: just files and stdio.
|
|
368
377
|
|
|
369
378
|
```
|
|
370
379
|
Apple Health → MetricBridge (iOS) → .health-cache.json → health-export-mcp → MCP client → you
|
|
@@ -376,11 +385,11 @@ Apple Health → MetricBridge (iOS) → .health-cache.json → health-export-mcp
|
|
|
376
385
|
|
|
377
386
|
Other Apple Health MCP servers in the ecosystem, worth a look depending on your setup:
|
|
378
387
|
|
|
379
|
-
- **[neiltron/apple-health-mcp](https://github.com/neiltron/apple-health-mcp)
|
|
380
|
-
- **[the-momentum/apple-health-mcp-server](https://github.com/the-momentum/apple-health-mcp-server)
|
|
381
|
-
- **[HealthyApps/health-auto-export-mcp-server](https://github.com/HealthyApps/health-auto-export-mcp-server)
|
|
388
|
+
- **[neiltron/apple-health-mcp](https://github.com/neiltron/apple-health-mcp):** an MCP server that runs SQL-style queries over an Apple Health export.
|
|
389
|
+
- **[the-momentum/apple-health-mcp-server](https://github.com/the-momentum/apple-health-mcp-server):** an MCP server for analyzing Apple Health data exported from the Health app.
|
|
390
|
+
- **[HealthyApps/health-auto-export-mcp-server](https://github.com/HealthyApps/health-auto-export-mcp-server):** an MCP server for the Health Auto Export app's data.
|
|
382
391
|
|
|
383
|
-
**How `health-export-mcp` differs:**
|
|
392
|
+
**How `health-export-mcp` differs:** the iPhone app keeps the export current in the background, so there's no manual `export.xml` and no re-import; the server has zero dependencies and needs no Docker, database or Mac app; every answer carries its units, date range and coverage; and it never writes to Apple Health: its only write is the events file your agent logs to.
|
|
384
393
|
|
|
385
394
|
---
|
|
386
395
|
|
|
@@ -398,4 +407,3 @@ MIT, see [LICENSE](LICENSE). Contributions welcome.
|
|
|
398
407
|
|
|
399
408
|
---
|
|
400
409
|
|
|
401
|
-
<sub>Apple Health MCP server · export Apple Health to AI · HealthKit MCP server · query Apple Health with Claude / ChatGPT / Cursor · Model Context Protocol health server · Apple Health to LLM · HRV, sleep & heart rate for AI agents.</sub>
|