Fitbit Air Daily Planner MCP Server
by fujirecords
README.md
# Fitbit Air Daily Planner
Fitbit/Pixel Watch由来のGoogle Health APIデータとGoogle Calendarの予定を組み合わせ、ChatGPTがその日のウェルネスプランを作るApps SDK + MCPアプリです。プランは確認カードで承認した場合だけ、専用Googleカレンダーへ登録されます。
> 単一ユーザー向けのハッカソンMVPです。医療機器ではなく、診断・治療・緊急時対応には使用できません。
## なぜこの構成か
- 推論はChatGPT内のGPT-5.6が担当し、OpenAI APIを呼びません。
- サーバーはGoogle Health API v4とCalendar APIの取得・整形・書き込みだけを行います。
- 旧Google Fit REST APIは2026年末、旧Fitbit Web APIは2026年9月に停止予定のため使用しません。
- Calendarのプライマリは読み取り専用、書き込みは`GOOGLE_CALENDAR_ID`で固定した専用カレンダーだけです。
- Calendarのprivate extended propertyで再試行時の重複登録を防ぎます。
- Cloudflare D1には本人プロフィールと日別集計だけを保存し、前週比と継続利用を実現します。生の心拍時系列やCalendar本文は保存しません。
- 行動目標は厚生労働省「健康づくりのための身体活動・運動ガイド2023」の成人向け推奨値を参考にし、個人差と当日の体調を優先します。
## アーキテクチャ
```mermaid
flowchart LR
D["Fitbit / Pixel Watch"] --> H["Google Health API v4"]
C["Google Calendar primary"] --> M["Cloudflare Worker / MCP"]
H --> M
G["ChatGPT / GPT-5.6"] <-->|"Streamable HTTP"| M
G --> W["Apps SDK cards"]
W -->|"confirm"| M
M --> P["Planner-only Calendar"]
P --> N["Desktop / mobile reminders"]
```
## MCPツール
| ツール | 動作 |
|---|---|
| `get_health_summary` | 指定日の歩数、睡眠、心拍、欠損を取得し健康カードを表示 |
| `get_weekly_health_trend` | 1〜14日の日別データと平均・達成日数を返す |
| `save_user_profile` | 初回の生年月日・膝状態を保存し、年齢別目標を設定 |
| `list_calendar_events` | プライマリカレンダーを読み取り、場所を含む予定を返す |
| `create_calendar_events` | `confirm:false`で下書き、カード承認後の`true`で専用カレンダーへ登録 |
## ローカルセットアップ
必要環境:Node.js 20以上、npm、Google Cloudプロジェクト。
```bash
npm install
cp .dev.vars.example .dev.vars
npm test
npm run check
npm run dev
```
MCP URLはローカルでは`http://localhost:8787/mcp`、ヘルスチェックは`/healthz`です。ChatGPTからの実機接続には公開HTTPS URLが必要です。
## Google Cloud / OAuth
1. Google CloudでGoogle Health APIとGoogle Calendar APIを有効化する。
2. OAuth consent screenをExternal / Testingにし、本人をTest userへ追加する。
3. Web application OAuth clientを作る。
4. 次の最小スコープをData Accessへ追加する。
```text
https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly
https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonly
https://www.googleapis.com/auth/googlehealth.sleep.readonly
https://www.googleapis.com/auth/calendar.events
```
5. OAuth Playgroundまたは補助スクリプトで本人のrefresh tokenを取得する。
```bash
GOOGLE_CLIENT_ID=... npm run oauth:url
GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... GOOGLE_AUTH_CODE=... npm run oauth:exchange
```
`GOOGLE_REDIRECT_URI`を省略するとOAuth Playground URLを使います。取得した秘密情報は`.dev.vars`またはCloudflare Secretsにだけ保存し、コミットしません。
Testingモードのrefresh tokenは7日で失効します。`AUTH_EXPIRED`になったら再認可してください。未検証アプリは最大100ユーザーで、100ユーザー超または一般公開にはOAuth verificationと第三者セキュリティレビューが必要です。
## 環境変数
| 名前 | 種別 | 説明 |
|---|---|---|
| `GOOGLE_CLIENT_ID` | Secret | Google OAuth client ID |
| `GOOGLE_CLIENT_SECRET` | Secret | Google OAuth client secret |
| `GOOGLE_REFRESH_TOKEN` | Secret | 互換用token。個別tokenが未設定の場合のみ使用 |
| `GOOGLE_HEALTH_REFRESH_TOKEN` | Secret | Google Healthの読み取りスコープだけで認可したtoken |
| `GOOGLE_CALENDAR_REFRESH_TOKEN` | Secret | `calendar.events`スコープだけで認可したtoken |
| `GOOGLE_CALENDAR_ID` | Secret | 書き込み専用カレンダーID。`primary`は禁止運用 |
| `MCP_SHARED_SECRET` | Secret/任意 | MCP endpointのBearer token |
| `DEFAULT_TIMEZONE` | Variable | 既定`Asia/Tokyo` |
| `STEPS_GOAL` | Variable | 既定`8000`。Google Health APIに目標APIがないためアプリ設定 |
| `ALLOWED_ORIGIN` | Variable | 既定`https://chatgpt.com` |
| `KNEE_STATUS` | Variable | `ok / pain / unknown`。既定`unknown`、Fitbitから推測しない |
| `BIRTH_DATE` | Secret/任意 | D1未使用時の単一ユーザー向け生年月日。D1プロフィールを優先 |
## D1プロフィール・ログ
初回ダッシュボードで生年月日を入力すると、D1設定済み環境ではプロフィールへ保存されます。日別ログは歩数、歩数目標、睡眠分数、安静時心拍、欠損項目だけです。
```bash
npx wrangler d1 create fitbit-daily-planner
# 出力されたdatabase_idでwrangler.jsoncへDB bindingを追加
npx wrangler d1 migrations apply fitbit-daily-planner --local
```
追加するbinding:
```jsonc
"d1_databases": [{
"binding": "DB",
"database_name": "fitbit-daily-planner",
"database_id": "作成時に表示されたID"
}]
```
## Cloudflareへのデプロイ手順(現時点では未実施)
```bash
npx wrangler login
npx wrangler secret put GOOGLE_CLIENT_ID
npx wrangler secret put GOOGLE_CLIENT_SECRET
npx wrangler secret put GOOGLE_REFRESH_TOKEN
npx wrangler secret put GOOGLE_HEALTH_REFRESH_TOKEN
npx wrangler secret put GOOGLE_CALENDAR_REFRESH_TOKEN
npx wrangler secret put GOOGLE_CALENDAR_ID
npx wrangler secret put MCP_SHARED_SECRET
npm run deploy
```
Cloudflare Workers Freeは小規模な単一ユーザー利用に十分ですが、無料枠超過時はリクエストが失敗する構成にし、有料機能へ自動移行しないでください。
## ChatGPTへの登録と受入確認
ChatGPT BusinessのWeb版で、Workspaceの管理者/オーナーがDeveloper Modeを有効化し、デプロイした`https://...workers.dev/mcp`をカスタムアプリとして登録します。full MCPとwrite/modify actionsはBusiness / Enterprise / EduのWeb版へbeta提供中であり、利用資格・権限・追加確認UIを実機で確認してください。
推奨プロンプト:
> 今日の健康サマリーと直近7日の傾向、今日の予定を確認し、無理のないウェルネスプランを作ってください。既存予定と重ねず、最初はカレンダーへ書き込まず確認カードを出してください。
確認項目:
1. 健康カードに実データまたは明示的な欠損が出る。
2. GPTが3つの読み取りツールを使い、プランを説明する。
3. `confirm:false`ではカレンダーに何も増えない。
4. カードのボタン後に専用カレンダーだけへ登録される。
5. 同じ操作を再実行しても重複しない。
Scheduled Tasksからカスタムアプリを自動呼び出せるかはアカウント/ロールアウト依存の実機検証項目です。非対応でも上記1プロンプト体験を提出版の本線とします。
## 行動提案の基準
- 成人の既定参考値は、1日60分以上の身体活動(目安約8,000歩)、息が弾み汗をかく程度以上の運動を週60分以上、筋力トレーニングを週2〜3日です。
- 月曜〜日曜を1週間として評価し、土日、とくに日曜日は平日の不足を責めず「今週残っている実行機会」として自宅・近所の有酸素運動を提案できます。1回の運動で日々の不足が完全に帳消しになるとは説明しません。
- ジムやOWLなど外部施設・運動アプリへの誘導は行いません。移動を伴わない選択肢を優先します。
- 本人が別作業で`kneeStatus: ok`と設定し、当日の体調にも問題がない場合は、自重スクワット20秒+休息10秒×8セット(本編4分)を時短候補にできます。ウォームアップとクールダウンを併記し、膝の痛み・違和感または状態不明時は提案しません。
- 4分メニューを厚労省の週60分と同等換算せず、田畑式原法の効果を一般的な20/10運動へそのまま帰属させません。
## 制限と安全性
- ChatGPTカスタムMCPと書き込みアクションはBusiness / Enterprise / EduのWeb版が対象です。
- Apps SDK UIはWeb版で確認します。モバイルではカスタムMCPアプリを利用できない場合があります。
- Google Health APIのTesting tokenは7日で失効します。
- Google Health APIの未検証アプリは100ユーザーまでです。
- センサー未装着、同期遅延、機種差により値が欠損します。ゼロとして補完しません。
- 健康状態を断定せず、行動提案は散歩・休憩・ストレッチ・自宅での短時間運動・睡眠習慣など一般的なウェルネス支援に限定します。
- MCPは単一Googleアカウントのtokenを共有します。第三者向けに公開しないでください。
- `MCP_SHARED_SECRET`を設定し、ChatGPT側で認証を渡せる構成にしてください。認証設定不可ならURLを公開共有しないでください。
## 撤去
1. Cloudflare Workerを削除する。
2. Google AccountのThird-party accessからアプリの権限を取り消す。
3. Google CloudのOAuth credentialsと専用カレンダーを削除する。
4. ローカルの`.dev.vars`を削除する。
D1データベースも削除してください。保存対象はプロフィールと日別集計だけで、Durable Objectsや生データの永続コピーはありません。
## 提出資料
- [制約・技術検証](docs/constraints.md)
- [3分デモ台本](docs/demo-script.md)
- [Devpost説明文](docs/devpost.md)
- [公開前チェックリスト](docs/release-checklist.md)
本人ログイン、OAuth認可、Developer Mode、デプロイ、実データ確認、録画・公開・提出は[別チャット用の手作業票](docs/04-manual-setup.md)へ分離しています。本リポジトリの実装工程ではデプロイしません。
## Codexの利用
Codexを使って、API廃止状況の調査、Google Health API v4への設計変更、MCPツール・Apps SDKカード・OAuth・重複防止・テスト・提出資料を一貫して作成しました。提出時にメイン開発セッションの`/feedback` IDを追記してください。
## License
MIT
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues