Mi Fitness Data Bridge
A local, read-only-by-default bridge that syncs Mi Fitness (Xiaomi) health data into a local SQLite cache and exposes it through stdio MCP query tools and exports.
Sync from Xiaomi:
sync_datapulls selected datasets (daily activity, heart rate, body measurements, sleep, workouts, SpO₂, stress, abnormal heartbeat) into local SQLite, by date range, foreground or background (sync_id), withforce_full_syncto ignore watermarks.Check connectivity/account:
get_connection_statusverifies the configured account can reach Xiaomi (may authenticate/rotate local credentials);get_profilereturns minimal local metadata (masked account ID, timezone, devices).Monitor and control sync jobs:
get_sync_statusreads one job's state;query_sync_historylists retained MCP jobs (latest 500);cancel_syncstops a running/queued background sync.Inspect cache coverage:
get_data_coveragereports which date ranges and day counts already exist per dataset, before choosing query dates or syncing.Query daily activity:
query_daily_activityreturns per-day totals (steps, distance, kcal, floors, active minutes) with quality flags and pagination.Query metric trends:
query_metric_seriesbuilds dated/aggregated series for steps, distance, active kcal, or weight (day/week/month, sum/avg/min/max/latest).Query sleep:
query_sleepreturns sessions plus a main-sleep summary (scores/sources, naps optional, wake-date based).Query workouts:
query_workoutslists session summaries (filter by activity type, duration, distance);query_workout_seriesreturns a downsampled heart-rate curve with zones for one workout.Query body measurements:
query_body_measurementsreturns timestamped weight, BMI, body fat, muscle mass, and water percentage readings.Query vitals/events:
query_heart_rate,query_spo2,query_stress, andquery_abnormal_heart_beatreturn timestamped samples or flagged events.Pagination everywhere: record-list tools support
limit/offsetwithnext_offset.
All query_* tools are read-only local SQLite lookups with no cloud calls and no automatic sync; it is a data connector only, not a diagnostic, coaching, or hosted service.
Provides tools to sync, query, and export personal Mi Fitness (Xiaomi) health data, including daily activity, sleep, workouts, body measurements, heart rate, SpO2, stress, and abnormal heart beats, into a local SQLite database and via MCP tools.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Mi Fitness Data Bridge What was my average sleep duration over the last 7 days?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
English version: README.en.md
米桥(Mi Fitness Data Bridge)
Local-first data bridge that exports your own 小米运动健康 data to SQLite, JSON, CSV, Python, and MCP-compatible tools.
The 小米运动健康 App is happy to show you your steps, sleep, and heart rate — but never lets you take that data with you. This bridge puts your own data into a SQLite file on your own hard drive.
Trademark notice: 小米, 米家, and Mi Fitness are trademarks of 小米 Corporation. This project is an unofficial community project and is not affiliated with or endorsed by 小米.
The experimental cloud adapter may become unusable at any time because 小米 changes its private APIs. Use it only on accounts and data you are authorized to access.
Verified in practice
Recorded on 2026-07-20 on Windows (Python 3.14) from a commit on the main branch. All data are synthetic and involve no credentials or network access. (Test counts re-checked and updated on 2026-08-17.)
Test suite:
$ python -m pytest -q -p no:cacheprovider
........................................................................ [ 96%]
... [100%]
75 passed in 10.27sEnd-to-end synthetic demo (examples/synthetic_demo.py first populates the local SQLite cache with synthetic records, then runs the real JSON/CSV export pipeline):
$ python examples/synthetic_demo.py
Seeded synthetic database: C:\Users\<you>\AppData\Local\Temp\mi-fitness-demo-53el7cfh\mi_fitness.db
daily_activity: 2026-07-15 .. 2026-07-15 (1 day(s))
sleep: 2026-07-14 .. 2026-07-14 (1 day(s))
workouts: 2026-07-15 .. 2026-07-15 (1 day(s))
body_measurements: 2026-07-15 .. 2026-07-15 (1 day(s))
Export completed
mi_fitness.json
daily_activity.csv
sleep.csv
workouts.csv
body_measurements.csv
heart_rate.csv
spo2.csv
stress.csv
abnormal_heart_beat.csv
JSON envelope:
schema_version: 1.0
source: mi_fitness_data_bridge
records.daily_activity: 1 row(s)
records.sleep: 1 row(s)
records.workouts: 1 row(s)
records.body_measurements: 1 row(s)
Sample sleep row (synthetic):
start_at=2026-07-14T23:20:00 end_at=2026-07-15T07:05:00
duration_minutes=465 score=86
stages=[{"stage": "deep", "minutes": 82}, {"stage": "light", "minutes": 271}, {"stage": "rem", "minutes": 88}, {"stage": "awake", "minutes": 24}]Related MCP server: miband-mcp
Merged health-assistant project
The health-assistant project (a local-first personal health dashboard: Strava, sleep, body composition, diet analysis) has been merged into this repository, and its original repository has been archived. The absorbed assets live under the docs/health-assistant/ directory:
analytics.py— zero-dependency reference implementation of a training/recovery summary and recommendation engine (7-day training statistics, acute-to-chronic workload ratio, readiness checks, daily training recommendations).coaching_methodology.md— the interpretable cycling coaching, body composition, and sports nutrition methodology behind it.README.md— full migration notes, including the parts intentionally not ported (FastAPI dashboard, Strava OAuth/Webhook pipeline, meal photo analysis) and the reasons.
What this project does
Reads 小米运动健康 data through an experimental China-region cloud adapter.
Stores normalized records in a local SQLite database.
Exports portable JSON or CSV without credentials.
Exposes local MCP query tools for personal automation.
Provides a reusable connector implementation for downstream projects (e.g., a personal fat-loss advisor).
It deliberately does not provide medical advice, weight-loss guidance, hosted account access, or multi-user cloud services.
Why this bridge?
Before | After |
Your health history lives only in the 小米运动健康 App, and the only way to “export” it is taking screenshots. |
|
To answer “how did I sleep last month”, you have to scroll back day by day in the App. |
|
To let an AI assistant access your health data, you have to hand over your credentials to some hosted service. |
|
Supported datasets
Daily activity: steps, distance, active calories, and active minutes.
Sleep records and sleep stages.
Workout records.
Body measurements: weight and available body composition fields.
Heart-rate samples, including resting heart rate when available.
Blood oxygen (SpO2), stress, and abnormal heartbeat events (depending on account/device availability).
Actual availability varies by device, account region, firmware, and 小米 upstream services.
Installation
git clone https://github.com/shkyyy18/mi-bridge.git mi_fitness_data_bridge
cd mi_fitness_data_bridge
python -m venv .venvWindows PowerShell:
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"Windows Git Bash:
source .venv/Scripts/activate
pip install -e ".[dev]"macOS/Linux:
source .venv/bin/activate
pip install -e '.[dev]'Configuration
A more secure interactive configuration path avoids writing the passToken directly into your shell history:
mi-fitness-bridge setup
mi-fitness-bridge doctorWhen available, credentials are stored via the local keyring. Some fallback keyring implementations may not store secrets securely; please understand your OS's keyring behavior before using.
How to get user_id and passToken
This bridge uses 小米 account-level credentials (the same login state as the 米家 App). Use either of the following two methods:
Method 1: manual copy from the browser
Open account.xiaomi.com in your browser and sign in with your 小米 account (the same account as the 小米运动健康 App).
Open Developer Tools (F12) → Application → Cookies →
https://account.xiaomi.com.Copy the values of the
userIdandpassTokencookies and paste them whenmi-fitness-bridge setupprompts you.
Method 2: QR-code login tool
Sign in once by scanning a QR code with the open-source mijia-api:
pip install mijiaAPI
python -c "from mijiaAPI import mijiaAPI; mijiaAPI().login()" # 终端出二维码,用米家 App 扫码The login state is saved by default at ~/.config/mijia-api/auth.json (on Windows, %USERPROFILE%\.config\mijia-api\auth.json). The userId and passToken inside it can be used directly with this bridge — 小米 account-level credentials work across services, and the bridge uses them to obtain a 小米运动健康 (sid=miothealth) session. Note that auth.json stores credentials in plaintext: after entering the userId and passToken into this bridge (system keychain), it is recommended to delete that file.
Note:
The passToken expires; when
doctorreports authentication failure, simply re-fetch it using the steps above.For the browser method, sign in from your usual network environment; frequent or off-site operations may trigger 小米 account risk control (slider/SMS verification). If you hit risk control, switch to the QR-code method.
Cookie names and the login flow are based on actual testing in 2026-08; they may vary by account region, device, or risk-control policy. 小米 may also adjust its private APIs at any time (see the experimental notice at the top).
These two values are equivalent to your account login state. Do not leak them, and do not commit them to Git.
Sync
mi-fitness-bridge sync --start-date 2026-07-01 --end-date 2026-07-15Or sync only one dataset:
mi-fitness-bridge sync --type sleep --start-date 2026-07-01 --end-date 2026-07-15
mi-fitness-bridge sync --type body_measurements --start-date 2026-07-01 --end-date 2026-07-15The database defaults to the platform user data directory (determined by platformdirs). sync, export, serve, and doctor all support moving it with the --db flag or the MI_FITNESS_DB_PATH environment variable. Precedence: command line > environment variable > default location. Note that platformdirs does not respond to the LOCALAPPDATA environment variable on Windows; to customize the path, use one of the two methods above:
mi-fitness-bridge sync --db ./data/mi_fitness.db --start-date 2026-07-01 --end-date 2026-07-15
export MI_FITNESS_DB_PATH=./data/mi_fitness.dbKnown limitation: incremental sync without a date argument starts from the time of the last local record; upstream corrections or backfills of earlier history are not pulled automatically. If needed, explicitly re-run that interval with an earlier --start-date (idempotent overwrite; no duplicate records are produced).
Export
Generate a portable JSON file:
mi-fitness-bridge export --format json --output exports/mi_fitness.jsonGenerate one CSV file per dataset:
mi-fitness-bridge export --format csv --output exports/csvFilter by dataset and date:
mi-fitness-bridge export --format json --type sleep \
--start-date 2026-07-01 --end-date 2026-07-15 \
--output exports/sleep.jsonExport files never contain the saved 小米 passToken, but they do contain identifying columns such as plaintext user_id — export files are sensitive personal data, so store them carefully. Exported health records are ignored by Git by default.
See Export format for export format details (JSON envelope structure, CSV layout, closed-interval date filtering rules).
MCP service
The compatibility command remains available:
mi-fitness-bridge serve
# legacy alias
mi-fitness-mcp serveAvailable tools include connection status, sync, coverage, daily summary, body measurements, sleep, workouts, heart rate, blood oxygen (SpO2), and stress queries, as well as the agent-oriented workout_series workout time-series tool — it automatically downsamples according to the hard max_points cap (fixed time-bucket means, aggregated inside SQLite), and reports downsampled, source_points, returned_points, and method truthfully in the response, while also providing full-precision statistics (avg/min/max/percentiles) and time in heart-rate zones. List/summary tools such as query_workouts and get_daily_summary include data_quality (covered days, missing metrics, last sync time).
Client integration example (configuration JSON for MCP clients such as Claude Code / Codex):
{
"mcpServers": {
"mi-bridge": {
"command": "mi-fitness-bridge",
"args": ["serve"]
}
}
}Note: serve is a stdio service; it communicates with the client over standard input/output, not an HTTP service. Running it directly in a terminal will look like it is “stuck” — that is it waiting for MCP messages from the client, which is normal. For everyday use, let your MCP client start it with the configuration above.
Use as a Python dependency
The normalized adapter remains available under a compatible module name:
from mi_fitness_mcp.adapters.mi_fitness_cloud import MiFitnessCloudAdapterDownstream projects should install this package rather than vendor or copy the connector source code.
License
License history: versions released before 2026-08-03 were licensed under MIT (the MIT attribution of the upstream kubulashvili/mi-fitness-mcp and binglua/mi-fitness-mcp-cn is retained in the NOTICE section at the top of LICENSE); new code in the current version is AGPL-3.0-only. See LICENSE and THIRD_PARTY_NOTICES.md for details.
Privacy and security
Safeguard the passToken, local database, export files, and logs; do not leak them.
Export files do not contain the passToken, but they do contain identifying columns such as plaintext
user_id, and are equally sensitive personal data.Do not run this bridge as a public credential proxy.
Do not commit real health data or screenshots containing personal metrics.
Always use synthetic data in bug reports and documentation.
This software is only for personal data access and engineering research, not for diagnosis or treatment.
See SECURITY.md for responsible disclosure and THIRD_PARTY_NOTICES.md for provenance.
Development
pip install -e '.[dev]'
python -m pytest -q -p no:cacheprovider
python -m ruff check src testsRelease
See CHANGELOG.md for version history and docs/release-checklist.md for release and post-release checklist items.
Related projects
garmin-mcp — a local-first MCP service for Garmin data. It shares the
agent-safe-series/v1data contract with this project (time-series downsampling field semantics are byte-for-byte aligned), so the same AI agent can seamlessly consume data from both services.
Support this project
If this tool helped you, give me a star on GitHub.
Available Tools
17 toolscancel_syncAIdempotent
Cancel a queued/running background MCP sync by its exact sync_id. Returns the terminal job status after cancellation completes; already-finished jobs are returned unchanged. Stops future requests without deleting or rolling back records already committed to SQLite; counts may be incomplete. Unknown IDs or foreground jobs return status=error. No new cloud request. Use get_sync_status to inspect progress and sync_data with user consent to resume via a new job.
Inputs: sync_id (required).
get_connection_statusA
Check whether the configured Mi Fitness account can connect before requesting a sync. May contact Xiaomi, authenticate and rotate credentials in the local keyring; does not sync health records. Requires local interactive CLI setup, never credentials in tool arguments. Returns connected, mode, last_sync_at and available_data_types; configured responses also include connection_state, region, last_connection_error and sync_in_progress. While syncing, reports existing connection state instead of probing. For cached date coverage use get_data_coverage.
Inputs: no named parameters.
get_data_coverageARead-onlyIdempotent
Inspect which date ranges already exist in the local cache before choosing query dates or requesting sync_data. Returns data.coverage [{data_type, first_date, last_date, days_with_data}] for nonempty datasets; omitted/empty data_types means all datasets. Empty datasets are omitted, and first/last dates do not guarantee uninterrupted coverage between them. This does not test cloud connectivity or report a background job; use get_connection_status or get_sync_status respectively. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use sync_data to refresh with user consent.
Inputs: data_types.
get_profileARead-onlyIdempotent
Read minimal metadata for the already-connected local account, not a medical or demographic profile. No cloud request or cache write; returns JSON text with status, source and data.profile containing account_id_masked, configured timezone and devices (currently an empty placeholder). Never returns credentials or plaintext account IDs. Returns status=error if disconnected; get_connection_status can establish/check the connection first. Use query_daily_activity for activity totals.
Inputs: no named parameters.
get_sync_statusARead-onlyIdempotent
Read one MCP sync job by sync_id, including after a server restart. Returns sync_id, status, timestamps and available result counts. States are queued, running, ok, partial, error, cancelled or interrupted (previous process stopped). Read-only local lookup; no cloud request. History retains the latest 500 completed jobs per account; unknown/expired IDs return status=error. Use query_sync_history to discover IDs, cancel_sync to stop a live background job, or get_connection_status for cloud connectivity. Restarted lookups omit raw error text for privacy.
Inputs: sync_id (required).
query_abnormal_heart_beatARead-onlyIdempotent
Read device-reported abnormal-heartbeat events starting within an inclusive YYYY-MM-DD range. Returns data.events [{event_id, start_at, end_at, duration_seconds}] and data.count, earliest first. limit defaults to 5000; use offset for subsequent pages. Events are upstream flags, not a diagnosis; an empty list is not evidence of a healthy heart. Use query_heart_rate for ordinary bpm samples, not this event list. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: end_date (required), start_date (required), limit, offset.
query_body_measurementsARead-onlyIdempotent
Read timestamped body measurements over an inclusive YYYY-MM-DD range. Returns data.measurements and data.count in timestamp order; latest_only=true returns only the last matching record, not the latest value of each field. Omitted/empty metrics returns all available fields; otherwise timestamp plus selected fields, with absent optional measurements omitted. Units are kg for mass, percent for body fat/water, dimensionless for BMI. Use query_metric_series(metric=weight_kg) for a daily or aggregated weight trend. latest_only selects before pagination. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: end_date (required), start_date (required), limit, offset, +2 more.
query_daily_activityARead-onlyIdempotent
Choose this for a multi-column daily activity table, not a single-metric trend. Read daily activity totals: steps, distance_m, active_kcal, total_kcal, floors and active_minutes, plus data_quality. Supply date for one day or both start_date/end_date for an inclusive YYYY-MM-DD range; date takes precedence if both forms are given. Returns data.summaries and data.data_quality. Missing optional upstream metrics may appear as zero with quality warnings; do not treat them as confirmed measurements. For one metric across days/weeks/months use query_metric_series; sleep and workouts have separate tools. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: date, limit, offset, end_date, +1 more.
query_heart_rateARead-onlyIdempotent
Read timestamped heart-rate samples in bpm over an inclusive YYYY-MM-DD range, optionally filtering sample_type. Returns data.samples [{timestamp, bpm, sample_type}] and data.count, earliest first. limit defaults to 5000; use a smaller page/date window for large datasets. The cloud adapter normally stores resting/active/passive, so sample_type=workout may be empty; use query_workout_series with a workout_id to analyze all samples in that activity window. Not a diagnosis. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: end_date (required), start_date (required), limit, offset, +1 more.
query_metric_seriesARead-onlyIdempotent
Build a dated trend for steps (count), distance_m (meters), active_kcal (kcal), or weight_kg (kg) over an inclusive YYYY-MM-DD range. Returns data.metric and data.series [{date, value}], sorted ascending, without filling missing dates. Activity uses daily totals; weight uses the latest stored measurement per day. granularity=day returns these daily values; week groups from Monday, month from the first day. aggregation (default sum) applies only to week/month daily values; latest selects the last available day. Prefer avg or latest for weight. For raw body readings use query_body_measurements; heart-rate samples use query_heart_rate; one workout uses query_workout_series. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: metric (required), end_date (required), start_date (required), limit, +3 more.
query_sleepARead-onlyIdempotent
Read sleep sessions (start-date filtered) and a main-sleep summary (local wake-date filtered) over an inclusive YYYY-MM-DD range. Returns data.sessions, count, main_sessions, metrics and data_quality; main sleep is the longest valid non-nap per wake date. include_naps defaults true and affects the raw list only, not main-sleep selection. Times include start_at/end_at; durations are minutes; sleep_score/source can be null and missing scores are not zero. Expand dates around midnight if needed; raw counts can differ from wake-date summary counts. Use this instead of query_daily_activity for sleep. Pagination affects sessions/count only; main_sessions, metrics and quality still describe the full date range, so keep ranges narrow. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: end_date (required), start_date (required), limit, offset, +1 more.
query_spo2ARead-onlyIdempotent
Read stored blood oxygen saturation samples (spo2_pct, percent) over an inclusive YYYY-MM-DD range. Returns data.samples [{timestamp, spo2_pct}] and data.count, earliest first. limit defaults to 5000; use offset for subsequent pages. These are device measurements, not a diagnosis; missing records do not indicate normal oxygen levels. Use query_heart_rate for bpm rather than oxygen saturation. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: end_date (required), start_date (required), limit, offset.
query_stressARead-onlyIdempotent
Read device stress samples over an inclusive YYYY-MM-DD range, optionally filtered by level (low/medium/high). Returns data.samples [{timestamp, stress_score, level}] and data.count, earliest first. stress_score is the upstream device score, not a clinical assessment. limit defaults to 5000; use offset for subsequent pages. Use query_sleep for sleep quality rather than inferring it from stress. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: end_date (required), start_date (required), level, limit, +1 more.
query_sync_historyARead-onlyIdempotent
List this account's MCP sync jobs, newest first, from persistent local SQLite. Returns data.jobs and data.pagination with timestamps, statuses, available counts and safe error codes, never credentials, raw errors or health records. Includes foreground/background jobs started since this feature was installed, not CLI syncs; retains the latest 500 completed jobs plus active jobs. Read-only, no cloud calls. Use get_sync_status for one ID and cancel_sync for a live background job. Empty jobs means no retained history. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: limit, offset.
query_workoutsARead-onlyIdempotent
List recorded workouts starting within an inclusive YYYY-MM-DD range. Returns data.workouts, count and data_quality; rows include workout_id, activity_type, start_at/end_at, duration_minutes, distance_m, calories_kcal and available heart-rate/pace fields (missing fields may be null). activity_types matches case-insensitively; min_duration is minutes and min_distance_km is kilometers (unlike output distance_m). Filters combine with AND before pagination. Use a returned workout_id with query_workout_series for a heart-rate curve; this tool returns session summaries, not samples. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent. Returns data.pagination {limit, offset, has_more, next_offset}; next_offset is null at the end. Keep filters unchanged and avoid syncing between pages.
Inputs: end_date (required), start_date (required), limit, offset, +3 more.
query_workout_seriesARead-onlyIdempotent
Read an auto-downsampled heart-rate curve for one workout_id obtained from query_workouts (contract agent-safe-series/v1). Uses all cached heart-rate sample types inside the workout window. Returns data with numeric t offsets in seconds from start_time, bpm values, downsampled/source_points/returned_points/method and full-resolution summary statistics. resolution defaults to 60 seconds and increases to respect max_points (default 400, hard cap 500). Pass the same reference_max_hr in bpm for comparable time_in_zone across activities; otherwise each workout uses its own maximum, so zones are not comparable. Unknown workout IDs or unsupported metrics return status=error. For raw date-range samples use query_heart_rate. Read-only local SQLite query; no cloud request or automatic sync. Requires a configured local account/cache. Returns JSON text with status, source=cache, generated_at and data; empty lists mean no cached matches, not zero measurements. Use get_data_coverage to inspect availability or sync_data to refresh with user consent.
Inputs: workout_id (required), metric, max_points, resolution, +1 more.
sync_dataA
Download selected Mi Fitness datasets from Xiaomi into local SQLite; writes records and sync watermarks, may authenticate/rotate local credentials, and does not modify cloud health records. Requires local CLI setup and user authorization to access the account. Omitted data_types selects all adapter-supported types; an empty list is invalid. Dates are inclusive YYYY-MM-DD; start_date must not exceed end_date. Omitted end_date uses today; omitted start_date resumes the watermark or uses configured lookback (default 30 days). force_full_sync ignores the watermark, not the requested date range, and does not erase the database. Only one sync runs at a time. background=false waits for status ok/partial/error, sync_id, record counts and per-type results; background=true returns accepted plus sync_id to poll with get_sync_status. Partial results may already be stored; inspect results before retrying. Use cached query tools instead when no refresh is needed.
Inputs: end_date, background, data_types, start_date, +1 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 17 tools
Each tool has a clearly distinct purpose: query_* tools target specific health data types or aggregation levels, while sync lifecycle tools (connection, sync, status, cancel, history, coverage) are well separated. Descriptions explicitly cross-reference related tools to resolve potential overlaps (e.g., metric series vs daily activity vs raw body measurements).
All names use consistent snake_case with predictable verb prefixes: get_ for system/status reads, query_ for cached data reads, and sync/cancel for actions. Minor singular/plural variation (query_workouts vs query_workout_series) is semantically meaningful and not confusing.
17 tools is slightly above the typical 3–15 range but justified by the breadth of distinct health metrics and sync management operations. No tool appears redundant; each query tool maps to a unique data type or purpose.
The surface covers connection, sync lifecycle, cache coverage, profile, and queries for all major Mi Fitness data types (activity, body, heart rate, sleep, workouts, SpO2, stress, abnormal beats). Minor gaps like sleep stages or workout GPS details may exist, but agents can work around them.
Maintenance
Related MCP Connectors
Apple Health history for Claude, ChatGPT and any MCP client: sleep, HRV, workouts, daily metrics.
Hosted Apple Health MCP: workouts, sleep and HRV in ChatGPT, Claude, Gemini, Grok. Free, no export.
Apple Health training load, recovery, HRV and workout detail for Claude, ChatGPT and any MCP client.
Your Garmin, Oura, WHOOP, Hevy and 35 more fitness apps, queryable from your own AI.
Related MCP Servers
- AlicenseCqualityDmaintenanceEnables reading and syncing Xiaomi Mi Fitness health data (steps, heart rate, sleep, workouts) from the Chinese cloud region to a local SQLite database via MCP tools.1019MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI to query Xiaomi Mi Band health data (steps, sleep, heart rate) from Gadgetbridge SQLite exports via the MCP protocol, allowing natural language questions about daily activity.1-
- AlicenseNot gradedqualityBmaintenanceLets AI assistants read your own Mi Fitness (Xiaomi cloud) health data — steps, heart rate, sleep, SpO2, stress, weight and workouts — through local MCP tools with QR-code login. Runs locally over stdio, returns results as JSON, and withholds GPS tracks unless explicitly allowed.447 PyPI2MIT
- AlicenseCqualityBmaintenanceEnables AI clients to query and analyze your own Xiaomi/Mi Fitness health data — daily activity, minute-level heart rate, sleep stages, workouts, body composition, SpO₂, stress, and abnormal heart beat events — after syncing it from the Xiaomi cloud into a local SQLite database. Exposes 14 tools covering connection status, incremental sync control, and metric/date-range queries, with everything stored and served locally.14MIT