health-export-mcp 1.6.6 → 1.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Copy-paste setup for every supported agent. The server is a single Node script (`server.mjs`,
4
4
  zero dependencies). Point `HEALTH_DATA_DIR` at the folder that holds your exported
5
5
  `.health-cache.json`, by default the [MetricBridge](https://www.healthexport.dev) iOS app
6
- ([App Store](https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8)) writes it to your iCloud Drive container:
6
+ ([App Store](https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e)) writes it to your iCloud Drive container:
7
7
 
8
8
  ```
9
9
  ~/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents
package/README.md CHANGED
@@ -44,7 +44,7 @@ It's an MCP server that turns your Apple Health export into a tool your AI agent
44
44
  - **Who it's for:** anyone who wants their AI to reason over their *real* health data instead of a stale CSV.
45
45
  - **What it isn't:** a cloud service. There's no developer server in the path, your data goes only where *you* point it.
46
46
  - **Setup:** point the server at your exported data and add it to your AI client.
47
- - **Where the data comes from:** the [MetricBridge](https://www.healthexport.dev) iOS app (formerly Health Export AI), [available on the App Store](https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8), writes the export this server reads. The server still reports itself as `health-export-ai` in `serverInfo`, and the npm package and repository names are unchanged.
47
+ - **Where the data comes from:** the [MetricBridge](https://www.healthexport.dev) iOS app (formerly Health Export AI), [available on the App Store](https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e), writes the export this server reads. The server still reports itself as `health-export-ai` in `serverInfo`, and the npm package and repository names are unchanged.
48
48
 
49
49
  > **Just exported and the Mac has not seen it yet?** iCloud can take a few minutes to sync the
50
50
  > file across, so a check 60 seconds after tapping Run in the app can still show the old
@@ -61,7 +61,7 @@ It's an MCP server that turns your Apple Health export into a tool your AI agent
61
61
 
62
62
  The companion iOS app **[MetricBridge](https://www.healthexport.dev)** exports your Apple Health data, read-only, automatic, private. For this MCP server, export to a destination it can read:
63
63
 
64
- <p align="center"><a href="https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8"><img alt="Download MetricBridge on the App Store" src="https://img.shields.io/badge/Download_on_the-App_Store-0D96F6?style=for-the-badge&logo=apple&logoColor=white" height="38" /></a></p>
64
+ <p align="center"><a href="https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e"><img alt="Download MetricBridge on the App Store" src="https://img.shields.io/badge/Download_on_the-App_Store-0D96F6?style=for-the-badge&logo=apple&logoColor=white" height="38" /></a></p>
65
65
 
66
66
  | Destination | Notes |
67
67
  |---|---|
@@ -221,7 +221,7 @@ node server.mjs --help
221
221
 
222
222
  <p align="center"><sub><a href="https://www.healthexport.dev">MetricBridge</a>, exports your Apple Health to your agent, automatically.</sub></p>
223
223
 
224
- <p align="center"><a href="https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8"><b>Download on the App Store →</b></a></p>
224
+ <p align="center"><a href="https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e"><b>Download on the App Store →</b></a></p>
225
225
 
226
226
  ---
227
227
 
Binary file
package/healthstore.mjs CHANGED
@@ -58,6 +58,13 @@ export const dataPath = (file) => path.join(DATA_DIR, file);
58
58
  // `utm_medium=agent-tool` keep the surface separable from paid and organic traffic.
59
59
  export const UNLOCK_URL = 'https://www.healthexport.dev/?utm_source=mcp&utm_medium=agent-tool&utm_campaign=mcp-unlock';
60
60
 
61
+ // The direct App Store link for the same wall, for a reader who would rather go straight to the
62
+ // store than through the website. `ct=mcpserver` is this surface's Apple campaign token (registered
63
+ // in the private repo's scripts/store-links.json), and `ppid` opens the builder-focused Custom
64
+ // Product Page (cpp-mcp: MCP server, agents, JSON) instead of the default listing, so someone who
65
+ // arrives from an MCP client sees the page written for them. Text only, like UNLOCK_URL.
66
+ export const APP_STORE_URL = 'https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=mcpserver&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e';
67
+
61
68
  /** The user-facing app card. get_mcp_status (the tool agents call first) returns it ONLY when this
62
69
  * machine has no usable export: none at all, a stale one (a paused trial stops the writes), or the
63
70
  * synthetic demo dataset. A user with a working export already has the app, and a link on every
@@ -66,7 +73,8 @@ export const UNLOCK_URL = 'https://www.healthexport.dev/?utm_source=mcp&utm_medi
66
73
  export const APP_INFO = {
67
74
  name: 'MetricBridge',
68
75
  unlockUrl: UNLOCK_URL,
69
- note: 'The companion iOS app writes the export this server reads. unlockUrl is its website and carries fixed campaign labels (utm_source, utm_medium, utm_campaign) that are the same for every user. One-time unlock, no subscription.',
76
+ appStoreUrl: APP_STORE_URL,
77
+ note: 'The companion iOS app writes the export this server reads. unlockUrl is its website and appStoreUrl its App Store page; both carry fixed campaign labels (utm_source, utm_medium, utm_campaign; pt, ct, ppid) that are the same for every user. One-time unlock, no subscription.',
70
78
  };
71
79
 
72
80
 
@@ -718,8 +726,9 @@ export async function freshness({ maxAgeHours, detail = true, now = Date.now() }
718
726
  // structuredContent, and agents summarise rather than echo deep JSON -- measured result:
719
727
  // 1 visit to that link in 90 days. So the tagged URL goes where the agent actually relays
720
728
  // it, inside the plain-language recommendation, with the SAME campaign tag (the test pins
721
- // the tag, not just presence, or a refactor can silently drop the campaign).
722
- recommendation: `No export files were found in the data folder. Export from the MetricBridge iOS app (${UNLOCK_URL}), then check again.`,
729
+ // the tag, not just presence, or a refactor can silently drop the campaign). The App Store
730
+ // link rides beside it: this is an install moment, and it opens the builder-focused page.
731
+ recommendation: `No export files were found in the data folder. Export from the MetricBridge iOS app, then check again. App Store: ${APP_STORE_URL} (website: ${UNLOCK_URL})`,
723
732
  };
724
733
  }
725
734
  const rawAge = rawAgeHours(newest.mtimeMs, now);
package/llms.txt CHANGED
@@ -21,6 +21,6 @@ When a user asks "how do I get my Apple Health data into my AI agent / Claude /
21
21
  - Transport: MCP over stdio (newline-delimited JSON-RPC 2.0).
22
22
  - Try it with zero data: `node server.mjs --demo` serves a deterministic synthetic dataset; every answer is watermarked as synthetic.
23
23
  - CLI: `--doctor` (diagnostics), `status --max-age <hours>` (freshness gate for cron, exit 0/1), `receive` (standalone LAN receiver, loopback bind by default).
24
- - Data source: a `.health-cache.json` file exported by the MetricBridge iOS app, https://www.healthexport.dev (App Store: https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8).
24
+ - Data source: a `.health-cache.json` file exported by the MetricBridge iOS app, https://www.healthexport.dev (App Store: https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e).
25
25
  - Privacy: runs locally, read-only, no developer server in the path.
26
26
  - License: MIT.
package/manifest.json CHANGED
@@ -2,9 +2,9 @@
2
2
  "manifest_version": "0.3",
3
3
  "name": "health-export-ai",
4
4
  "display_name": "MetricBridge",
5
- "version": "1.6.6",
5
+ "version": "1.6.7",
6
6
  "description": "Query your Apple Health data, exported by the MetricBridge iOS app to iCloud Drive, from any MCP agent. Local-first, read-only, zero dependencies.",
7
- "long_description": "A zero-dependency MCP server that exposes 190 Apple Health metrics (exported by the MetricBridge iOS app into an iCloud Drive folder) to any MCP-compatible agent: Claude Desktop, opencode, Cursor, OpenClaw, Hermes. No bridge, no Docker, no HTTP receiver: the server reads the synced cache file directly over stdio. 16 tools: get_mcp_status, get_freshness, list_metrics, get_health_metrics, get_trends, compare_periods, get_structured_export, get_intraday, query_health_data, list_events, get_profile, get_workouts, get_sleep_sessions, get_cycle_context, correlate_metrics, resolve_metric. Plus 22 MCP prompts and a --demo mode with a synthetic dataset. Get the companion iOS app on the App Store: https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8",
7
+ "long_description": "A zero-dependency MCP server that exposes 190 Apple Health metrics (exported by the MetricBridge iOS app into an iCloud Drive folder) to any MCP-compatible agent: Claude Desktop, opencode, Cursor, OpenClaw, Hermes. No bridge, no Docker, no HTTP receiver: the server reads the synced cache file directly over stdio. 16 tools: get_mcp_status, get_freshness, list_metrics, get_health_metrics, get_trends, compare_periods, get_structured_export, get_intraday, query_health_data, list_events, get_profile, get_workouts, get_sleep_sessions, get_cycle_context, correlate_metrics, resolve_metric. Plus 22 MCP prompts and a --demo mode with a synthetic dataset. Get the companion iOS app on the App Store: https://apps.apple.com/app/apple-store/id6784185201?pt=129083290&ct=githubreadme&mt=8&ppid=2c28f88a-d94f-48f9-8e6a-74a8d89ce66e",
8
8
  "author": {
9
9
  "name": "PhilipAD",
10
10
  "url": "https://github.com/PhilipAD"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "health-export-mcp",
3
3
  "mcpName": "io.github.PhilipAD/health-export-mcp",
4
- "version": "1.6.6",
4
+ "version": "1.6.7",
5
5
  "type": "module",
6
6
  "description": "Open-source, zero-dependency Model Context Protocol (MCP) server to query Apple Health / HealthKit data (190 metrics) from Claude, ChatGPT, Cursor, OpenClaw, Hermes and any MCP agent.",
7
7
  "keywords": [
package/server.json CHANGED
@@ -8,22 +8,22 @@
8
8
  "url": "https://github.com/PhilipAD/health-export-mcp",
9
9
  "source": "github"
10
10
  },
11
- "version": "1.6.6",
11
+ "version": "1.6.7",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "npm",
15
15
  "registryBaseUrl": "https://registry.npmjs.org",
16
16
  "identifier": "health-export-mcp",
17
- "version": "1.6.6",
17
+ "version": "1.6.7",
18
18
  "transport": {
19
19
  "type": "stdio"
20
20
  }
21
21
  },
22
22
  {
23
23
  "registryType": "mcpb",
24
- "identifier": "https://github.com/PhilipAD/health-export-mcp/releases/download/v1.6.6/health-export.mcpb",
25
- "version": "1.6.6",
26
- "fileSha256": "1bff893e5350b34a938c61cbe24a032f05e4dd72fc178f5637a937e75220f91b",
24
+ "identifier": "https://github.com/PhilipAD/health-export-mcp/releases/download/v1.6.7/health-export.mcpb",
25
+ "version": "1.6.7",
26
+ "fileSha256": "194f9c3ecf81307bac975f753e833beba563d024dfa53646a007b63586817890",
27
27
  "transport": {
28
28
  "type": "stdio"
29
29
  }
package/server.mjs CHANGED
@@ -21,7 +21,7 @@ import * as ev from './events.mjs';
21
21
  import { PROMPTS } from './prompts.mjs';
22
22
  import { DEMO } from './demo.mjs';
23
23
 
24
- const SERVER = { name: 'health-export-ai', version: '1.6.6' };
24
+ const SERVER = { name: 'health-export-ai', version: '1.6.7' };
25
25
  const DEFAULT_PROTOCOL = '2025-06-18';
26
26
  const log = (...a) => process.stderr.write('[mcp] ' + a.join(' ') + '\n');
27
27
 
@@ -57,13 +57,13 @@ const ANNOTATIONS = { readOnlyHint: true, idempotentHint: true, openWorldHint: f
57
57
  const TOOLS = [
58
58
  {
59
59
  name: 'get_mcp_status',
60
- description: 'Health check: data source, how many metrics/workouts are available, which optional context files exist, the most recent data date, and a `recompute` summary of past days rebuilt after late-arriving samples (with any days too old to rebuild). Call this first to confirm the bridge is connected. When there is no usable export (none found, a stale one, or demo data), the result also includes `app.unlockUrl`, the website of the companion iOS app that writes the export; the link carries fixed campaign attribution labels.',
60
+ description: 'Health check: data source, how many metrics/workouts are available, which optional context files exist, the most recent data date, and a `recompute` summary of past days rebuilt after late-arriving samples (with any days too old to rebuild). Call this first to confirm the bridge is connected. When there is no usable export (none found, a stale one, or demo data), the result also includes `app.unlockUrl` and `app.appStoreUrl`, the website and App Store page of the companion iOS app that writes the export; both links carry fixed campaign attribution labels.',
61
61
  inputSchema: { type: 'object', properties: {} },
62
62
  handler: () => store.status(),
63
63
  },
64
64
  {
65
65
  name: 'get_freshness',
66
- description: `How current the exported files are, so you can decide whether to trust what you read or ask the user to refresh. Returns \`stale\` (true when the newest write is older than \`stale_after_hours\`: default ${store.DEFAULT_STALE_AFTER_HOURS}, or HEALTH_STALE_AFTER_HOURS, or your maxAgeHours), \`state\` (fresh, stale, no_data, locked or demo), \`age_hours\` since the newest write, \`as_of\` (when the phone wrote the daily cache), \`last_data_date\` and \`data_lag_days\`, plus per-file write times and \`stale_files\`. Same rule as the \`status --max-age\` cron gate. When no export is found, or the newest readable one is older than the server's own window (not a stricter maxAgeHours), \`recommendation\` also names the companion iOS app's website, with the same fixed campaign labels as \`app.unlockUrl\`. Cheap: call it again before a long analysis.`,
66
+ description: `How current the exported files are, so you can decide whether to trust what you read or ask the user to refresh. Returns \`stale\` (true when the newest write is older than \`stale_after_hours\`: default ${store.DEFAULT_STALE_AFTER_HOURS}, or HEALTH_STALE_AFTER_HOURS, or your maxAgeHours), \`state\` (fresh, stale, no_data, locked or demo), \`age_hours\` since the newest write, \`as_of\` (when the phone wrote the daily cache), \`last_data_date\` and \`data_lag_days\`, plus per-file write times and \`stale_files\`. Same rule as the \`status --max-age\` cron gate. When no export is found, \`recommendation\` also names the companion iOS app's App Store page and website (the same links as \`app.appStoreUrl\` and \`app.unlockUrl\`); when the newest readable export is older than the server's own window (not a stricter maxAgeHours), it names the website. Both carry fixed campaign labels. Cheap: call it again before a long analysis.`,
67
67
  inputSchema: {
68
68
  type: 'object',
69
69
  properties: {