# partymola/fitbit-mcp [Health: Active]

**Category:** 🏃 Sports  
**Repository:** https://github.com/partymola/fitbit-mcp  
**GitHub Stars:** 2  
**npm Downloads (last month):** 64  
**Views:** 3  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/partymola-fitbit-mcp

## Description
MCP server for the Fitbit Web API. OAuth 2.0 PKCE, local SQLite cache with auto-sync, and trend analysis. Tools for heart rate, activity, exercises, sleep, weight, SpO2, and HRV.

## Tools
Capabilities this server exposes over MCP:

- **fitbit_sync** — Sync Fitbit health data to the local cache.

Fetches data from the Fitbit API and stores it in SQLite for fast
offline queries. Run this before using other fitbit_get_* tools.

Syncs incrementally: only fetches data newer than the most recent
entry in each table. First sync fetches the specified number of days.

Args:
    data_types: What to sync. Options: "all", "heart_rate", "activity",
        "exercises", "sleep", "weight", "spo2", "hrv", "azm",
        "breathing_rate", "skin_temperature", "core_temperature",
        "cardio_fitness", "food_log".
        Comma-separated for multiple, e.g. "sleep,hrv". Default: "all".
    days: Days of history for first sync (default: 30). Ignored
        on subsequent syncs (uses last synced date).
    since: Optional "YYYY-MM-DD" backfill date. When set, fetches from this
        date regardless of what is already cached - use to pull history
        older than the current cache. Overrides incremental resume and days.
    until: Optional "YYYY-MM-DD" inclusive end date; requires since.
        Together they re-fetch and upsert exactly the since..until window -
        use to repair a gap in the middle of the cache without re-pulling
        everything from the gap to today.

Returns summary of records synced per data type.
Not for querying data - use fitbit_get_heart_rate, fitbit_get_activity,
fitbit_get_sleep, etc. instead.

- **fitbit_get_activity** — 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).

- **fitbit_trends** — Analyse trends in cached Fitbit data.

Computes averages and totals over time from the local cache,
auto-syncing if stale.

Args:
    data_type: What to analyse. Options: "heart_rate", "activity",
        "exercises", "sleep", "weight", "spo2", "hrv", "azm",
        "breathing_rate", "skin_temperature", "core_temperature",
        "cardio_fitness", "food_log". Default: "activity".
    period: Aggregation period. Options: "weekly", "monthly",
        "quarterly". Default: "monthly".
    start_date: Start date as "YYYY-MM-DD" or "365d". Default: last 12 months.
    end_date: End date as "YYYY-MM-DD". Default: today.
    compare: Compare two periods. Format: "last_30d vs previous_30d",
        "2026-03 vs 2026-02", "2026-Q1 vs 2025-Q4".
        When set, period/start_date/end_date are ignored.

Returns aggregated averages per period. For activity: steps, distance,
active minutes. For exercises: sessions, duration, calories.
For sleep: duration, efficiency, stage breakdown.
For heart_rate: resting HR min/avg/max. For weight: weight, fat%, BMI.
For spo2: avg/min/max oxygen saturation. For hrv: daily and deep RMSSD.
Not for raw data - use fitbit_get_* tools instead.

- **fitbit_get_azm** — 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.

- **fitbit_get_breathing_rate** — 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.

- **fitbit_get_cardio_fitness** — 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.

- **fitbit_get_devices** — 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.

- **fitbit_get_exercises** — 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).

- **fitbit_get_food_log** — 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.

- **fitbit_get_heart_rate** — 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.

- **fitbit_get_hrv** — 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.

- **fitbit_get_lifetime_stats** — 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?").

- **fitbit_get_goals** — 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.

- **fitbit_get_sleep** — 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).

- **fitbit_get_spo2** — 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.

- **fitbit_get_skin_temperature** — Get nightly skin temperature variation (degrees Celsius from personal baseline).

This is the device-derived RELATIVE deviation recorded during sleep, NOT an
absolute body temperature - for fever / body-temperature readings use
fitbit_get_core_temperature instead. Fitbit needs ~3 nights to establish a
baseline before values appear. Useful as an illness/cycle/recovery signal.

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 nightly_relative (degrees C, can be negative)
and log_type (e.g. "dermal").

- **fitbit_get_core_temperature** — Get manually-logged core (body) temperature readings (degrees Celsius).

These are absolute body temperatures the user enters by hand - e.g. a
forehead/thermometer reading saved to Fitbit - and are the right source for
fever / body-temperature questions. They are NOT the device-derived nightly
skin-temperature variation from fitbit_get_skin_temperature. A single day can
hold several readings (each timestamped), useful for tracking a fever over time.

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 logged reading with datetime (YYYY-MM-DDThh:mm:ss)
and temp_celsius.

- **fitbit_get_weight** — Get weight log entries (weight, BMI, body fat percentage).

Returns data from the local cache by default. Use live=True to fetch
from Fitbit API. Run fitbit_sync first to populate the cache.

Weight data is sparse: only days with weigh-in entries are present.

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 weigh-in with weight_kg, bmi, fat_pct.


## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `uvx` (confidence: high):

```json
"mcpServers": {
  "fitbit-mcp": {
    "command": "uvx",
    "args": ["fitbit-mcp"]
  }
}
```

## Documentation

## What partymola/fitbit-mcp MCP server does

The partymola/fitbit-mcp MCP server connects an MCP client to the Fitbit Web API and presents Fitbit health records as agent-callable tools. It covers daily activity, heart rate and zones, exercise sessions, sleep, weight, SpO2, HRV, Active Zone Minutes, breathing rate, skin-temperature variation, manually logged core temperature, cardio fitness, food and water logs, paired devices, activity goals, and lifetime statistics.

Most historical measurements can be synchronized into a local SQLite cache. Query tools then read from that cache by default, while a `live` option bypasses cached data and requests the Fitbit API directly. Trend analysis aggregates cached records weekly, monthly, or quarterly and can compare two periods.

The project is retired. Fitbit has stopped accepting new app registrations, and its Web API is scheduled to shut down on September 30, 2026. Existing installations may continue working until that date, but a new setup cannot be completed without an already registered personal Fitbit app.

## How it works

Authentication uses OAuth 2.0 with PKCE, so the setup uses a Fitbit client ID rather than a client secret. Running the authentication command opens a browser, completes Fitbit authorization, and stores tokens locally. Access tokens last eight hours and refresh automatically; refresh tokens expire after 90 days of inactivity.

`fitbit_sync` performs the initial download and subsequent incremental updates. The first sync can cover a selected number of days, while later syncs resume from the newest cached record for each data type. A `since` date supports older backfills, and `since` combined with `until` can refresh a specific date window. Query tools can automatically sync when needed, or callers can run an explicit sync first.

Live requests are useful for current device state and uncached data, but some endpoints make one API request per day. The documented Fitbit rate limit is 150 requests per hour, so large live date ranges should be avoided.

## Setup and configuration

The partymola/fitbit-mcp MCP server requires Python 3.13 or newer and a registered personal Fitbit developer app. The app must use `http://localhost:8080` as its redirect URL. The client ID is needed for PKCE; the setup does not require the client secret.

Install the package with `pip install fitbit-mcp` or run it without installation using `uvx fitbit-mcp`. Run `fitbit-mcp auth` to authorize Fitbit, then start the stdio server with `fitbit-mcp`. Tokens are saved under `~/.config/fitbit-mcp/fitbit_tokens.json` with restrictive file permissions. The command-line interface also provides `doctor`, `sync`, and JSON `import` commands.

A first sync is optional because query tools can populate the cache automatically. Use an explicit sync when you need more than the default initial history or want to select particular data types.

## Tools and capabilities

Available capabilities include:

- Synchronize selected Fitbit data types into SQLite with incremental updates and date-range backfills.
- Query activity, exercise, sleep, weight, heart rate, HRV, SpO2, AZM, breathing rate, temperature, cardio fitness, and food-log records.
- Analyze cached metrics with period averages, totals, and comparisons.
- Inspect paired devices, battery information, and last sync times through a live-only tool.
- Retrieve live-only activity goals, lifetime totals, and personal-best records.
- Filter exercise results by a case-insensitive activity-name substring.

Sleep, HRV, SpO2, and other device-derived records can be sparse because they depend on tracking coverage. HRV and SpO2 endpoints require Fitbit Premium access. Food and water results only contain days logged in the Fitbit app.

## Limitations and notes

This package cannot be newly configured from scratch after Fitbit stopped accepting app registrations. Its usefulness therefore depends on an existing registered personal app and continued Fitbit API availability. The API shutdown date is September 30, 2026.

The local database is specific to this project. The project documentation recommends copying `fitbit.db` before shutdown if retained Fitbit-only fields are needed. The suggested replacement, `google-health-mcp`, reads history from Google rather than importing this cache, and some fields do not have equivalent coverage there. This server is also not a medical diagnostic system: Fitbit measurements such as SpO2, breathing rate, temperature variation, and recovery metrics should be interpreted as recorded device or user-entered data.

_Full upstream README: https://allmcps.com/mcp/partymola-fitbit-mcp/readme_

