mi-health-mcp
by lyizhuo
README.md
# mi-health-mcp
Local-first Xiaomi health data hub for agents: **REST + MCP + scheduled sync**.
This is a clean rebuild of the ideas from the community `mi-fitness-mcp` projects. It is not
affiliated with Xiaomi. It reads **your own** health data from the Xiaomi cloud and stores it in a
local SQLite database for analysis by agents.
> Status: data plane + admin UI implemented. REST/MCP serve the same query layer; the React admin
> console covers login, overview, charts, keys, sync status and QR login.
## What it does
- Syncs Xiaomi Mi Fitness cloud data on a schedule (steps/HR/SpO2/stress every 30 minutes, sleep
every 2 hours, workouts/body every 12 hours by default).
- Stores data in SQLite with WAL and batched transactions.
- Serves the same query layer through:
- REST `/api/*`
- MCP Streamable HTTP `/mcp`
- Returns freshness metadata (`data_as_of`, `last_synced_at`, `stale`) with every response.
- Uses read-only agent API keys (optional `sync` scope); admin operations are separate.
## Architecture
```text
Internet
-> reverse proxy / TLS
-> 127.0.0.1:8330
FastAPI (REST / SPA / MCP)
worker (scheduler + backfill + sync)
SQLite WAL (/data)
```
The API and worker are separate processes in the same container. The API never performs a Xiaomi
sync, so a slow RC4/JSON/SQLite batch cannot block agent queries.
## Quick start
```bash
python -m venv .venv
. .venv/bin/activate
pip install -e '.[dev]'
# 1. Generate a master key for encrypted credentials
python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())'
export MI_HEALTH_MASTER_KEY='...'
# 2. Admin login + session secret (hash is Argon2id; prompt is interactive)
export MI_HEALTH_ADMIN_PASSWORD_HASH="$(mi-health admin hash-password)"
export MI_HEALTH_SESSION_SECRET="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
# 3. Store your Xiaomi userId/passToken, or use the admin UI QR login
mi-health set-credentials --user-id "<userId>" --pass-token "<passToken>" --region cn
# 4. Create a read-only agent key (shown once)
mi-health key create --label agent --scopes read
# 5. Run API and worker (separate processes)
mi-health serve-api --host 127.0.0.1 --port 8330
mi-health serve-worker
```
Open `http://127.0.0.1:8330/` for the admin console. It uses a session cookie, not an agent API key.
The bottom of the overview shows whether data is stale; use **同步** for an on-demand refresh and
**扫码登录** to authorize Xiaomi.
MCP client URL: `http://127.0.0.1:8330/mcp/` with `Authorization: Bearer mhk_...` (the mounted Streamable HTTP endpoint redirects `/mcp` to `/mcp/`).
Frontend development/build:
```bash
cd web
bun install
bun run typecheck
bun run build # -> web/dist
# run the API with the built UI
MI_HEALTH_WEB_DIR=web/dist mi-health serve-api --host 127.0.0.1 --port 8330
```
REST example:
```bash
curl 'http://127.0.0.1:8330/api/summary?start_date=2026-11-01&end_date=2026-11-03' \
-H 'Authorization: Bearer mhk_...'
```
## Docker
```bash
cp .env.example .env # set MI_HEALTH_MASTER_KEY and MI_HEALTH_ALLOWED_HOSTS
docker compose -f docker-compose.example.yml up -d --build
mi-health key create --label agent --scopes read # from inside the container or the CLI
```
The example binds `127.0.0.1:8330` on the host; expose it through a TLS reverse proxy and set
`MI_HEALTH_ALLOWED_HOSTS` to the public host, otherwise MCP's DNS-rebinding protection rejects the
Host header. Set `MI_HEALTH_HTTPS_ONLY=1` so the session cookie gets the Secure flag.
## Data notes
- **Sleep HRV is aggregate-only.** Xiaomi's `sleep` payload exposes `avg_hrv`, `min_hrv`,
`max_hrv`, `hrv_median`, `hrv_std`, quantiles, baseline min/max and an analysis timestamp; there
is no public time-series HRV endpoint in the old cloud API.
- The cloud is the source of truth. The local DB is a cache; the UI/API report both
`data_as_of` (cloud record time) and `last_synced_at` (local sync time).
- This project only reads your own data. It is not a Xiaomi-official product.
## Upstream references and credits
This project would not exist without the community's reverse-engineering work. It does not copy
their data or credentials; protocol behavior is reimplemented/adapted with attribution.
- [kubulashvili/mi-fitness-mcp](https://github.com/kubulashvili/mi-fitness-mcp) — original MCP
server and Xiaomi cloud adapter (MIT), which this project's protocol layer is adapted from.
- [HUAYUE1024/mi-fitness-mcp-cn](https://github.com/HUAYUE1024/mi-fitness-mcp-cn) —
China-region fork, QR login and data-field work (MIT).
- [kevinkwee/Mi-Fitness-Sync](https://github.com/kevinkwee/Mi-Fitness-Sync) — decompiled auth/FDS
notes and Python client (MIT).
- [Jenwein/mifit](https://github.com/Jenwein/mifit) — protocol/field notes and probes.
- [ilyasaftr/better-mi-fitness-sync](https://github.com/ilyasaftr/better-mi-fitness-sync) —
sleep HRV field semantics/units (Kotlin client).
- [AlexxIT/SmartScaleConnect](https://github.com/AlexxIT/SmartScaleConnect) —
Go Xiaomi signed-request reference.
- [motor-screwdriver/advx2026-project](https://github.com/motor-screwdriver/advx2026-project) —
Go MiFitness login/RC4/sleep client reference.
No Xiaomi code or assets are included. The protocol is unofficial and may break.
## Security
- Never commit `.env`, `MI_HEALTH_MASTER_KEY`, API keys, or `passToken`.
- `passToken` is encrypted at rest with a master key from the environment.
- API keys are stored as hashes and shown only once.
- Bind the app to `127.0.0.1` and expose it through a TLS reverse proxy.
- Read the [requirements](docs/REQUIREMENTS.md) for the agreed threat model.
## License
MIT. See [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues