Connect Apple Health to opencode: Native MCP Setup

opencode is a terminal agent, so it never gets a Settings panel with a nice "add server" button. Everything lives in one JSON file. This is the exact mcp block that puts your real Apple Health numbers behind opencode, plus the tool-scoping trick that keeps 16 health tools out of your context window until you need them.

By MetricBridge · Updated 15 October 2026 · ~8 min read

AI-assisted, human reviewed. How we use AI

Quick answer. opencode supports MCP servers natively through the mcp key in opencode.json. Add a type: "local" entry whose command is ["npx", "-y", "health-export-mcp"], set HEALTH_DATA_DIR to the folder holding your export, and opencode can call 16 read-only Apple Health tools in the TUI. Nothing is uploaded: the server reads a local JSON file and makes zero runtime network calls.

What opencode does differently from Cursor or Claude Desktop

If you have already wired Apple Health into another MCP client, two opencode details will trip you up.

  • It is TUI-first. There is no MCP panel to inspect. Verification happens in the terminal with opencode mcp list and by asking the agent a question.
  • Tool names carry a server prefix. Call your entry health-export and the tools register as health_export_get_trends, health_export_compare_periods, and so on. That prefix is the handle for tool-scoping globs, so pick the name deliberately.

What you need before starting

  1. MetricBridge on iOS: install it, grant read-only Apple Health access, turn on export. iCloud Drive is the simplest destination because it lands on your Mac without a sync client. The app is a single $24.99 one-time unlock covering export, the MCP tools, and the on-device Ask and Weekly Brief.
  2. Node.js 18 or later: npx ships with it.
  3. opencode installed: any current release.

The two values you will type twice

HEALTH_DATA_DIR: absolute path to the folder holding your .health-cache.json. With iCloud on macOS:

/Users/you/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents

Server command: npx -y health-export-mcp, which pulls the published package on demand so there is nothing to download by hand.

Expand ~ yourself. Config files do not understand a tilde, and a failure here looks like a timeout rather than a path error.

Configure opencode

opencode reads opencode.json (or opencode.jsonc) from your project directory and from the global config location. Project values override global ones. Create or edit the file and add a mcp entry:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "health-export": {
      "type": "local",
      "command": ["npx", "-y", "health-export-mcp"],
      "enabled": true,
      "environment": {
        "HEALTH_DATA_DIR": "/Users/you/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents"
      }
    }
  }
}

That is the whole bridge. A few config details worth knowing:

  • type and command are required for a local server. command is an array, not a shell string, so you cannot chain with &&.
  • environment passes variables to the spawned process. Add "PAIRING_SECRET": "your-code" here if you enabled pairing in the iOS app.
  • timeout defaults to 5000 ms and only caps how long opencode waits when fetching the tool list at startup. Raise it if your first npx run has to download the package on a slow connection.
  • Set enabled: false to keep the block but skip the server. Handy when you want the health data available on one machine and not another.

Verify it connected

From the directory where you added the config, run the MCP subcommand:

$ opencode mcp list

health-export   local   connected   16 tools

If that line says disconnected, opencode never started the process. Nine times out of ten it is npx not being on the PATH of the shell that launched the TUI (common with version managers, where the TUI inherits a thinner environment than your login shell). Point command at the absolute path from which npx and reload.

Run your first query

MCP tools sit alongside the built-in ones, but naming the server makes the intent unambiguous. Start with a status check:

You: Use the health-export server to call get_mcp_status and tell me
     what it reports.

opencode: Calling health_export_get_mcp_status...

{"status":"ok",
 "dataSource":"/Users/you/Library/Mobile Documents/...",
 "serverVersion":"1.6.1"}

The server is running and can see your health cache. All 16 tools
are available.

Then ask something real. Raw tool output lands in the transcript first, and the model interprets it second:

You: Call get_trends on health-export for resting heart rate over the
     last 14 days and flag any deviation from my personal baseline.

► health_export_get_trends(metric: resting_hr, period: 14d)

{
  "metric": "HKQuantityTypeIdentifierRestingHeartRate",
  "period": "14d",
  "avg": 56,
  "prev_avg": 58,
  "change_pct": -3.45,
  "unit": "bpm",
  "samples": 280
}

opencode: Resting heart rate averaged 56 bpm over the last 14 days,
down 3.5% from the prior fortnight (280 samples, both periods).
Two more calls worth making from here: compare_periods on HRV and
sleep, or correlate_metrics if you want to test whether the sleep
change tracks the HR change.

No CSV attachment, no unit conversion, no copy-paste. The agent gets typed data and computes on it. The bridge's 16 read-only tools are get_mcp_status, get_freshness, list_metrics, resolve_metric, get_health_metrics, get_trends, compare_periods, get_intraday, query_health_data, correlate_metrics, list_events, get_profile, get_workouts, get_sleep_sessions, get_cycle_context and get_structured_export, plus 22 prompts.

Keep health tools out of your coding context

opencode's own documentation warns that MCP servers add to the context window and that a chatty server can eat it. Sixteen health tools is not the worst offender, but if you use opencode for actual code work you probably do not want them live in every session. Disable the server globally and switch it on for one agent:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "health-export": {
      "type": "local",
      "command": ["npx", "-y", "health-export-mcp"],
      "enabled": true,
      "environment": { "HEALTH_DATA_DIR": "/Users/you/export/here" }
    }
  },
  "tools": {
    "health_export_*": false
  },
  "agent": {
    "health": {
      "tools": { "health_export_*": true }
    }
  }
}

The glob is the part people miss. opencode registers the server's tools with the server name as a prefix, so health_export_* targets exactly this server and nothing else. Rename the server entry and you must rename the glob too.

On-device answers vs shipping your health rows to a cloud

There are two popular architectures for "ask AI about my health data," and they differ in where the computation happens, not in how nice the chart looks.

QuestionCloud health AIOn-device app plus a local MCP bridge
Where is the answer computed? On the vendor's servers, because the model that answers lives there. On the iPhone for in-app answers, on your own machine for agent queries, so the vendor's servers never hold the rows. healthexport.dev/mcp [E2]
Who can read the raw data? Anyone with cloud access, plus whatever retention allows. The device that produced it: the server runs locally and makes zero runtime network calls. health-export-mcp on GitHub [E1]
Is there an account? Usually required, because a cloud needs a tenant to bill. No account and no sign-in: the bridge exposes 16 tools and 22 prompts over local files. healthexport.dev/mcp [E2]
Can your own agent use it? Only if the vendor ships an API, which most consumer health AIs do not. Yes. The MCP surface is open source and read-only, so the same data feeds opencode, Claude, Cursor, or whatever you run next. [E1]

Sources: [E1] the public server repository at github.com/PhilipAD/health-export-mcp; [E2] the MCP page at healthexport.dev/mcp. Captured 11 October 2026.

This is a contrast of approach, not a named rival. A cloud health AI is a reasonable product; it just puts the model somewhere you do not control. An on-device app with a local MCP bridge keeps the rows where they were created. The trade is that you configure the server yourself, which is what the rest of this page is about.

Troubleshooting

"health-export" shows as disconnected

opencode failed to spawn the command. In order of likelihood: npx is not on the TUI's PATH, HEALTH_DATA_DIR still contains a literal ~, or the JSON has a trailing comma. Run the same command by hand to see the real error: HEALTH_DATA_DIR="/your/path" npx -y health-export-mcp. If it starts and waits on stdin, the config is fine.

The tool list never finishes loading

That is the 5000 ms timeout. On a cold cache npx fetches the package before the process answers, so set timeout to 20000 for the first run. Warm runs are instant.

The server starts but reports no data

Check three things: export is on in the iOS app, a .health-cache.json file exists in the folder, and your sync client finished downloading it here. ls -la "<your-HEALTH_DATA_DIR>" confirms all three at once. If you added a tools glob and the tools still do not show up, check the prefix against the server key: a server named health-export publishes tools as health_export_*, and that join is not spelled the same way as the config entry.

Get Apple Health into opencode in two minutes

One purchase unlocks the export, the on-device Ask and Weekly Brief, and the raw MCP tools. No subscription, no account, nothing on our servers.

Frequently asked questions

Does opencode support MCP servers natively?

Yes. opencode reads servers from the mcp key in its config and supports local servers (type: "local", started by a command array) and remote ones (type: "remote", reached by url). Their tools join opencode's built-in tools.

Where does opencode look for its config file?

It reads opencode.json or opencode.jsonc from your project directory and from the global config location. Project values override global defaults.

Does connecting Apple Health to opencode send my health data anywhere?

No. The server reads a local JSON file and executes the query on your machine, with zero runtime network calls and no telemetry or account. Only the numbers the model decides to quote enter your prompt to whichever model provider you configured.

Why do my health tools show up with a prefix?

opencode registers MCP tools with the server name as a prefix, so health_export_* targets exactly that server in a tool-scoping glob. Rename the server key and the prefix changes.

How do I keep 16 health tools from flooding opencode's context?

Disable them globally under the tools key with a glob such as health_export_*, then enable them only inside the agent that needs them. opencode's docs recommend being selective, because tool definitions add to the context window.

MetricBridge · Apple Health → your AI agent, privately. · Home · Privacy · Terms · Support