Ask your agent about your real Apple Health data
Paste one command. Claude Code, Claude Desktop, Cursor, VS Code, opencode, OpenClaw or Hermes then reads your Apple Health export through 18 tools over 194 metrics, on your own machine. Nothing to host, no account, no cloud AI in the path.
Install: one command (Claude Code)
claude mcp add health-export -- npx -y health-export-mcp
On a Mac that is the whole install: since 1.7.3 the server finds the app's iCloud Drive folder by itself.
On Windows or Linux, or if your export lands somewhere else, add
-e HEALTH_DATA_DIR="/path/to/your/export/folder". Needs Node.js 18 or later. Then restart the client and
ask: "Use health-export: how did my HRV this week compare with last week?"
The Cursor and VS Code links install npx -y health-export-mcp with no folder set, which is right
on a Mac; on Windows or Linux add HEALTH_DATA_DIR to the entry afterwards. Other clients:
client config.
- Read-only. No tool can write to Apple Health; the app asks for read permission only.
- Zero dependencies. One npm package, about 4,000 lines of plain JavaScript, no network requests.
- Where the data comes from. The MetricBridge iPhone app writes
.health-cache.jsonto iCloud Drive, a folder or your LAN. The server reads that file. Nothing reaches us. - Pairing is optional. Turn on Agent pairing in the app and set
PAIRING_SECRETif you want a code to gate the tools. Otherwise there is nothing to set. - The app is required for your own data. 7-day free trial, then $24.99 once, no subscription. The server is free, MIT.
- No iPhone yet?
npx -y health-export-mcp --demoserves a watermarked synthetic dataset, so you can see every tool first.
Last updated 28 October 2026 · health-export-mcp 1.8.0 · source on GitHub · npm: health-export-mcp
What a real answer looks like
You ask in plain language; the agent picks a tool; the tool answers with numbers that carry their own
provenance: the unit, the exact date ranges, whether each window was complete, and how much history the export
holds. This is the real output of get_trends on health-export-mcp 1.7.3, captured on 27 October 2026
from the built-in --demo dataset (synthetic, so it can be published; a real export answers with the
same fields and without the watermark).
You: "Use health-export: how did my HRV this week compare with last week?"
Agent calls get_trends with {"metric":"heart_rate_variability","window":7} and gets:
[SYNTHETIC DEMO DATA] {"metric":"heart_rate_variability","unit":"ms","window":7,
"recent":50.859,"prior":51.306,"change":-0.447,"changePercent":-0.871,"direction":"flat",
"recentRange":{"from":"2026-08-12","to":"2026-08-18"},"recentDays":7,"priorDays":7,
"windowSatisfied":true,"coverage":{"firstDate":"2025-07-15","lastDate":"2026-08-18","days":400}}
Agent: Your HRV averaged 50.9 ms over 12 to 18 August against 51.3 ms the week before, down 0.4 ms (0.9%). Both windows had all seven days, so this is flat, not a dip. The export holds 400 days, back to 15 July 2025.
Every data tool answers this way. get_mcp_status names the file it read and the latest data date;
compare_periods reports pointsInRange for each period and comparable: false when
one side is too thin; correlate_metrics refuses below ten aligned days and says "association, not
causation" in the payload. A number without its working does not come out of this server.
On this page
What your agent can answer: the 18 tools
All sixteen are read-only and none makes a network request. Your agent picks the tool from your question; you never name one. The left column is the question, the right is what answers it.
| Your question | Tool | What comes back |
|---|---|---|
| "Is my health data connected?" | get_mcp_status | The file it read, metric and workout counts, latest data date, a freshness summary. Agents call this first. |
| "Is this export current enough to trust?" | get_freshness | stale against a threshold (26 hours by default), judged on the daily cache and sleep sessions, age_hours, as_of, per-file write times, and stale_copy when this computer still has an older copy of a file than the phone wrote. |
| "What do you have on me?" | list_metrics | Every metric in the export with unit, day count and date range. |
| "What was my resting heart rate each day in September?" | get_health_metrics | Daily values for one metric (or all) over a range, plus avg/sum/min/max/latest. Long ranges roll up to weekly or monthly points with the aggregate still over every day. |
| "How does this week compare with last week?" | get_trends | Recent N days against the prior N: change, percent change, direction, whether both windows were complete. |
| "Compare this January with last January" or "before and after I started the medication" | compare_periods | Two arbitrary periods, or a logged event with N days either side (the event day excluded). |
| "Give me HRV, RHR and sleep for the last 14 days as JSON" | get_structured_export | Clean JSON for chosen metrics and range, paginated with a cursor. |
| "What has my heart rate done today?" | get_intraday | Yesterday and today hour by hour, written by the app's hourly automations (app 1.4 or later), with each hour's lowest and highest reading for vitals when the app writes them. Replaced each run, not a history. |
| Anything phrased loosely: "average HRV last month" | query_health_data | Routes a plain question to structured results. The specific tools above are cheaper and more predictable. |
| "When did I start the new medication / change shifts / travel?" | list_events | Events you logged in the app, or your agent logged with add_event (medication, habit, visit, life, shift, episode, travel), filtered by type, tag or date, each marked as from the app or the agent. |
| "I started magnesium today, note it" | add_event | Logs an event you state into health-events-agent.json, the one file the server writes, so a later export from the app never wipes it. Sealed when your export is encrypted. |
| "Remove that event you logged" | remove_event | Removes an event your agent logged. Events you logged in the app are edited in the app. |
| "What conditions or goals have I told you about?" | get_profile | Only the profile fields you switched on. An absent field means withheld, never "none". |
| "Show my runs this month with heart rate and pace" | get_workouts | Workouts by activity and date, with heart rate, running dynamics, cycling power, intervals and whether a route exists. Paginated. |
| "How did I sleep last night, and was it split?" | get_sleep_sessions | Clustered sleep sessions attributed to the waking day, with stage totals; split nights stay split. |
| "Where am I in my cycle?" | get_cycle_context | Day-in-cycle and a coarse phase from logged period starts only. Never predictive; only with sensitive categories on. |
| "Does a late workout go with worse HRV the next day?" | correlate_metrics | Pearson r between two metrics with a 0 to 3 day lag; refuses under ten aligned days; states association, not causation. |
| "What do you call VO2 max, and is 180 lb in kg?" | resolve_metric | Canonical name and unit for any spelling, unit conversions with formulas, whether the export holds it, and (on newer exports) which device fed each metric. |
The server also ships 22 MCP prompts (daily brief, weekly review, doctor visit prep, an n-of-1
experiment protocol, medication before/after, shift block comparisons and more), a --doctor diagnostics
command, and status --max-age <hours> as a freshness gate for cron jobs. Prompt and tool reference
with every parameter: the README.
get_mcp_status
Reports the data source, how many metrics and workouts are available, the most recent data date and a
freshness summary. Since 1.7.3 the source line also says why that folder was chosen
(HEALTH_DATA_DIR, the iCloud default on a Mac, or the current directory).
{ "ok": true, "source": "file /Users/you/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents/.health-cache.json (default: the MetricBridge iCloud Drive folder)",
"metricCount": 34, "workoutCount": 12, "lastDataDate": "2026-10-26",
"freshness": { "state": "fresh", "stale": false, "age_hours": 3.2, "stale_after_hours": 26 } }
get_health_metrics
| Parameter | Type | Notes |
|---|---|---|
metric | string | e.g. step_count, or any alias resolve_metric accepts. Omit for all metrics. |
start, end | string | YYYY-MM-DD, both optional. |
aggregation | string | avg, sum, min, max or latest. Defaults to sum for cumulative metrics, average otherwise. |
granularity | string | auto (default), day, week or month. Auto picks the finest bucket that fits the response budget. |
filterDays | object | Restrict to days covered by logged events of a type or tag, with negate to exclude them. |
get_trends
| Parameter | Type | Notes |
|---|---|---|
metric | string | Required. |
window | integer | Days per window. Defaults to 7. |
excludeTravelDays | boolean | Drop days on which the phone changed time zone. |
get_intraday
The current hour-by-hour window written by the iOS app's hourly automations (app 1.4 or later)
to health-intraday.json, beside the daily cache. The file is replaced on every hourly run
(a live within-day view, not an accumulating history), so day-level questions still belong to
get_health_metrics. Optional metric filters to one metric; when no hourly automation has
delivered yet it answers available: false with setup guidance instead of an error.
{ "available": true, "file": "health-intraday.json", "replacedEachRun": true,
"metrics": [ { "name": "heart_rate", "unit": "count/min",
"points": [ { "t": "2026-08-17 09:00:00 +0100", "v": 71 } ],
"latest": { "t": "2026-08-17 09:00:00 +0100", "v": 71 } } ] }
resolve_metric
| Parameter | Type | Notes |
|---|---|---|
name | string | Required. Any spelling, e.g. steps, StepCount, Body Weight, VO2 max. A word that names several metrics comes back with candidates, never a guess. |
value, unit | number, string | Optional. Converts the value into the canonical unit, e.g. 180 lb to kg. |
Full setup, the first time
Under two minutes if the app is already exporting to iCloud Drive on a Mac: paste the command, restart the client, ask. The first time, add the app install and a few minutes for iCloud to bring the file to your Mac.
- Install the MetricBridge iOS app. Install the MetricBridge iOS app on your iPhone and allow read access to the Apple Health types you want to share. It has a 7-day free trial, then costs $24.99 once. Download on the App Store.
- Choose an export destination. In the app, choose where the export goes: iCloud Drive, a local folder, or your LAN. The app writes
.health-cache.jsonthere. On a Mac, iCloud Drive needs no further setup. - Add the server to your MCP client. In Claude Code run:
claude mcp add health-export -- npx -y health-export-mcp. On a Mac the server finds the app's iCloud Drive folder by itself (since 1.7.3); on Windows or Linux, or for another folder, add-e HEALTH_DATA_DIR="/path/to/your/export/folder". Claude Desktop: open health-export.mcpb instead. - Check the connection. Ask your agent to call
get_mcp_status. It reports the data source, the metric count and the most recent data date.
npx -y health-export-mcp --doctor prints the folder the server chose
and why, each file's age and the freshness verdict. iCloud can take a few minutes after you tap Export in the app.
When the trial ends and exports stop, get_freshness says so and links the unlock page; once the app is
unlocked, exports resume with no change on this side.
Client configuration
Every client runs the same command, npx -y health-export-mcp, over stdio. On a Mac no environment
variable is needed; elsewhere set HEALTH_DATA_DIR. Prefer a pinned, checksum-verified copy instead of
npm? Download the files under verify the download and replace npx -y health-export-mcp
with node /path/to/server.mjs in any block below, keeping the nine .mjs files together in
one folder.
Claude Code
claude mcp add health-export -- npx -y health-export-mcp
# Windows, Linux, or an export outside iCloud Drive:
claude mcp add health-export -e HEALTH_DATA_DIR="/path/to/your/export/folder" -- npx -y health-export-mcp
Everything after -- is the command Claude Code runs. Add --scope user before the
-- to make the server available in every project; the default is the current project. Check with
claude mcp list. Claude Code also reads a project-scoped .mcp.json using the same
mcpServers shape as Claude Desktop. If pairing is on, do not pass PAIRING_SECRET on the
command line: it would land in your shell history and in ps output. Put it in the config file instead.
Claude Desktop
Easiest: open health-export.mcpb, click Install, and it asks for the export
folder (and the pairing code, if you use one) itself. Desktop runs it with its own Node, so nothing goes on your
PATH. Or edit claude_desktop_config.json, merge into mcpServers, then quit and reopen
Claude Desktop:
{
"mcpServers": {
"health-export": {
"command": "npx",
"args": ["-y", "health-export-mcp"],
"env": { "HEALTH_DATA_DIR": "/path/to/your/export/folder" }
}
}
}
Drop the env line on a Mac using iCloud Drive. If Desktop logs spawn npx ENOENT, its
PATH cannot see Node (common with nvm or Homebrew): set "command" to the full path from
which npx, or use the bundle.
Cursor
Cursor reads ~/.cursor/mcp.json (global) or .cursor/mcp.json (per project), using the
same mcpServers block as Claude Desktop.
VS Code
VS Code reads .vscode/mcp.json in the workspace. The top key is servers, and a secret can
be prompted for rather than stored:
{
"servers": {
"health-export": {
"type": "stdio",
"command": "npx",
"args": ["-y", "health-export-mcp"],
"env": { "HEALTH_DATA_DIR": "/path/to/your/export/folder" }
}
}
}
opencode
Add the server to opencode.json (project) or ~/.config/opencode/opencode.json. The top
key is mcp, command is an array and the env key is environment:
{
"mcp": {
"health-export": {
"type": "local",
"command": ["npx", "-y", "health-export-mcp"],
"enabled": true,
"environment": { "HEALTH_DATA_DIR": "/path/to/your/export/folder" }
}
}
}
OpenClaw, Hermes and any other MCP client
The server speaks standard MCP over stdio, so any compliant client works. Add a health-export entry
with command npx, args ["-y", "health-export-mcp"] and, outside a Mac with iCloud Drive,
HEALTH_DATA_DIR in its environment, in whatever shape that client's MCP config uses. Per-client blocks
are kept current in AGENTS.md.
Agents can also set this up for you from the setup skill.
ChatGPT, Gemini, Grok, n8n and Home Assistant do not run local MCP servers. They read the same data through the app's webhook export to an endpoint you run.
Environment variables
From health-export-mcp --help at 1.8.0. None is required on a Mac that exports to iCloud Drive.
| Variable | Purpose |
|---|---|
HEALTH_DATA_DIR | Folder containing .health-cache.json. When unset: on macOS, the app's iCloud Drive folder ~/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents if it exists (since 1.7.3), otherwise the current directory. A leading ~ is expanded. |
PAIRING_SECRET | Only if the iOS app has Agent pairing on. Must match the code shown under Settings → Agent pairing. Without it the data tools return a clear "Locked" error rather than an empty result. |
HEALTH_EXPORT_PASSPHRASE, HEALTH_EXPORT_PASSPHRASE_FILE | Only if Export encryption is on in the app. The server decrypts in memory on your machine; the file form keeps the passphrase out of shell history. |
HEALTH_STALE_AFTER_HOURS | Hours after which get_freshness reports the export as stale. Default 26. |
HEALTH_DEMO=1 | Same as --demo: a watermarked synthetic dataset, no file read. |
HEALTH_LISTEN=1, HEALTH_LISTEN_HOST, HEALTH_LISTEN_PORT, HEALTH_LISTEN_TOKEN | Local-network path only: also accept pushes from the iPhone inside the MCP process (default bind 127.0.0.1:27184; the token is mandatory on any other bind). |
HEALTH_MAX_RESULT_CHARS | Per-answer size budget. Default 100000. |
Transports (stdio only)
stdio is the only MCP transport. Every client config above uses it, and there is no hosted endpoint. The server only ever runs on your machine, reading a local file.
Verifying the download
The copy hosted here is minisign-signed and checksummed, so you can confirm you are running exactly what was
published before you execute it. The signing key is also published in the GitHub repo (minisign.pub);
pin it from there, not only from this site.
- SHA256SUMS: checksums for each file
- SHA256SUMS.minisig: minisign signature
- minisign.pub: the public key
minisign -Vm SHA256SUMS -p minisign.pub
shasum -a 256 -c SHA256SUMS
npx -y health-export-mcp resolves the latest npm release at run time instead; npm verifies package
integrity and each release carries npm provenance linking the tarball to its commit. Policy:
security.
What agents can see
An agent never talks to your iPhone. It reads the files in the place you chose (iCloud Drive, a folder, or the local-network receiver), through this server on your own computer: the files the MetricBridge app writes, and any events your agent adds there. This is everything those files contain. The same list is in the app under Settings, What agents can see.
Agents can read
- Daily values per metric (
.health-cache.json, and the same data ashealth-export.json, plus yesterday's copy,.health-cache.prev.json, for recovery): only the Apple Health types you allowed, one value per day, across the activity, heart, respiratory, body, mobility, nutrition, vitals and lab, hearing, sleep, mindfulness, symptoms, environment and characteristics families, plus a few types that fit none of these, and the reproductive family only with sensitive categories on. - Workout summaries (
.health-workouts-cache.json): type, time, duration, distance, energy, heart rate, elevation, running and cycling averages, laps, pauses and sub-activities. - Sleep sessions (
health-sessions.json): start, end and stage totals for each night and nap. - Blood pressure readings (
health-readings.json): each reading with its time and source, so several readings in a day stay separate. - Device sources (
health-sources.json): which device or app recorded each value, such as Apple Watch or a ring, with each device's own reading when two recorded the same thing. - Yesterday and today, hour by hour (
health-intraday.json): only from hourly exports, and replaced each time. Each hour has an average and, for vitals such as heart rate and blood oxygen, the lowest and highest reading. - Events and profile fields you entered (
health-events.json,health-profile.json): only what you typed, and only the profile fields you switched on. - Events your agent logged (
health-events-agent.json): added by your agent on your computer withadd_event, never by the app. You see them in the app under Events. - Export check (
.health-manifest.json): when the iPhone last wrote each file, so this server can tell an old copy from a current one. It includes when last night's sleep ended, unless exports are encrypted. - Cycle start dates (
health-cycles.json): only with sensitive categories on. - Time zone changes (
health-days.json): so travel days can be flagged.
Reproductive health, sexual activity and alcohol are included only if you switch on sensitive categories in the app. They are off by default.
Never included
- No write access to Apple Health. The app asks for read permission only, and no tool here can
write to it. The one file this server writes is
health-events-agent.json, for events your agent logs. - No workout routes or GPS locations. A route leaves the phone only as a GPX file you share yourself from the app. It is never written to a destination, and this server reads no route file.
- No medication records from Apple Health. The app does not read them. A medication reaches an agent only if you type it into an event or your profile, or your agent logs one.
- No individual raw samples, except your blood pressure readings. Agents get daily values, one summary per workout and per sleep session, and hour-by-hour summaries.
- No health data sent to us. There is no MetricBridge account.
This covers the files an agent reads. A webhook, if you set one up, sends to a server you run, and the app lists every destination under Settings, What leaves this phone.
Who can read it: pairing
With pairing on (Settings, Agent pairing), this server serves your data only when
PAIRING_SECRET matches the current code; otherwise every data tool answers “Locked”.
The app writes only a SHA-256 hash of the code beside your data, never the code itself. Regenerating the code
in the app cuts off every agent using the old one as soon as the new pairing file reaches your computer.
Pairing covers the iCloud Drive and folder exports; it does not cover a copy saved by the local-network
receiver. Pairing protects this server, not the files: anyone who can open the files can read them, unless you turn on
export encryption in the app.
Is it private?
The server makes no network requests, has no dependencies, requires no account, and reads a local file you control, so your health data never reaches us or a cloud AI through it. Apple Health access happens only in the iOS app, which requests read-only HealthKit permission and never writes back. The export goes only to the destination you choose; what your agent then does with an answer is governed by that agent, not by this server. Full data-flow table: privacy.
Frequently asked questions
What is an Apple Health MCP server?
An Apple Health MCP server is a Model Context Protocol server that exposes your Apple Health data to AI agents as tools they can call on demand, rather than as a file you paste into a chat.
How do I install health-export-mcp in Claude Code?
Run one command: claude mcp add health-export -- npx -y health-export-mcp. On a Mac it finds the app's iCloud Drive folder by itself; on Windows or Linux add -e HEALTH_DATA_DIR="/path/to/your/export/folder". It requires Node.js 18 or later.
Do I need the iOS app?
For your own data, yes. This server reads a file and does not talk to your iPhone directly. The MetricBridge iOS app writes the JSON export, and without the app there is no export for this server to read. To try the tools first, the --demo mode serves a watermarked synthetic dataset.
How many tools and prompts does the server have?
The server has 18 tools and 22 MCP prompts. 16 only read; add_event and remove_event write one file, health-events-agent.json, beside your export. None of the tools can write to Apple Health, and none of them make network requests.
Is the MCP server free?
The MCP server is free and open source under the MIT license. The MetricBridge iOS app that writes the export is a separate purchase: a 7-day free trial, then a single $24.99 one-time unlock, with no subscription.
Does the server send my health data anywhere?
No. The server makes no network requests, has no dependencies, requires no account, and reads a local file you control. Your health data never reaches us or a cloud AI through this server.
Does it work on Windows or Linux?
Yes, anywhere Node.js 18 runs. Only the iCloud Drive default is Mac-only: on Windows or Linux set HEALTH_DATA_DIR to the folder your export syncs to.
Related
- The setup skill (SKILL.md): lets an agent do this install for you, with your review.
- Webhook contract: the same data POSTed to an endpoint you run, for non-MCP tools.
- MetricBridge for platforms: let your users bring their own Apple Health to your product.
- Ask on the iPhone: the app's own on-device answers, no agent needed.
- All 194 metrics and how the numbers are computed.
- Connect Apple Health to Claude with an MCP server
- Export Apple Health to JSON for AI: the complete guide