Rust, DuckDB or Zero Dependencies: Three Ways One MCP Server Reads a Single Apple Health Export

Every Apple Health MCP server you can install today starts from the same pile of records and ends at the same place: your agent asks a question, the server answers from your data. What differs is everything in between, and the in-between is what you actually run, debug and keep fresh for years.

By MetricBridge · Published 12 November 2026 · ~7 min read

AI-assisted, human reviewed. How we use AI

Quick answer

There are three live ways an open-source Apple Health MCP server gets at your data. One parses the native export.xml directly and loads it into a local DuckDB database. One pre-processes the export into CSV with a separate iPhone app, then loads that CSV into an in-memory DuckDB. One reads a JSON file the exporter already wrote, with no database engine and no dependencies at all. Same records, three different numbers of steps between the file and a tool call, and that count is the thing that decides how fresh your data is and how much can break on a Tuesday.

The one file everyone starts from

Apple's Export All Health Data button produces a zip. Unzipped, it is export.xml plus optional electrocardiograms/ and workout-routes/ folders. The XML is the awkward part: a single document, often hundreds of megabytes to several gigabytes, one row per sample, and a schema that has to be read rather than assumed. Everything downstream is a choice about how to turn that document, or some intermediate format, into something an AI tool can query quickly.

Way one: parse the native export, in Rust, into DuckDB

vpetersson/apple-health-mcp-server is a Rust server with a deliberately narrow thesis: read Apple's own export directly, do it fast, and stop there. Its import step streams export.xml with a SAX-style parser and bulk-loads records, workouts, ECG readings and GPX route points into a local DuckDB file. Then a serve step exposes the data over MCP, standard input or Streamable HTTP.

apple-health-mcp import --export-dir /path/to/apple_health_export
apple-health-mcp serve --transport stdio

It ships twelve tools, all read-only, including one that runs arbitrary read-only SQL against the DuckDB database, which is the real payoff of a database backend: the agent is not limited to the questions the author predicted. Re-importing is safe because records are deduplicated by content hash, so a new export adds only the delta. The author's own write-up reports a 2.5GB decompressed dataset importing in under a minute on a laptop, and the README is candid that the project exists because a CSV-based peer could not handle long time ranges.

What you pay for it: a Rust build or a Homebrew install, a two-step import-then-serve routine, a database file to keep, and data that is exactly as current as the last time you manually exported.

Way two: pre-process to CSV, then DuckDB in memory

neiltron/apple-health-mcp takes the other common route. It runs on Node.js 22 or newer and reads CSV exports produced by Simple Health Export CSV, a separate iPhone app, loading them into DuckDB in memory. It states plainly that the native export.xml format is not supported, that the database is rebuilt from the CSV files on each launch, and that it makes no network requests and confines file access to the directory you point it at.

{
  "mcpServers": {
    "apple-health": {
      "command": "npx",
      "args": ["-y", "@neiltron/apple-health-mcp"],
      "env": { "HEALTH_DATA_DIR": "/path/to/your/unzipped/health-export" }
    }
  }
}

Three tools cover schema discovery, one analytical query, and a periodic summary. There is a memory ceiling you can raise, and the in-memory design means the first query after a launch pays the reload. the-momentum/apple-health-mcp-server is a third sibling in the same family, mounting the same idea over DuckDB, Elasticsearch or ClickHouse and exposing both raw XML readers and query tools.

What you pay for this one: you own a second iPhone app and an export step before the server sees anything, and the CSV conversion is a moving part between your Health data and the query.

Way three: read the JSON the app already wrote, with no database

The third shape deletes the middle. Instead of teaching a server to parse Apple's format, it has the exporter write a small, well-shaped JSON file in the first place, and the server reads that. Ours, health-export-mcp, does exactly this: the iOS app writes 194 metrics as JSON or CSV to a folder you choose, and the MCP server reads that folder. There is no XML parse, no CSV conversion, no database file, and no build step.

claude mcp add health-export -- npx -y health-export-mcp

On a Mac that is the whole setup. Windows and Linux set HEALTH_DATA_DIR to the export folder. The server ships 22 tools, 20 of them read-only, and no tool writes to Apple Health. Because the app exports in the background, the file the server reads stays current without you remembering to re-run anything, which is the point of removing the import step rather than optimising it.

What you pay for it: less. You give up a SQL engine and the ECG and GPX route tooling that a native-export parser carries. In exchange there is no second app, no database to manage, and nothing to compile.

What the choice actually changes

It is tempting to frame this as a speed race, and the three servers do differ in how fast a full import runs. But for daily use the sharper axis is how many things sit between your data and a tool call, because each one is something you have to install, run and keep working.

  • Native XML into DuckDB. One artifact (the export zip), two steps (import, then serve), one database file. Freshness equals your last manual export. You get SQL and the extras the parser handles.
  • CSV into DuckDB. Two products (a CSV exporter app plus the server) and a conversion step. Freshness equals the last export plus the last conversion. You get SQL with the least code to read the XML yourself.
  • JSON the app wrote. Zero extra steps beyond the app you already run, no database engine, no compile. Freshness tracks the app's background export. You trade a SQL engine for fewer moving parts.

None of these is wrong. If you already have a native export and want raw SQL over ECGs, way one is the right tool. If you already use a CSV exporter, way two slots in. If what you want is for your agent to answer questions about your Apple Health this afternoon, the shortest pipeline wins.

The checkable part of the zero-dependency claim

"No network calls" is the kind of sentence that deserves a test rather than trust, so here is the one I ran against our own package. It is public, and you can repeat it in a minute.

Clone health-export-mcp and open package.json: the dependencies block is empty. Then search every shipped module for an HTTP client. The only matches are receiver.mjs, the optional LAN receiver you have to start yourself, and mock-endpoint.mjs, a test mock. Neither file is in the read path, so the code that answers a query has no HTTP client to call with. That is stronger evidence than a policy sentence, because it is a property of the code you can grep rather than a promise about behaviour you cannot see.

The test in one line. Empty dependencies block, and an HTTP-client search whose only hits are files you start yourself. No client in the read path means nothing in the read path can reach out.

Where MetricBridge lands

MetricBridge is a private, on-device health AI for iPhone, with a Mac app and an Apple Watch app, plus a free open-source MCP server. It reads Apple Health read-only, answers your questions on the device with a provenance card on every answer, and writes 194 metrics as clean JSON or CSV to a destination you choose. There is no account, no sign-in, and no server of ours in the path. The developer half is the same decision in a different shape: a zero-dependency MCP server, stdio by default, 22 tools (20 read-only), reading a folder you own.

It is one product: a 7-day free trial, then a $24.99 one-time unlock that covers the export, the MCP tools, on-device Ask, the Weekly Brief, and the Mac and Apple Watch apps. Not a subscription, and not something that meters the parts you use most.

And the boundary that applies to all of it: this is a wellness tool, not a medical one. It reads your own data and describes it against your own baseline. It does not detect, treat or monitor a condition, and it should never be asked to.

FAQ

What are the three ways an MCP server can read an Apple Health export?

One: parse the native export.xml directly, which is what a Rust server that streams the XML into DuckDB does. Two: pre-process the export into CSV with a separate iPhone app, then load that into DuckDB, which is what a TypeScript server that reads CSV exports does. Three: skip the export format entirely and read a JSON file the exporter already produced, which is what a zero-dependency server that reads the app's own output does. Same data, three different amounts of work between the file and a tool call.

Do I need DuckDB to query my Apple Health data with an AI?

No. DuckDB is one valid choice: it gives you SQL over the data and handles aggregations well, and two of the three servers above use it. It also means a database file or an in-memory database to load before the first query. A server that reads a small JSON file the app already wrote can answer the same common questions without a database engine at all, because the file is already the shape the tools want.

How do I check whether an MCP server makes network calls?

Read its dependency manifest and its source, both of which are public for an open-source server. A zero-dependency package has an empty dependencies block, so there is no HTTP client to import. Then search the shipped source for an HTTP module: if the only matches are files you have to start yourself, the default read path has nothing to call out with. That takes about a minute and it is stronger evidence than a README sentence.

Which approach keeps the data freshest?

The one with the fewest manual steps. Any pipeline that starts with pressing Export All Health Data in the Health app is only as current as the last time you did that. A pipeline where the app exports in the background, and the server re-reads that folder on each query, tracks your data continuously without you remembering to re-run an import.

A server with nothing between your data and the answer

Point your agent at the folder the app writes and ask. No database to load, no second app, no network client in the read path.

Where it goes: answers are computed on the iPhone and your health data never reaches us or a cloud AI; exports go only to the destination you pick. What you get: all 194 metrics, on-device Ask with a provenance card on every answer, the Weekly Brief, and the Mac and Apple Watch apps. Price: $24.99 one time after a 7-day free trial, not a subscription. Wellness, not medical advice.