Apple Health MCP server
The MetricBridge MCP server exposes your Apple Health data to any MCP client as 16 read-only tools. It is zero-dependency, runs entirely on your own machine, and never writes to Apple Health or sends data anywhere.
Last updated 10 October 2026 · source on GitHub · npm: health-export-mcp
Install the iOS app first
This server reads the JSON export the MetricBridge app writes. Without the app there is no export to
query. Install it, choose an export destination, then point HEALTH_DATA_DIR at that folder.
On this page
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. MetricBridge's server reads a local JSON snapshot written by the iOS app and serves it through 16 read-only tools, so an agent can ask for a specific metric, trend or date range instead of loading everything into its context.
The practical difference: Apple's own export produces one large export.xml archive that most
tools cannot parse and that will not fit in a model's context window. An MCP server turns the same data into
queryable tools.
Install
Before you start. This server reads a file. It does not talk to your iPhone directly. You need three things: the MetricBridge iOS app (it writes the JSON export), a destination you point it at (iCloud Drive, a local folder, your LAN or a webhook), and Node.js 18+ on the machine running your agent. Without the app there is no export for this server to read.
The server is a single npm package with no dependencies. It requires Node.js 18 or later.
One command (Claude Code)
This is the fastest install. It registers the server and runs the current npm release through
npx, so there is nothing to download by hand:
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 full setup in four steps
- 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.
- 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. - Add the server to your MCP client. Add the server to your MCP client with one command, setting
HEALTH_DATA_DIRto your export folder. In Claude Code:claude mcp add health-export -e HEALTH_DATA_DIR="/path/to/your/export/folder" -- npx -y health-export-mcp - 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.
Other ways to run it
Run it once without installing anything:
npx -y health-export-mcp
Or install it globally:
npm install -g health-export-mcp
You can also run the file directly from a clone of the repository; it imports nothing outside Node's standard library, so there is no install step to audit.
.health-cache.json to a location
you choose. On macOS the default is
~/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents. Point
HEALTH_DATA_DIR at that folder (see environment variables).
The sixteen tools
All sixteen are read-only. None of them can write to Apple Health, and none of them make network requests.
get_mcp_status
Health check: reports the data source, how many metrics and workouts are available, the most recent data
date and a freshness summary. Call this first to confirm the bridge is connected.
{ "ok": true, "source": "file /Users/you/…/.health-cache.json",
"metricCount": 34, "workoutCount": 12, "lastDataDate": "2026-07-24" }
get_freshness
How current the export is, so an agent can decide whether to trust what it reads or ask you to refresh.
Returns stale against a stated threshold (26 hours by default, or
HEALTH_STALE_AFTER_HOURS, or the maxAgeHours you pass), age_hours since the
newest write, as_of, last_data_date and per-file write times. It applies the same rule
as the status --max-age cron gate.
| Parameter | Type | Notes |
|---|---|---|
maxAgeHours | number | Optional. Stale threshold in hours for this call. |
list_metrics
Lists every available metric with its unit, day count and date range. Use it to discover exact metric names
before querying: names are snake_case, such as heart_rate_variability.
get_health_metrics
The core data-retrieval tool. Returns daily values for one metric (or all metrics) over an optional date range, plus an aggregate.
| Parameter | Type | Notes |
|---|---|---|
metric | string | e.g. step_count. 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. |
get_trends
Compares the most recent N-day window against the prior N days and returns the change, percent change and direction. This is the tool behind questions like "compare my HRV this week versus last week".
| Parameter | Type | Notes |
|---|---|---|
metric | string | Required. |
window | integer | Days per window. Defaults to 7. |
{ "metric": "heart_rate_variability", "unit": "ms", "window": 7,
"recent": 59.657, "prior": 57.157, "change": 2.5,
"changePercent": 4.374, "direction": "up" }
compare_periods
Compares one metric between two arbitrary date periods and returns each aggregate plus the change and percent change. Use it when the two windows are not adjacent, for example this January against last January.
get_structured_export
Returns clean structured JSON for the chosen metrics and date range, shaped to drop straight into an agent's context window.
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 } } ] }
query_health_data
A natural-language convenience tool: pass a question such as "average HRV last month" and it routes to structured results. Prefer the specific tools above when you know which one you need. They are cheaper and more predictable.
list_events
The user's event timeline from health-events.json: medication starts, habit changes, doctor
visits, shift blocks, trips. Filter by type, tag or date range. Events are typed
by the user in the app (1.5 or later) and are what make before-and-after analysis honest.
get_workouts
Workouts with per-interval structure and running dynamics (power, stride length, vertical oscillation,
ground contact time) where recorded. Filters for activityType and date range, paginated with
limit and cursor.
get_profile
The opt-in agent profile (conditions, medications, goals, allergies, notes). A field the user did not enable is absent, and the answer says absence means withheld, never none.
get_sleep_sessions
Individual sleep sessions with local time offsets, attributed to the waking day the same way the daily cache is, so the two never disagree. Split nights appear as separate sessions on one day.
get_cycle_context
Day-in-cycle and coarse phase derived from user-logged periods only. Every answer states it is derived from logged data and is not predictive. Only present when the user opted in to sensitive categories.
correlate_metrics
Aligns two metrics day by day with an optional lag of up to 3 days (alcohol tonight against
HRV tomorrow), returns the aligned-pair count and Pearson r, and refuses to correlate on fewer than 10
aligned days. The payload itself says: association, not causation.
resolve_metric
Returns the canonical name and unit for any spelling of a metric (steps, StepCount,
Body Weight, hrv), the unit variants other apps use with the exact formula into the
canonical unit, and whether your export holds it. Pass a value and unit to convert one
number. A word that names several metrics comes back with candidates, never a guess. The data tools accept the
same aliases.
| Parameter | Type | Notes |
|---|---|---|
name | string | Required. Any spelling, e.g. steps or VO2 max. |
value, unit | number, string | Optional. Converts the value into the canonical unit, e.g. 180 lb to kg. |
Prompts, demo mode and the CLI
The server also ships 22 MCP prompts (daily brief, doctor visit prep, an /experiment protocol, shift
block comparisons and more), a --demo mode that serves a watermarked synthetic dataset so you
can try every tool before exporting anything, a --doctor diagnostics command, and
status --max-age <hours> as a freshness gate for cron jobs.
Client configuration
Any MCP client works. Replace SERVER_PATH with the path to server.mjs and
HEALTH_DATA_DIR with your export folder.
Since 1.4.0 the server is a set of small modules (server.mjs, healthstore.mjs,
envelope.mjs, normalize.mjs, metric-catalog.mjs, events.mjs,
prompts.mjs, demo.mjs, receiver.mjs).
The easiest installs are npx -y health-export-mcp or the one-click
bundle; if you download files by hand, keep them together in one folder.
Claude Desktop
Edit claude_desktop_config.json and merge into mcpServers, then restart Claude Desktop.
{
"mcpServers": {
"health-export": {
"command": "node",
"args": ["SERVER_PATH"],
"env": { "HEALTH_DATA_DIR": "/path/to/your/export/folder" }
}
}
}
Claude Code
Use the CLI. It writes the config for you. The npm route needs no download:
claude mcp add health-export -e HEALTH_DATA_DIR="/path/to/folder" -- npx -y health-export-mcp
Or point it at a local copy of the server:
claude mcp add health-export -e HEALTH_DATA_DIR="/path/to/folder" -- node "SERVER_PATH"
Claude Code also reads a project-scoped .mcp.json using the same mcpServers shape
as Claude Desktop. If pairing is enabled, 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.
Cursor
Cursor reads ~/.cursor/mcp.json (global) or .cursor/mcp.json (per project), using
the same mcpServers shape shown above.
VS Code
VS Code's MCP support reads .vscode/mcp.json in the workspace, again with the same server
shape. Reload the window after editing.
opencode
Add the server to opencode.json:
{
"mcp": {
"health-export": {
"type": "local",
"command": ["node", "SERVER_PATH"],
"enabled": true,
"environment": { "HEALTH_DATA_DIR": "/path/to/folder" }
}
}
}
Any other MCP client
The server speaks standard MCP over stdio, so any compliant client works: OpenClaw, Hermes, and others.
Point the client at node SERVER_PATH and set HEALTH_DATA_DIR.
Environment variables
| Variable | Purpose |
|---|---|
HEALTH_DATA_DIR | Folder containing .health-cache.json. Defaults to the current directory; on macOS the app's iCloud container is ~/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents. A leading ~ is expanded. |
PAIRING_SECRET | Only needed if the iOS app has pairing enabled. Must match the code shown in the app under Settings → Agent pairing. Without it the data tools return a clear "Locked" error rather than an empty result. |
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
Every published artifact is checksummed and signed, so you can confirm you are running exactly what was published before you execute it.
- 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
What agents can see
An agent never talks to your iPhone. It reads the files the MetricBridge app writes to a place you chose (iCloud Drive, a folder, or the local-network receiver), through this server on your own computer. 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): 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. - The current hourly window (
health-intraday.json): written only by hourly automations and replaced on every run. - Events and profile fields you entered (
health-events.json,health-profile.json): only what you typed, and only the profile fields you switched on. - 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 every tool here is read-only.
- 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.
- No individual raw samples. Agents get daily values, one summary per workout and per sleep session, and the hourly window.
- 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?
Yes. The server makes no network requests, has no dependencies, requires no account, and reads a local file you control. Apple Health access happens only in the iOS app, which requests read-only HealthKit permission and never writes back. Your data goes only to the destination you configure.
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 -e HEALTH_DATA_DIR="/path/to/your/export/folder" -- npx -y health-export-mcp. It requires Node.js 18 or later.
Do I need the iOS app?
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 16 read-only tools and 22 MCP prompts. 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 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.