MCP server for the Fitbit Web API, which shuts down on 30 September 2026. Retired, superseded by google-health-mcp.
Server has 15 tools with complete input schemas and descriptions. Naming follows verb_noun convention (fitbit_get_*, fitbit_sync, fitbit_trend_analysis). Descriptions are detailed (150-400 chars) and explain WHAT, WHEN, and RETURN values. However, output schemas are not formally documented in the tool definitions, responses are formatted as JSON strings rather than structured objects with declared fields. Parameters lack enums for constrained values (e.g., 'period' accepts 'daily|weekly|monthly|quarterly' but no enum constraint). Error handling is minimal, no recovery guidance or actionable error messages visible in code. Security: no secrets exposed as parameters (auth via require_auth decorator). Composition is sound: tools are single-purpose and chainable (sync → get_* → trend_analysis). Baseline: avg tool description ~280 chars (within 194-char median but acceptable for domain complexity); all params have descriptions; schemas present but output types undocumented.
Get daily activity summaries (steps, calories, active minutes, distance). Returns data from the local cache by default. Use live=True to fetch from Fitbit API. Run fitbit_sync first to populate the cache. Note: live=True fetches one API call per day - avoid large ranges to stay within the 150 requests/hour rate limit. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. live: If true, fetch directly from Fitbit API instead of cache. Returns one entry per day with steps, calories, active minutes, distance. active_minutes = very_active + fairly_active (excludes lightly active).
Get daily Active Zone Minutes (AZM) - Fitbit's headline cardio metric. AZM counts minutes spent in heart rate zones at or above Fat Burn intensity. Cardio and Peak zone minutes count double. Returns from local cache by default, auto-syncing if stale. Use live=True to bypass the cache. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. live: If true, fetch directly from Fitbit API instead of cache. Returns one entry per day with total_minutes plus per-zone breakdown (fat_burn_minutes, cardio_minutes, peak_minutes). Distinct from active_minutes in fitbit_get_activity, which counts wall-clock minutes regardless of intensity.
Get nightly breathing rate (avg breaths per minute during sleep). Sourced during sleep tracking. Useful as an illness/recovery signal: sustained increases of 2-3 bpm above personal baseline can indicate incipient infection or strain. Returns from cache by default, auto-syncing if stale. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. live: If true, fetch directly from Fitbit API instead of cache. Returns one entry per night with breaths_per_min. Typical adult range: 12-20 bpm at rest.
Output schemas not formally documented. Tools return format_response() JSON strings without declared field types or structure. LLMs cannot infer what fields to expect or plan downstream calls.
Constrained parameters lack enum declarations. 'period' in fitbit_trend_analysis and fitbit_get_goals accepts 'daily|weekly|monthly|quarterly' but no JSON Schema enum constraint. LLMs may hallucinate invalid values.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 60 | <=2025-11-25 | v2 |
Get Cardio Fitness Score (VO2 Max estimate). Fitbit estimates VO2 Max from resting HR, HR during walks/runs, and demographics. Updates roughly weekly. Returns from cache by default, auto-syncing if stale. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. live: If true, fetch directly from Fitbit API instead of cache. Returns entries with vo2_max_low and vo2_max_high (mL/kg/min). Fitbit reports as a range (e.g. 39-43); when a single value is given, low and high are equal. Higher = better cardiorespiratory fitness.
List paired Fitbit devices with battery level and last sync time. Live-only (no caching) - reflects current device state. Useful for monitoring tracker health, knowing which device produced data, and spotting sync gaps. Returns one entry per paired device with id, type, device_version, battery (e.g. "High"), battery_level (0-100), last_sync_time, mac, and features list.
Get exercise log entries (individual tracked activities). Returns exercise sessions from the local cache by default. Use live=True to fetch from Fitbit API. Run fitbit_sync first to populate the cache. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. exercise_type: Filter by activity name (case-insensitive substring match), e.g. "cycling", "walk", "run". Default: all types. live: If true, fetch directly from Fitbit API instead of cache. Returns exercise entries with name, duration, calories, avg heart rate, distance, and source (auto-detect vs manual). Note: HR data from cycling may be unreliable (optical sensor vs handlebar grip).
Get daily food and water log summary. Returns calories consumed and water intake (in mL) per day. Only populated if the user logs food/water in the Fitbit app. Returns from cache by default, auto-syncing if stale. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. live: If true, fetch directly from Fitbit API. Uses one API call per day. Returns one entry per day with calories_in and water_ml. Days with no logging are omitted.
Get user-set activity goals for steps, distance, calories, etc. Live-only (no caching). Use to compare actuals (from fitbit_get_activity) against the targets the user set in the Fitbit app. Args: period: "daily" or "weekly". Default: "daily". Returns goals dict with keys like steps, distance, calories_out, active_minutes, active_zone_minutes, floors. Weekly omits some fields.
Get daily resting heart rate and heart rate zones. Returns resting HR and zone breakdown (Out of Range, Fat Burn, Cardio, Peak) from the local cache by default, auto-syncing if stale. Use live=True to bypass the cache entirely. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. live: If true, fetch directly from Fitbit API instead of cache. Returns one entry per day with resting_hr and zones array. Zone data: name, minutes, caloriesOut, max/min HR for each zone.
Get nightly HRV (heart rate variability) data. Returns data from the local cache by default. Use live=True to fetch from Fitbit API. Run fitbit_sync first to populate the cache. HRV data is sparse: only nights with on-wrist sleep tracking produce readings. Requires Fitbit Premium for access to this endpoint. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. live: If true, fetch directly from Fitbit API instead of cache. Returns one entry per night with daily_rmssd and deep_rmssd (ms). RMSSD = root mean square of successive RR interval differences. Higher values generally indicate better recovery and parasympathetic activity.
Get all-time activity totals and personal best records. Live-only (no caching). Returns lifetime totals (steps, distance, floors, calories, active score) and personal bests (best day for steps, distance, floors), each with the date the record was set. Useful for long-term context that the daily activity table can't easily answer (e.g. "what's my best step day ever?").
Get nightly sleep data (duration, stages, efficiency). Returns sleep data from the local cache by default. Use live=True to fetch from Fitbit API. Run fitbit_sync first to populate the cache. Sleep data is sparse: only nights with watch-tracked sleep are present. Travel, off-wrist nights, or manual logs may be missing. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. live: If true, fetch directly from Fitbit API instead of cache. Returns one entry per night with total_minutes, efficiency, start/end times, and stage breakdown (deep, light, REM, wake minutes).
Get nightly SpO2 (blood oxygen saturation) data. Returns data from the local cache by default. Use live=True to fetch from Fitbit API. Run fitbit_sync first to populate the cache. SpO2 data is sparse: only nights with on-wrist sleep tracking produce readings. Requires Fitbit Premium for access to this endpoint. Args: start_date: Start date as "YYYY-MM-DD", "YYYY-MM", or "30d". Default: last 30 days. end_date: End date as "YYYY-MM-DD". Default: today. live: If true, fetch directly from Fitbit API instead of cache. Returns one entry per night with avg, min, max SpO2 percentage. Normal range: 95-100%. Below 90% may indicate sleep apnea.
Sync health data from Fitbit API into local SQLite cache. Fetches activity, sleep, heart rate, weight, exercises, and other metrics for a date range. Respects API rate limits (150 requests/hour) with automatic backoff.
Analyze trends in cached health data (activity, sleep, heart rate, weight, etc.) aggregated by period (daily, weekly, monthly, quarterly).
No error recovery guidance. Code shows format_response() for missing data (e.g., 'No activity data found') but no actionable next steps. LLMs receive bare messages without retry hints or alternative tool suggestions.
Date format flexibility ('YYYY-MM-DD', 'YYYY-MM', '30d') documented in descriptions but not validated in code. Invalid formats may silently fail or produce unexpected results.
STDIO transport only. Server is not remotely accessible and cannot be used by hosted MCP clients. Limits deployment to local/containerized environments.