The cardinal design rule: every field name in HealthKite MCP’s JSON is Apple’s own. Field-naming choices that were already made by Apple in the HealthKit framework are kept; we don’t invent.

What that means in practice

  • Workout activity type"HKWorkoutActivityTypeRunning", not "running".
  • Quantity sample type identifiers"HKQuantityTypeIdentifierHeartRate", not "hr" or "heart_rate".
  • Workout metadata keys"HKMetadataKeyIndoorWorkout", "HKAverageMETs", "HKWeatherTemperature" — verbatim from Apple’s metadata dictionaries.
  • Source revision shape → preserves Apple’s HKSourceRevision structure (source.name, source.bundleIdentifier, version, productType, operatingSystemVersion).
  • Units → strings produced by HKUnit.string(). Heart rate is "count/min", distance is "m", energy is "kcal". No conversion to user preference at the wire layer.
  • Dates → ISO 8601 UTC (2026-05-09T16:11:50Z) at top levels; integer seconds offsets inside columnar sample arrays.

Why

Five reasons, in priority order:
  1. Self-documenting. A consumer who doesn’t know HealthKite MCP can still parse the JSON by looking up HKQuantityTypeIdentifierRunningPower in Apple’s HealthKit documentation. Zero app-specific docs required.
  2. Future-proof. When Apple ships a new workout activity type or quantity identifier next year, it just appears in the output with its canonical name. No HealthKite MCP release needed to “support” it.
  3. Legally clean. Field names are descriptions of Apple’s API surface, not borrowed from any competing product’s schema.
  4. Lossless. Without unit conversion, no rounding error. Without aggregation, every sample is preserved. Receivers do their own conversion or rollup if they want.
  5. Architecturally honest. The JSON is what HealthKit returned, with provenance hoisted to deduplicate. Nothing more, nothing less.

Anatomy of a workout

{
  "uuid": "06E9D6D6-7E37-406C-8465-1DAAD7C223A1",
  "workoutActivityType": "HKWorkoutActivityTypeRunning",
  "startDate": "2026-05-09T16:11:50Z",
  "endDate": "2026-05-09T16:44:24Z",
  "duration": 1953.68,
  "totalDistance":     { "value": 4855.06, "unit": "m" },
  "totalEnergyBurned": { "value": 482.62,  "unit": "kcal" },
  "averageHeartRate":  { "value": 164.81,  "unit": "count/min" },
  "metadata": {
    "HKAverageMETs": "11.1232 kcal/hr·kg",
    "HKElevationAscended": { "value": 40.8, "unit": "m" },
    "HKIndoorWorkout": false,
    "HKTimeZone": "America/Chicago",
    "HKWeatherHumidity":   { "value": 59,   "unit": "count" },
    "HKWeatherTemperature": "70.7173 degF"
  },
  "sampleEncoding": "columnar-v1",
  "src": 0,
  "sources": [
    { "id": 0, "device": {...}, "sourceRevision": {...} }
  ],
  "samples": {
    "HKQuantityTypeIdentifierHeartRate": {
      "unit": "count/min",
      "t": [5, 10, 15, 20, ...],
      "v": [108, 112, 120, 124, ...]
    },
    "HKQuantityTypeIdentifierRunningPower": { ... },
    "HKQuantityTypeIdentifierStepCount":    { ... }
  },
  "statistics": {
    "HKQuantityTypeIdentifierHeartRate": {
      "average": { "value": 165.92, "unit": "count/min" },
      "minimum": { "value": 117,    "unit": "count/min" },
      "maximum": { "value": 191,    "unit": "count/min" }
    }
  },
  "workoutEvents": [
    { "type": "segment", "dateInterval": { "start": "...", "end": "..." }, "metadata": {} }
  ]
}
Three structural features are HealthKite MCP-specific and worth understanding:
  • sampleEncoding: "columnar-v1" — see Columnar encoding.
  • sources array with src indices — see Provenance hoisting.
  • workoutActivityType as the full Apple enum string — see above. We don’t shorten to "running".
These three are the only places HealthKite MCP adds structure beyond what HealthKit literally returns. Everything else is a faithful encoding of the Swift objects.

What HealthKite MCP does NOT do

  • We do not bucket heart rate into Min/Avg/Max per minute. The full per-sample series is preserved.
  • We do not convert distance, weight, or temperature to user-preferred units. The iOS UI converts for display; the wire data stays in HealthKit-native units.
  • We do not add derived metrics (sleep score, training load, time-in-zone). Receivers compute those if they want.
  • We do not dedupe upstream data quality issues (e.g., a third-party app writing duplicate samples). What HealthKit gave us is what you get.

Comparison to Health Auto Export

Health Auto Export (HAE) is the paid commercial product in the same space. Different design choices:
HAEHealthKite MCP
Field namesinvented (heartRateData, activeEnergy, walkingAndRunningDistance)Apple’s (HKQuantityTypeIdentifierHeartRate, etc.)
Heart rate seriesbucketed Min/Avg/Maxevery raw sample
Unitsconverted to user pref (mi/km, lb/kg)HealthKit-native always
Sample shapeper-sample dict (~250 B per sample)columnar (~10 B per sample)
Typical 30-min run~1.2 MB~80 KB
Licenseclosedopen MCP (MIT)
Costfreemiumfree
Neither approach is wrong. HAE’s shape is what users already have dashboards wired up against; HealthKite MCP’s shape is what an LLM agent can pull, parse, and reason about efficiently.