Two People, One Mac: Who Can Read Whose Apple Health Data

Every Apple Health MCP setup is isolated by something: a per-person token, or a per-machine file. Those are different boundaries with different failure modes, and on a shared Mac the difference decides whether your partner's account can read your export.

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

AI-assisted, human reviewed. How we use AI

Quick answer

A hosted connector isolates people with a token: each person signs in, each person gets their own account, and the vendor's servers hold the boundary (and the data). A local bridge isolates with files: one export folder, one HEALTH_DATA_DIR, and whatever the macOS account and the file permissions around that folder allow. On a Mac with separate user accounts, the file route is already scoped per person. On one shared login, it is not, and no local server can tell the two of you apart.

What a shared Mac actually exposes

macOS scopes the home directory per account, and the default export destination on a Mac lives inside it:

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

That path belongs to one user. iCloud Drive is per Apple Account too, so a second person on a second macOS account gets their own folder and never sees yours. Two cases break that:

  • One shared login. Both people are the same user. Every process either of you runs can read every file the other one's export wrote. No MCP server can separate you, because at the file-system level there is nothing to separate.
  • A shared destination. If the export goes to a folder that syncs for both of you (a NAS mount, a shared cloud folder, a Dropbox both accounts join), the file is readable by whoever can open that folder.

Check yours in about 30 seconds

Ask the file system first, then ask the server. The server ships a diagnostics command that prints the folder it chose, why it chose it, the age of every file it reads, the pairing state and the encryption state:

stat -f "%Sp %Su %Sg  %N" ~/Library/Mobile\ Documents/iCloud~ai~healthexport~app/Documents
# drwx------ rdpsuser  staff  /Users/rdpsuser/Library/...

npx -y health-export-mcp --doctor

Real output from the published 1.10.2 build, on a folder with no export in it yet:

health-export-mcp doctor (1.10.2)
  node:            v24.15.0
  data dir:        /Users/you/health-export
  chosen by:       HEALTH_DATA_DIR
  pairing:         not required (no .health-pair.json, no PAIRING_SECRET)
  files:
    .health-cache.json             absent
    .health-workouts-cache.json    absent
    health-intraday.json           absent
    health-events.json             absent
    health-events-agent.json       absent
    health-profile.json            absent
    health-sessions.json           absent
    health-cycles.json             absent
    health-days.json               absent
    health-sources.json            absent
    health-readings.json           absent
    health-strength.json           absent
    health-labs.json               absent
    health-tags.json               absent

Two lines in that output do the work. chosen by tells you whether the folder came from HEALTH_DATA_DIR, the app's iCloud folder, or a fallback, which is how you catch a config pointing at the wrong person's folder. pairing tells you whether access is gated at all. If you want a narrower folder, chmod 700 on the export directory leaves it readable by that account and nothing else.

The two values that decide access

Both live in the client's config, and neither belongs on a command line:

{
  "mcpServers": {
    "health-export": {
      "command": "npx",
      "args": ["-y", "health-export-mcp"],
      "env": {
        "HEALTH_DATA_DIR": "/Users/you/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents",
        "PAIRING_SECRET": "the code from Settings > Agent pairing"
      }
    }
  }
}

HEALTH_DATA_DIR is which export this client reads. PAIRING_SECRET is the code the iOS app shows under Settings, Agent pairing, and it is the difference between a server that answers anyone who can spawn it and one that answers only a caller holding the code. Pass it through env in the config file rather than as an argument: command-line arguments land in shell history and in the process list, where the other person on the Mac can read them with ps.

The one leg that actually travels

Stdio stays on the machine. The LAN receiver is the part that crosses the wire: start the server with HEALTH_LISTEN=1 and the app can push its daily summary straight to it over HTTP or WebSocket instead of through a synced folder. On that leg the pairing token rides in a plain HTTP header, so the honest hardening step is to refuse plaintext pushes once the app encrypts that destination:

HEALTH_LISTEN=1 HEALTH_REQUIRE_ENCRYPTED=1 npx -y health-export-mcp

With that set, a push the server cannot decrypt is answered 422 with a machine-readable reason (passphrase_missing, passphrase_mismatch, tampered, malformed, unsupported_version, passphrase_file_unreadable, encryption_required) rather than being accepted or silently dropped. Host and origin checks apply as well, and the same passphrase and token rules cover the strength-log push.

Encrypt the export, and know what that buys

Export encryption is switched on per destination in the app (Settings, Export encryption). Give the server the same passphrase and every file is decrypted in memory on your Mac:

HEALTH_EXPORT_PASSPHRASE_FILE=~/.config/metricbridge/passphrase npx -y health-export-mcp

The format is a versioned envelope, metricbridge.enc v1, built on Node's own crypto: AES-256-GCM for the payload, PBKDF2-HMAC-SHA256 at 600,000 iterations for the key derivation, HKDF-SHA256 to split off the encryption key and an 8-byte key-check value, and a fresh 12-byte nonce per message. Every header field is bound in as associated data, so a tampered header fails the open rather than being ignored.

That is genuinely useful, and the limits matter more than the feature list. Encryption protects the export at rest in the destination and the LAN push on the wire, plus the integrity of every sealed file. It does not protect an unlocked phone, this computer (which holds the passphrase), metadata such as file sizes and timing, a whole sealed file being rolled back or replayed, files you hand out of the app yourself, or a weak passphrase guessed offline. The app requires at least 8 characters, and the passphrase is never logged.

The honest limit of the file route. If two people share one macOS login, no local configuration fixes it. Separate accounts are the boundary. Everything above is defence in depth around a boundary that has to exist first.

Four-step setup for two people on one Mac

  1. Separate macOS accounts. This is the isolation. Everything else is hardening on top of it.
  2. One HEALTH_DATA_DIR per person, in that person's own MCP config, never a shared folder both accounts can open.
  3. PAIRING_SECRET in the config's env block, never as a command-line argument, so it stays out of shell history and ps.
  4. Encrypted export, and HEALTH_REQUIRE_ENCRYPTED=1 on the receiver, so a plaintext push is refused instead of trusted.

Then confirm it with the two reads that report state instead of assuming it: npx -y health-export-mcp --doctor for the folder, the pairing line and the encryption line, and get_mcp_status from the agent, which reports the data source it found, lastDataDate and whether the export it read was encrypted.

FAQ

If two people use the same Mac login, can a local Apple Health MCP server tell them apart?

No. A local server reads whatever is in the folder you point it at, so on one shared login both people are the same user as far as the file system is concerned. Separate macOS accounts are what create the boundary, not the server.

Is a hosted connector's per-person token safer on a shared Mac?

It isolates differently, not automatically better. Each person gets their own token and account, so the vendor's account model holds the boundary. The trade is that the data sits on the vendor's servers rather than on your Mac.

Does encrypting the export stop someone else on my Mac from reading it?

It stops them reading the files themselves. It does not cover an unlocked phone, this computer (which holds the passphrase), metadata such as file sizes and timing, a whole sealed file being rolled back or replayed, files you share by hand out of the app, or a weak passphrase guessed offline. The app requires at least 8 characters.

Where should the pairing code and the export passphrase live?

In the client's env block in its config file, never on the command line: an argument lands in shell history and in the process list. For the passphrase, point the server at a file with HEALTH_EXPORT_PASSPHRASE_FILE so it is read from disk instead of the environment.

Set it up once, then read it locally

MetricBridge exports all 194 metrics to a folder you choose, and the MCP server reads them on your machine with no account in the path. 7-day free trial, then one $24.99 unlock for the app and the Mac and Apple Watch apps, with no subscription.

Server facts read from the published health-export-mcp 1.10.2 README, SECURITY.md and the --doctor output on 12 November 2026. MetricBridge is a general-wellness app, not a regulated medical device. Wellness information, not medical advice.