mifit について
mifitは、Xiaomiクラウドから自分のMi Fitnessデータを取得するPythonライブラリ、コマンドラインツール、MCPサーバーです。構造化された健康・運動記録を扱い、MCPサーバーではGPSトラックをデフォルトで無効にしています。
主な機能
- 01歩数、睡眠、心拍データの取得
- 02運動記録と日別健康サマリーの取得
- 03期間を指定したJSONエクスポート
- 04未解釈のサービスデータの取得
- 05QRコードによるログイン
活用シーン
- 01アシスタントに最近の睡眠を要約させる
- 02歩数や心拍数の傾向を確認する
- 03指定期間の運動記録をエクスポートする
- 04その他のフィットネスデータ項目を調べる
MCP 対応
ローカルMCPサーバーは、Mi Fitnessの記録の読み取りと、QRコードログインの開始・状態確認を行うツールを提供します。運動のGPSトラックは`--allow-gps`で明示的に有効化した場合のみ返されます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
16掲載時のツール一覧 · 2 週間前に更新
このツールにパラメーターはありません。
詳細
mifit
Xiaomi のクラウドから、ご自身の Mi Fitness(小米运动健康)データを読み取ります。AI アシスタント向けの、小さな Python ライブラリ、コマンドラインツール、MCP サーバーです。
Mi Fitness アプリは歩数、心拍数、睡眠などのデータを Xiaomi のクラウドに同期しますが、Xiaomi は個人向けの公開 API を提供していません。mifit は QR コードでご自身のアカウントにサインインし、同期されたデータを読み取って、JSON または Python オブジェクトとして返すため、そのデータを利用して開発できます。
非公式です。 Xiaomi との提携、承認、サポートはありません。 免責事項をご覧ください。
現在読み取れるデータ
| ドメイン | 取得できるデータ | records の型 | アプリとの照合 |
|---|---|---|---|
steps | 1 日ごとの歩数と距離 | StepRecord | はい |
heart_rate | 心拍数の生データ | HeartRatePoint | はい |
heart_rate_daily | 1 日ごとの心拍数:平均、最大、最小、安静時 | HeartRateDailySummary | はい |
consumption | 1 日ごとのカロリー:安静時、アクティブ、摂取、合計 | ConsumptionRecord | はい |
sleep | 1 日ごとの睡眠:合計、睡眠ステージの時間、ステージのタイムライン付きセッション | SleepRecord → SleepSession → SleepStage | はい。睡眠スコアは照合できず、raw のみに含まれます |
workouts | ワークアウトごとの記録:開始と終了、スポーツ、時間、距離、アクティブおよび合計カロリー、平均および最大心拍数、歩数 | Workout | はい |
workout_detail | ワークアウトごとの詳細(屋外のランニングとサイクリング):1 秒ごとのサンプル(心拍数、累積距離と歩数、ケイデンス、ペースまたは速度)および GPS トラック | WorkoutDetail → WorkoutSample / TrackPoint | はい(屋外ランニング 1 回、サイクリング 1 回)。高度は raw のみに含まれます。ランニングの高度はアプリの表示と数メートルずれていました |
spo2_daily | 1 日ごとの血中酸素飽和度(SpO2):平均、最大、最小 | Spo2DailySummary | はい |
spo2 | SpO2 の生データ | Spo2Point | はい |
stress_daily | 1 日ごとのストレスレベル:平均、最高、最低、および各ストレス帯(リラックス、軽度、中程度、重度)の時間 | StressDailySummary | はい |
activity_daily | アプリの活力指標ページと同様の 1 日ごとの活動データ:活動回数(活动次数)、活動時間(活动时长)、アクティブカロリー(卡路里) | ActivityDailySummary | はい |
weight | 体重の記録:時刻、体重、BMI(体組成は raw のみに含まれます) | WeightRecord | はい。体組成は照合できず、raw のみに含まれます |
profile(専用コマンド:mifit profile) | 身長、体重、1 日の歩数、カロリー、活動時間の目標 | UserProfile | はい |
raw(CLI:mifit raw、Python:client.raw、raw_window、daily_report) | フィットネスデータまたは日次レポートの任意のキーの行を、サービスから送信されたまま取得 | なし:解釈されていないサービスの行 | 該当なし:解釈されません |
「アプリとの照合」とは、実際のアカウント 1 件(中国リージョン、UTC+8)で、Mi Fitness アプリに表示される値と比較したことを意味します。今後、対応範囲を広げる予定です。それまでは、mifit raw(Python では raw_window と daily_report)を使うと、フィットネスデータまたは(--daily を指定した場合は)日次レポートのエンドポイントにあるその他の任意のキーの行を、解釈せずに取得できます。
各バージョンの変更点(破壊的変更を含む)については、CHANGELOG.mdをご覧ください。
インストール
Python 3.12 以降が必要です。必要な場合は uv がインストールします。
uv tool install mifit # recommended: its own environment, `mifit` on your PATH
pipx install mifit # the same, with pipx
pip install mifit # into the current environment, to use it as a library
アップグレード:uv tool upgrade mifit(または pipx upgrade mifit、pip install -U mifit)。
ログイン
mifit login
ターミナルに QR コードが表示され、その下にログイン URL が表示されます。スマートフォンの Xiaomi / Mi Fitness アプリでスキャンするか、URL を開いてサインインを承認してください。パスワードが mifit を経由することはありません。
セッションは ~/.mifit/session.json に保存されます(Windows では %USERPROFILE%\.mifit\session.json)。このセッションにより、Mi Fitness アカウントの健康データへのアクセスが許可されます(読み取り専用ではありません)。また、アカウントの passToken も保持されます。mifit はこれを使って、セッションの有効期限が切れたときに更新します。passToken はアカウント単位のもので、あらゆる Xiaomi サービスのトークンを取得できます。そのため、このファイルは Mi Fitness の健康データだけでなく、Xiaomi アカウント全体へのアクセスを許可し、セッショントークン自体の有効期限が切れた後も長く利用できます。パスワードと同様に扱い、共有したりコミットしたりしないでください。Linux と macOS ではファイルを読み取れるのは本人だけです。Windows ではユーザープロファイルのアクセス許可に従います。
Xiaomi から追加のセキュリティ確認を求められた場合は、mifit login に URL が表示されます。URL を開いて確認した後、もう一度 mifit login を実行してください。
AI アシスタントでの使用(MCP)
mifit mcp は、Model Context Protocol サーバーです。Claude Desktop、Claude Code、Cursor、VS Code などの AI アシスタントで起動すると、質問したとき(「先週はよく眠れましたか?」など)に、コンピューター上の Mi Fitness データを読み取ります。
コンピューターの外部に送信されるデータ。 アシスタントが呼び出すツールの結果は、会話のほかの内容と同様に、アシスタントのモデルプロバイダーに送信されます。ログイン情報はこのコンピューターの ~/.mifit に保存されます。サーバーは stdin/stdout でローカル実行され、ネットワークポートを開かず、結果に認証情報を含めることもありません。読み取るのは健康データのみです(ログインツールは新しいセッションを ~/.mifit に保存します)。GPS トラックはデフォルトで無効です。サーバーがワークアウトのルートを提供するのは、--allow-gps を付けて起動した場合(Claude Desktop 拡張機能では Allow GPS tracks スイッチがオンの場合)かつ、アシスタントがそれを要求した場合のみです。ルートからは自宅を含む居場所がわかります。
一度だけログインします。ターミナルで次のコマンドを実行します。
uvx mifit login
(または、uv tool install mifit の後に mifit login を実行します)。ターミナルがない場合は、アシスタントにログインを依頼できます。アシスタントは login_start を呼び出し、Xiaomi または Mi Fitness アプリでスキャンする QR コードを返します。
アシスタントにサーバーを追加します。 uv に含まれる uvx は、必要に応じて mifit をダウンロードして実行します。
claude mcp add --scope user mifit -- uvx mifit mcp
// Claude Desktop: %APPDATA%\Claude\claude_desktop_config.json
// (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json)
{"mcpServers": {"mifit": {"command": "uvx", "args": ["mifit", "mcp"]}}}
// Cursor: ~/.cursor/mcp.json
{"mcpServers": {"mifit": {"type": "stdio", "command": "uvx", "args": ["mifit", "mcp"]}}}
// VS Code: .vscode/mcp.json
{"servers": {"mifit": {"command": "uvx", "args": ["mifit", "mcp"]}}}
uv tool install mifit の後は、コマンドを mifit にして、引数として mcp を指定することもできます。GPS トラックを許可するには、mcp の後に --allow-gps を追加します(["mifit", "mcp", "--allow-gps"])。
公式の MCP Registry にも、io.github.Jenwein/mifit として掲載されています。これは、レジストリからサーバーをインストールするクライアント向けです。
Claude Desktop ならワンクリックで導入できます。 最新リリースから mifit-<version>.mcpb をダウンロードして開くか、Claude Desktop の Settings → Extensions からインストールします。Claude Desktop(Windows、macOS)で拡張機能のインストールを促すメッセージが表示されます。設定にある Allow GPS tracks スイッチは、デフォルトでオフです。この拡張機能は同梱されている mifit リリースを実行します。更新するには、新しいリリースの .mcpb をインストールしてください。拡張機能と上記の JSON 設定は、どちらか一方だけを使用してください。
ツール。 各ツールはデータを一種類ずつ読み取ります。日付は現地の暦日に基づきます。
| ツール | 読み取るデータ | 1 回の呼び出しあたり |
|---|---|---|
get_status | 今日の日付、タイムゾーン、ログイン状態、GPS 設定(クラウドからの情報はありません) | — |
get_steps | 1 日あたりの歩数と距離 | 92 日分 |
get_calories | 1 日あたりのカロリー:安静時、活動時、摂取量、合計 | 31 日分 |
get_activity | 1 日あたりの活動回数、時間、カロリー | 92 日分 |
get_heart_rate_daily | 1 日あたりの心拍数:平均、最大、最小、安静時 | 92 日分 |
get_sleep | セッションを含む 1 日あたりの睡眠データ。要求に応じてステージのタイムラインも取得 | 92 日分(ステージ情報付きは 7 日分) |
get_spo2_daily | 1 日あたりの血中酸素濃度 | 92 日分 |
get_stress_daily | 1 日あたりのストレスレベルと、各ストレス帯における時間 | 92 日分 |
get_weight | 体重測定値 | 92 日分 |
get_workouts | ワークアウト | 92 日分 |
get_heart_rate | 心拍数のサンプル。500 件を超える場合はバケット単位 | 7 日分 |
get_spo2 | 血中酸素濃度の測定値。500 件を超える場合はバケット単位 | 7 日分 |
get_workout_detail | 1 件のワークアウトの 1 秒ごとのサンプル(屋外でのランニングとサイクリング)。--allow-gps を付けた場合は GPS トラックも取得します(拡張機能では Allow GPS tracks がオンの場合) | 1 件のワークアウト、最大 500 行 |
get_profile | 身長、体重、1 日の目標 | — |
login_start | QR コードによるログイン(コードを返します) | — |
login_status | ログイン状態 | — |
結果には Python API の records が含まれます。Unix 秒ではなく、現地時刻(2026-10-07T23:12:00+08:00)が使われ、raw は含まれません。密度の高いデータは最大 500 行に削減され、その方法は注記に記載されます。結果は 5 分間保持されるため、再度要求しても新たなリクエストは送信されません。
自分の言葉で質問してください。アシスタントが適切なツールを選択します。たとえば、「今月、安静時心拍数は上がりましたか?」と聞いてみてください。
エクスポート
mifit export <domain> --from YYYY-MM-DD --to YYYY-MM-DD [--json PATH] [--full] [--no-track] [--chunk day|week|month] [--long] [--resume]
<domain>:activity_daily、consumption、heart_rate、heart_rate_daily、sleep、spo2、spo2_daily、steps、stress_daily、weight、workouts、またはworkout_detail(屋外ランニングやライドの秒単位のサンプルと GPS トラック)。--from/--to:開始日と終了日。ローカルの暦日として両端の日を含みます。--json PATH:標準出力ではなく、ファイルに書き込みます。--full:heart_rate専用です。1つの時間枠をクエリする代わりに、履歴を遡ってページごとに読み込みます(既知の制限を参照)。 これは1回の読み込みです。--fromは無視されるため、期間の長さにかかわらず--longは不要です。また、--chunk、--long、--resumeと併用できません。--no-track:workout_detail専用です。GPS ファイルをスキップするため、トラックはリクエストも書き込みもされません。--chunk day|week|month:1チャンクより長い期間のチャンクサイズ(1日、7日、または31日)です。デフォルトはドメインによって異なります。--long:92日を超える期間を許可します。--resume:PATH.partialから中断したエクスポートを再開します(--jsonが必要です)。
mifit export sleep --from 2026-10-01 --to 2026-10-07 --json sleep.json
出力は3つのリストを含む1つの JSON オブジェクトです。
{ "records": [], "raw": [], "notes": [] }
長期間のエクスポート
1つのチャンク(生の心拍数、SpO2、workout detail は7日、それ以外は31日。いずれも --from から数えます)より長い期間は、チャンクごとに1回ずつリクエストを行って読み込み、標準エラー出力に進行状況を表示します。これより短い期間は、これまでどおり1回で読み込みます。チャンクは同じ形式の1つの出力に統合されます。複数のチャンクがある場合、各ノートは元のチャンクを示す情報で始まります。92日を超える期間には --long が必要です。リクエストが多く、完了まで何分もかかる場合があります。例外は heart_rate --full です。これは --from を無視し、チャンク分割せずに1回で読み込むため、--long は不要です。
mifit export heart_rate --from 2026-01-01 --to 2026-06-30 --long --json heart_rate.json
--json PATH を指定すると、進行状況は PATH.partial に保存されます。このファイルにはエクスポートしたデータとエクスポート時の引数(ドメイン、日付、チャンクサイズ)が含まれ、認証情報は含まれません。出力ファイルと同様に取り扱ってください。エクスポートが停止した場合(ネットワークエラー、セッションの期限切れ、Ctrl+C など)、完了したチャンクはこのファイルに残ります。同じコマンドに --resume を付けて再実行すると、不足しているチャンクだけが読み込まれます。出力は中断せずに実行した場合と同じになり、書き込み後に部分ファイルは削除されます。標準出力へのエクスポートも同じようにチャンク分割されますが、再開はできません。
チャンクが失敗するとエクスポートは停止し、自動的に再試行されることはありません。1つのチャンクが繰り返し失敗する場合は、その前後の期間を別々にエクスポートして、そのチャンクをスキップできます。
任意のキー:mifit raw
mifit raw <key> --from YYYY-MM-DD --to YYYY-MM-DD [--daily [--tag TAG]] [--json PATH] [--long]
フィットネスデータまたは(--daily を指定した場合は)日次レポートのエンドポイントにある任意のキーを、サービスから返されたとおりに読み込みます。mifit にそのキーのドメインがあるかどうかは問いません(heart_rate にはドメインがあります)。
{records: [], raw, notes}を書き込みます。rawにはサービスの行が格納され、それぞれのフィールドと、JSON 文字列からデコードされたvalueが含まれます。recordsは常に空です。- raw キーの場合、サービスには1日早くリクエストし、指定期間内の行を保持するため、期間の開始時刻のデータも完全に取得できます。
--dailyを指定すると、キーの日次レポートを読み込みます。データのあるローカル日ごとに1行が返されます。--tag TAGを指定すると、別の集計タグを選択できます(デフォルトはdaily_report)。- 1回の読み込みでページ処理されます。92日を超える期間には
--longが必要で、--resumeは使用できません。 - 現時点で判明しているキーは、notes/domain-catalog.md に記載されています。
mifit raw stress --from 2026-10-01 --to 2026-10-07 --json stress.json
Python API
from mifit import MiFit
client = MiFit() # uses the session saved by `mifit login`
steps = client.steps("2026-10-01", "2026-10-07")
for day in steps.records:
print(day.date, day.steps, day.distance_m)
sleep = client.sleep("2026-10-01", "2026-10-07")
energy = client.consumption("2026-10-01", "2026-10-07")
heart = client.heart_rate("2026-10-07", "2026-10-07") # one time window
heart_full = client.heart_rate("2026-10-07", "2026-10-07", full=True)
detail = client.workout_detail("2026-10-12", "2026-10-12") # samples and GPS track
no_gps = client.workout_detail("2026-10-12", "2026-10-12", track=False)
rows = client.raw("sleep", "2026-10-07", "2026-10-07") # any fitness-data key, as served
window = client.raw_window("stress", "2026-10-07", "2026-10-07") # a complete window
daily = client.daily_report("valid_stand", "2026-10-01", "2026-10-07") # daily rows
raw_window(key, ...) は raw を拡張したもので、1 日早く問い合わせ、ウィンドウ内の行を保持し、value をデコードします。daily_report(key, ...) は、そのキーの日次行を返します。データがあるローカル日ごとに 1 行ずつ返し、tag= を使って daily_report 以外のタグを選択できます。どちらも records=[] と、raw 内の行を返します。
存在するキーと検証済みの内容については、notes/domain-catalog.md を参照してください。
workout_detail は、records にワークアウトごとの WorkoutDetail を 1 件返します。各 WorkoutDetail には、workout の概要(workouts の Workout)、samples(WorkoutSample。記録された秒ごとに 1 件)、および track(TrackPoint)が含まれます。track=False を指定すると、GPS ファイルを取得しません。
日付には、ローカルの暦日を表す "YYYY-MM-DD" 形式の文字列(開始日と終了日を含む)、または Unix 秒の整数を指定します。各ドメインメソッドは、records、raw、notes を含む結果を返します。raw(key, ...) は、フィットネスデータエンドポイント(data/get_fitness_data_by_time)の任意のキーについて、サービスから受け取ったままの行を返します。日次レポートは対象外です(ウィンドウ全体を取得するには raw_window を参照してください)。mifit 固有のエラーは mifit.MiFitError を継承します。AuthError は使用可能なセッションがない場合、または HTTP 401 の場合に発生します。そのサブクラスである RenewalError は、自動更新で解決できなかった HTTP 401 で発生します。その場合は再度ログインしてください。ApiError は、サービスがリクエストを拒否した場合、または読み取れない内容を送信した場合に発生します。NotificationRequiredError は、Xiaomi がセキュリティ確認を求めた際に、ログイン処理から発生します。ネットワーク障害は requests の例外として発生し、不正な日付引数は ValueError または TypeError を発生させます。
長期間のデータを取得する場合、read_chunks は 1 回に 1 チャンクずつ読み込みます(CLI のチャンクサイズを使用します。size="day"、"week"、"month" で上書きできます)。merge_chunks は各部分を結合します。日付には "YYYY-MM-DD" 形式の文字列のみを指定できます。
from mifit.chunks import merge_chunks
parts = []
for chunk, part in client.read_chunks("heart_rate", "2026-01-01", "2026-06-30"):
print(chunk.label, len(part.records)) # each chunk is read when the loop asks for it
parts.append((chunk, part))
heart = merge_chunks(parts) # its records are those of one read of the whole range
read_chunks(..., skip=labels) は、再開時に、すでにラベルがあるチャンクを読み飛ばします。options= は、各チャンクの呼び出しにキーワード引数を渡します。たとえば、workout_detail に {"track": False} を指定できます。options={"full": True} は ValueError を発生させます。全件読み込みでは各チャンクの終了位置からさかのぼってページングするため、どのチャンクでも同じサンプルを再び読み込んでしまうからです。代わりに heart_rate(..., full=True) を 1 回呼び出してください。このライブラリに 92 日の上限はありませんが、長期間の取得には多数のリクエストが必要です。必要なデータだけをリクエストしてください。
HTTP 401 でリクエストが拒否されると、クライアントは passToken を使ってセッションを 1 回更新し、リクエストを再送信します。mifit login で保存したセッションを使うクライアントの場合、更新後のセッションは ~/.mifit に保存されます。明示的なセッション(MiFit(session))はメモリ内で更新されます。更新後のセッションを保持するには、client.session を読み取ってください。MiFit(auto_renew=False) を指定すると更新は無効になり、401 が発生した時点で AuthError がそのまま発生します。
MiFit(http=...) を指定すると、HTTP クライアントを注入し、クライアントをオフライン状態に保てます。更新が有効な場合、更新処理もそのクライアントを使うため、get は通常の params=、headers=、timeout= に加えて、cookies= と allow_redirects= のキーワードも受け付ける必要があります(requests.Session は対応しています)。クライアントを注入しない場合、更新には独自の新しい requests.Session が使われます。
2 つのレイヤー:raw と records
rawは、サービスがデコードしたペイロードです(各行の内側のvalue、または消費データの場合はレスポンスのresultオブジェクトです。workout_detailの場合は、各ワークアウトのデコード済みサマリーと、保存された値としてのファイルです)。Xiaomi 独自のフィールド名が使われています。サービスが送信したすべての行を完全にダンプしたものではありません。汎用読み取りは例外です。raw_window、daily_report、mifit rawでは、rawに対象期間についてサービスが送信した各行全体が格納され、外側のフィールドも含めてvalueがデコードされます。recordsは、中立的な名前(asleep_min、avg_hr_bpmなど)を使った型付きデータクラスです。フィールドの意味は、このレイヤーに入る前に、アプリの表示またはアプリ独自のコードから判断しています。REM ステージだけは例外で、著者のデバイスでは REM が報告されないため、アプリ独自のコードだけに基づいています。睡眠スコアはこのレイヤーには含まれません。アプリには評価のみが表示され、数値を確認できなかったためです。rawにはsleep_scoreとして含まれています。サービスが報告していない値は、作られた0ではなくNoneになります。notesは、スキップされた行や不完全な可能性があるデータなど、該当する結果に関する注意事項です。
既知の制限事項
- クラウドのみで、クラウドの同期には遅れがあります。 mifit は、アプリから Xiaomi クラウドに同期されたデータを読み取ります。クラウド同期がオフになっているか、まだ実行されていない場合、データが欠落したり、反映が遅れたりします。最新日のデータは不完全なことがあります。
- カロリーリングはアプリが合成したものです。 アプリはクラウド上のアクティビティとスマートフォン側のアクティビティを組み合わせるため、最新日の
consumptionはリングの値より低くなることがあります。stepsのstep_caloriesは、歩数レポートの歩行による消費カロリーであり、リングの値ではありません。 - SDK によって生データのウィンドウが補正されます。 サービスは、生データウィンドウの先頭にあるサンプル(最初のバケット)を除外します。確認したすべての高密度な生データキーがこの仕様になっています。対象は
heart_rate、spo2、stress、caloriesです(notes/08、notes/11、notes/domain-catalog.md)。heart_rate、spo2、weightの読み取り、raw_window、mifit rawは、開始日より1日分前の日付を指定してサービスに問い合わせ、要求されたウィンドウのデータのみを保持します。raw(key, ...)は、どのキーでもこの補正を行わず、サービスからの応答をそのまま返します。完全なウィンドウを取得するにはraw_windowを使用してください。--full(full=True、heart_rateのみ)は、代わりに終了日からさかのぼってページを取得します。開始日は無視し、最大10ページで停止します。古いデータが残っている場合は、その旨がnotesに記載されます。 - NaN と Infinity は
nullになります。 JSON にはこのような数値がないため、サービスから送信された場合、CLI はnullを出力し、置き換えた数をnotesに記載します。 - サービスが読み取りを途中で打ち切った場合、その旨が通知されます。 サービスが続きのページがあると報告しても、取得に使えるカーソルを送信しない場合、読み取りはそこで停止し、範囲内の行が欠落している可能性があることが
notesに記載されます。 - ワークアウトの詳細読み取りは、屋外でのランニングとサイクリングのみを対象とします。 これまでに確認されたファイル形式(記録ファイルのバージョン8と5、GPSファイルのバージョン2)を対象としています。ウォーキング、ハイキング、水泳、屋内でのランニング、その他のスポーツ、および他のファイルバージョンは、注記が表示され、サンプルは取得されません。それぞれ、実際のファイルと手書きのレイアウトテーブルが必要です。高度は
rawにのみ含まれます。1回の呼び出しで詳細を読み取るワークアウトは最大10件です(長期間の場合は1週間ごとに分割して読み取ります)。GPSトラックからは、居住地を含む現在地がわかります。--no-track(track=False)を指定すると、GPSトラックは除外されます。ダウンロードリンクとキーは出力に表示されません。 - 中国リージョン以外のワークアウトファイルは未テストです。 ファイルは
.fds.api.xiaomi.com配下のホスト(中国リージョンのアカウントで確認されたホスト)からのみダウンロードされます。別のホストへのリンクは注記とともに拒否され、そのワークアウトはサンプルやトラックを含まず、概要のみが保持されます。 - 読み取り専用です。 mifit がアカウントのデータを書き込んだり、変更したり、削除したりすることはありません。
- セッションには有効期限があります。 HTTP 401 が返された場合、mifit は保存済みの passToken からセッションを一度更新し、リクエストを再試行します。更新に失敗した場合、または更新機能が導入される前にセッションが保存されている場合(passToken がない場合)は、
mifit loginを再実行してください。更新機能は2026-10-15に実際の環境で確認済みです。更新なしでの有効期間は引き続き調査中ですが、これまでのところ少なくとも22時間です。ログイン、401、更新は、イベント、時刻、経過時間のみが~/.mifit/session-log.jsonlに記録されます。(HTTP 401 はリクエスト署名が拒否されたことを意味する場合もあります。更新直後の401はそのケースとみなし、再試行しません。) - テストの範囲は限定的です。 中国リージョンの1アカウントでテストしています。他のリージョンにも振り分けられますが、検証はしていません。また、Xiaomi はいつでもプロトコルを変更する可能性があります。
- サービスに負荷をかけないようにしてください。 リクエストは約1秒の間隔とランダムな揺らぎを加えて、1件ずつ送信されます。長期間のデータは分割して読み取られ、92日を超える範囲には
--longが必要です。これによりレート制限のリスクは下がりますが、なくなるわけではありません。
開発
git clone https://github.com/Jenwein/mifit.git
cd mifit
pip install -e ".[test]"
python -m pytest -q
テストはオフラインで実行されます。Xiaomi のクラウドの代わりに偽のトランスポートを使用し、ネットワーク接続を開こうとするとテストは失敗します。test エクストラには tzdata が含まれているため、独自のタイムゾーンデータベースを持たない Windows でも、夏時間のテストが実行されます。CI では、Python 3.12、3.13、3.14 を使用して Linux 上でテストスイートを実行します。
免責事項
mifit は独立した非公式プロジェクトです。Xiaomi との提携、承認、サポートはありません。「Xiaomi」と「Mi Fitness」は各所有者の商標であり、このソフトウェアが対応する対象を示す目的でのみ使用しています。
このソフトウェアは、ご自身のアカウントを使ってご自身のデータを読み取ることを目的としています。自動アクセスは Xiaomi の利用規約に抵触する可能性があり、アカウントのレート制限や利用制限につながるおそれがあります。ご自身の責任でご使用ください。出力される情報は、いかなるものも医療上の助言ではありません。本ソフトウェアは、いかなる保証もなく「現状有姿」で提供されます(LICENSE を参照)。
クレジット
リクエストの署名と暗号化、トランスポート、リージョンテーブル、STS トークン交換は、kevinkwee による Mi-Fitness-Sync(MIT License)を基にしています。THIRD_PARTY_NOTICES を参照してください。
ライセンス
MIT。LICENSE を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。