@einlogic/mcp-fitbit 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,209 +1,184 @@
1
- # Fitbit MCP Connector for AI
2
-
3
- [![Fitbit API](https://img.shields.io/badge/Fitbit-00B0B9?logo=fitbit&logoColor=white)](https://dev.fitbit.com/)
4
- [![CI](https://github.com/TheDigitalNinja/mcp-fitbit/actions/workflows/ci.yml/badge.svg)](https://github.com/TheDigitalNinja/mcp-fitbit/actions/workflows/ci.yml)
5
- [![Coverage Status](https://coveralls.io/repos/github/TheDigitalNinja/mcp-fitbit/badge.svg?branch=main)](https://coveralls.io/github/TheDigitalNinja/mcp-fitbit?branch=main)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
- [![npm version](https://badge.fury.io/js/mcp-fitbit.svg)](https://badge.fury.io/js/mcp-fitbit)
8
- [![npm downloads](https://img.shields.io/npm/dm/mcp-fitbit.svg)](https://www.npmjs.com/package/mcp-fitbit)
9
-
10
- > Connect AI assistants to your Fitbit health data
11
-
12
- Give your AI assistant access to your Fitbit data for personalized health insights, trend analysis, and automated tracking. Works with Claude Desktop and other MCP-compatible AI tools.
13
-
14
- ## What it does
15
-
16
- 🏃 **Exercise & Activities** - Get detailed workout logs and activity data
17
- 😴 **Sleep Analysis** - Retrieve sleep patterns and quality metrics
18
- ⚖️ **Weight Tracking** - Access weight trends over time
19
- ❤️ **Heart Rate Data** - Monitor heart rate patterns and zones
20
- 🍎 **Nutrition Logs** - Review food intake, calories, and macros
21
- 👤 **Profile Info** - Access basic Fitbit profile details
22
-
23
- *Ask your AI things like: "Show me my sleep patterns this week" or "What's my average heart rate during workouts?"*
24
-
25
- ## Quick Start
26
-
27
- **🚀 Want to test the tools right away?**
28
-
29
- ### Option 1: Install from npm (Recommended)
30
- 1. [Get Fitbit API credentials](https://dev.fitbit.com/)
31
- - Create an app with OAuth 2.0 Application Type: `Personal`
32
- - Set Callback URL: `http://localhost:3000/callback`
33
- - Note your **Client ID** and **Client Secret**
34
-
35
- 2. Install the package globally:
36
- ```bash
37
- npm install -g mcp-fitbit
38
- ```
39
-
40
- 3. Add to your Claude Desktop config file:
41
- ```json
42
- {
43
- "mcpServers": {
44
- "fitbit": {
45
- "command": "mcp-fitbit",
46
- "args": [],
47
- "env": {
48
- "FITBIT_CLIENT_ID": "your_client_id_here",
49
- "FITBIT_CLIENT_SECRET": "your_client_secret_here"
50
- }
51
- }
52
- }
53
- }
54
- ```
55
- - Config file location:
56
- - Windows: %AppData%\Claude\claude_desktop_config.json
57
- - macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
58
- - Linux: ~/.config/Claude/claude_desktop_config.json
59
-
60
- 4. Restart Claude Desktop and ask about your Fitbit data!
61
-
62
-
63
-
64
- ### Option 2: Development Setup
65
- 1. [Get Fitbit API credentials](https://dev.fitbit.com/) (see Installation below)
66
- 2. Then run:
67
-
68
- ```bash
69
- git clone https://github.com/TheDigitalNinja/mcp-fitbit
70
- cd mcp-fitbit
71
- npm install
72
- # Create .env with your Fitbit credentials
73
- npm run dev
74
- ```
75
-
76
- Both options open the **MCP Inspector** at `http://localhost:5173` where you can test all tools interactively and handle the OAuth flow.
77
-
78
- ## Installation
79
-
80
- ### For End Users (npm package)
81
-
82
- 1. **Get Fitbit API credentials** at [dev.fitbit.com](https://dev.fitbit.com/)
83
- - Set **OAuth 2.0 Application Type** to `Personal`
84
- - Set **Callback URL** to `http://localhost:3000/callback`
85
-
86
- 2. **Install the package:**
87
- ```bash
88
- npm install -g mcp-fitbit
89
- ```
90
-
91
- 3. **Create `.env` file in the package directory:**
92
-
93
- When you run `mcp-fitbit` for the first time, it will tell you exactly where to create the `.env` file. It will look something like:
94
- ```
95
- C:\Users\YourName\AppData\Roaming\npm\node_modules\mcp-fitbit\.env
96
- ```
97
-
98
- 4. **Add your credentials to the `.env` file:**
99
- ```bash
100
- FITBIT_CLIENT_ID=your_client_id_here
101
- FITBIT_CLIENT_SECRET=your_client_secret_here
102
- ```
103
-
104
- 5. **Run the server:**
105
- ```bash
106
- mcp-fitbit
107
- ```
108
-
109
- ### For Developers (from source)
110
-
111
- 1. **Get Fitbit API credentials** at [dev.fitbit.com](https://dev.fitbit.com/)
112
- - Set **OAuth 2.0 Application Type** to `Personal`
113
- - Set **Callback URL** to `http://localhost:3000/callback`
114
-
115
- 2. **Clone and setup:**
116
- ```bash
117
- git clone https://github.com/TheDigitalNinja/mcp-fitbit
118
- cd mcp-fitbit
119
- npm install
120
- ```
121
-
122
- 3. **Create `.env` file:**
123
- ```bash
124
- FITBIT_CLIENT_ID=your_client_id_here
125
- FITBIT_CLIENT_SECRET=your_client_secret_here
126
- ```
127
-
128
- 4. **Build the server:**
129
- ```bash
130
- npm run build
131
- ```
132
-
133
-
134
- ## Available Tools
135
-
136
- | Tool | Description | Parameters |
137
- |------|-------------|------------|
138
- | `get_weight` | Weight data over time periods | `period`: `1d`, `7d`, `30d`, `3m`, `6m`, `1y` |
139
- | `get_sleep_by_date_range` | Sleep logs for date range (max 100 days) | `startDate`, `endDate` (YYYY-MM-DD) |
140
- | `get_exercises` | Activity/exercise logs after date | `afterDate` (YYYY-MM-DD), `limit` (1-100) |
141
- | `get_daily_activity_summary` | Daily activity summary with goals | `date` (YYYY-MM-DD) |
142
- | `get_activity_goals` | User's activity goals (daily/weekly) | `period`: `daily`, `weekly` |
143
- | `get_activity_timeseries` | Activity time series data (max 30 days) | `resourcePath`, `startDate`, `endDate` (YYYY-MM-DD) |
144
- | `get_azm_timeseries` | Active Zone Minutes time series (max 1095 days) | `startDate`, `endDate` (YYYY-MM-DD) |
145
- | `get_heart_rate` | Heart rate for time period | `period`: `1d`, `7d`, `30d`, `1w`, `1m`, optional `date` |
146
- | `get_heart_rate_by_date_range` | Heart rate for date range (max 1 year) | `startDate`, `endDate` (YYYY-MM-DD) |
147
- | `get_food_log` | Complete nutrition data for a day | `date` (YYYY-MM-DD or "today") |
148
- | `get_nutrition` | Individual nutrient over time | `resource`, `period`, optional `date` |
149
- | `get_nutrition_by_date_range` | Individual nutrient for date range | `resource`, `startDate`, `endDate` |
150
- | `get_profile` | User profile information | None |
151
-
152
- **Nutrition resources:** `caloriesIn`, `water`, `protein`, `carbs`, `fat`, `fiber`, `sodium`
153
-
154
- **Activity time series resources:** `steps`, `distance`, `calories`, `activityCalories`, `caloriesBMR`, `tracker/activityCalories`, `tracker/calories`, `tracker/distance`
155
-
156
- ### Claude Desktop
157
-
158
- **Using npm package (recommended):**
159
-
160
- Add to `claude_desktop_config.json`:
161
- ```json
162
- {
163
- "mcpServers": {
164
- "fitbit": {
165
- "command": "mcp-fitbit",
166
- "args": []
167
- }
168
- }
169
- }
170
- ```
171
-
172
- **Using local development version:**
173
-
174
- Add to `claude_desktop_config.json`:
175
- ```json
176
- {
177
- "mcpServers": {
178
- "fitbit": {
179
- "command": "node",
180
- "args": ["C:\\path\\to\\mcp-fitbit\\build\\index.js"]
181
- }
182
- }
183
- }
184
- ```
185
-
186
- **Config file locations:**
187
- - Windows: `%AppData%\Claude\claude_desktop_config.json`
188
- - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
189
- - Linux: `~/.config/Claude/claude_desktop_config.json`
190
-
191
- ### First Run Authorization
192
-
193
- When you first ask your AI assistant to use Fitbit data:
194
- 1. The server opens your browser to `http://localhost:3000/auth`
195
- 2. Log in to Fitbit and grant permissions
196
- 3. You'll be redirected to a success page
197
- 4. Your AI can now access your Fitbit data!
198
-
199
- ## Development
200
-
201
- ```bash
202
- npm run lint # Check code quality
203
- npm run format # Fix formatting
204
- npm run build # Compile TypeScript
205
- npm run dev # Run with MCP inspector
206
- ```
207
-
208
- **Architecture:** See [TASKS.md](TASKS.md) for improvement opportunities and technical details.
209
-
1
+ # Google Health (Fitbit) MCP Connector for AI
2
+
3
+ [![CI](https://github.com/TheDigitalNinja/mcp-fitbit/actions/workflows/ci.yml/badge.svg)](https://github.com/TheDigitalNinja/mcp-fitbit/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ > Connect AI assistants to your Fitbit / Pixel Watch health data through the **Google Health API**
7
+
8
+ The legacy Fitbit Web API was shut down on **2 November 2026**. Google replaced it with the
9
+ [Google Health API](https://developers.google.com/health), which uses Google OAuth 2.0. This server now talks to
10
+ the Google Health API and returns its raw JSON.
11
+
12
+ ## What it does
13
+
14
+ 🏃 **Exercise & Activities** - Workout sessions and daily activity roll-ups
15
+ 😴 **Sleep Analysis** - Sleep sessions
16
+ ⚖️ **Weight Tracking** - Weight data points
17
+ ❤️ **Heart Rate Data** - Samples, daily roll-ups and HRV
18
+ 🍎 **Nutrition Logs** - Food log, calories, macros and water
19
+ 👤 **Profile & Devices** - Profile, settings, identity and paired trackers
20
+
21
+ *Ask your AI things like: "Show me my sleep patterns this week" or "What's my step count trend this month?"*
22
+
23
+ ## ⚠️ Breaking changes from the Fitbit version
24
+
25
+ - You must create a **Google Cloud** OAuth client (see below) and re-authorize. Old Fitbit tokens cannot be reused.
26
+ - Credentials are now `GOOGLE_HEALTH_CLIENT_ID` / `GOOGLE_HEALTH_CLIENT_SECRET` (the old `FITBIT_*` names still work as a fallback).
27
+ - The token file is now `.google-health-token.json` (the old `.fitbit-token.json` is ignored and can be deleted).
28
+ - Responses are the Google Health API's JSON, not Fitbit's. Fitbit-style `period` (`1d`, `7d`, ...) parameters are gone: tools take explicit start/end times, as the API does.
29
+ - `get_activity_goals` was removed: the Google Health API has no goals endpoint.
30
+ - New tools: `get_identity`, `get_settings`, `list_paired_devices`, `list_data_points`, `reconcile_data_points`.
31
+
32
+ ## Setup
33
+
34
+ ### 1. Link your account to Google Health
35
+
36
+ In the **Google Health mobile app**, tap **Sign in with Google** and choose the Google Account to use (this creates a
37
+ Google Health profile or migrates your existing Fitbit account). Without this, the API returns `ACCOUNT_NOT_LINKED`.
38
+
39
+ ### 2. Create Google OAuth credentials
40
+
41
+ 1. In the [Google Cloud Console](https://console.cloud.google.com/), create (or pick) a project.
42
+ 2. [Enable the Google Health API](https://console.developers.google.com/apis/library/health.googleapis.com).
43
+ 3. Create an **OAuth client ID** of type **Web application** and add the authorized redirect URI
44
+ `http://localhost:3000/callback`. Note the **Client ID** and **Client secret**.
45
+ 4. On the [OAuth consent screen / Audience](https://console.developers.google.com/auth/audience) page, keep the user
46
+ type **External** and add your Google Account under **Test users**.
47
+ 5. On the [Data Access](https://console.developers.google.com/auth/scopes) page, add these scopes (all read-only):
48
+ - `https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly`
49
+ - `https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonly`
50
+ - `https://www.googleapis.com/auth/googlehealth.sleep.readonly`
51
+ - `https://www.googleapis.com/auth/googlehealth.nutrition.readonly`
52
+ - `https://www.googleapis.com/auth/googlehealth.profile.readonly`
53
+ - `https://www.googleapis.com/auth/googlehealth.settings.readonly`
54
+
55
+ > **Refresh tokens in Testing mode expire after 7 days.** For a personal tool, set the app's publishing status to
56
+ > **In production** (an unverified app is limited to 100 users and shows a warning screen at consent, which is fine
57
+ > for your own account). Verification is only required beyond that.
58
+
59
+ ### 3. Install and configure
60
+
61
+ **From npm:**
62
+ ```bash
63
+ npm install -g mcp-fitbit
64
+ ```
65
+
66
+ **From source:**
67
+ ```bash
68
+ git clone https://github.com/TheDigitalNinja/mcp-fitbit
69
+ cd mcp-fitbit
70
+ npm install
71
+ npm run build
72
+ ```
73
+
74
+ Create a `.env` file in the package directory (the server prints the expected path if it is missing):
75
+ ```bash
76
+ GOOGLE_HEALTH_CLIENT_ID=your_client_id_here
77
+ GOOGLE_HEALTH_CLIENT_SECRET=your_client_secret_here
78
+ ```
79
+
80
+ ### 4. Claude Desktop
81
+
82
+ Add to `claude_desktop_config.json`:
83
+ ```json
84
+ {
85
+ "mcpServers": {
86
+ "google-health": {
87
+ "command": "mcp-fitbit",
88
+ "args": [],
89
+ "env": {
90
+ "GOOGLE_HEALTH_CLIENT_ID": "your_client_id_here",
91
+ "GOOGLE_HEALTH_CLIENT_SECRET": "your_client_secret_here"
92
+ }
93
+ }
94
+ }
95
+ }
96
+ ```
97
+ For a local build use `"command": "node", "args": ["C:\\path\\to\\mcp-fitbit\\build\\index.js"]`.
98
+
99
+ Config file locations:
100
+ - Windows: `%AppData%\Claude\claude_desktop_config.json`
101
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
102
+ - Linux: `~/.config/Claude/claude_desktop_config.json`
103
+
104
+ ### First Run Authorization
105
+
106
+ 1. The server opens your browser to `http://localhost:3000/auth`
107
+ 2. Sign in to Google and grant the requested Google Health permissions
108
+ 3. The server verifies your Google Health link (`/v4/users/me/identity`) and saves the token
109
+ 4. Your AI can now access your data. Access tokens refresh automatically.
110
+
111
+ ## Available Tools
112
+
113
+ Time parameters follow the API: ranges are **start inclusive, end exclusive**. Samples (`get_weight`, `get_heart_rate`)
114
+ use RFC 3339 timestamps (e.g. `2026-03-04T00:00:00Z`); sessions use civil time (`YYYY-MM-DD` or `YYYY-MM-DDTHH:MM:SS`).
115
+ List tools accept `pageSize` and `pageToken` (use `nextPageToken` from the response).
116
+
117
+ | Tool | Google Health API | Parameters |
118
+ |------|-------------------|------------|
119
+ | `get_weight` | `weight` data points | `startTime`, optional `endTime` (RFC 3339) |
120
+ | `get_sleep_by_date_range` | `sleep` data points (max 25/page) | `startTime`, optional `endTime` (civil) |
121
+ | `get_exercises` | `exercise` data points (max 25/page) | `startTime`, optional `endTime` (civil) |
122
+ | `get_daily_activity_summary` | daily roll-ups of steps, distance, total calories, active zone minutes, floors | `date` |
123
+ | `get_activity_timeseries` | `dailyRollUp` (max 90 days; 14 for calories/active minutes) | `dataType`, `startDate`, `endDate` |
124
+ | `get_azm_timeseries` | `dailyRollUp` of `active-zone-minutes` | `startDate`, `endDate` |
125
+ | `get_heart_rate` | `heart-rate` samples | `startTime`, optional `endTime` (RFC 3339) |
126
+ | `get_heart_rate_by_date_range` | `dailyRollUp` of `heart-rate` (max 14 days) | `startDate`, `endDate` |
127
+ | `get_hrv` / `get_hrv_by_date_range` | `daily-heart-rate-variability` | `date` / `startDate`, `endDate` |
128
+ | `get_food_log` | `nutrition-log` data points | `startTime`, optional `endTime` (civil) |
129
+ | `get_nutrition` / `get_nutrition_by_date_range` | `dailyRollUp` of `nutrition-log` / `hydration-log` | `dataType`, `date` / `startDate`, `endDate` |
130
+ | `get_profile` | `users/me/profile` | none |
131
+ | `get_identity` | `users/me/identity` | none |
132
+ | `get_settings` | `users/me/settings` | none |
133
+ | `list_paired_devices` | `users/me/pairedDevices` | none |
134
+ | `list_data_points` | any of the 38 data types | `dataType`, optional raw `filter` |
135
+ | `reconcile_data_points` | `dataPoints:reconcile` for any data type | `dataType`, optional `filter`, `dataSourceFamily` |
136
+
137
+ **Activity data types:** `steps`, `distance`, `total-calories`, `active-energy-burned`, `floors`, `active-minutes`
138
+
139
+ See the [data types reference](https://developers.google.com/health/data-types) for everything `list_data_points` can query.
140
+
141
+ ## Fitbit-compatible output mode
142
+
143
+ Set `GOOGLE_HEALTH_OUTPUT_MODE=fitbit` (in the Claude Desktop `env` block or `.env`) to make the overlapping tools behave
144
+ like the old Fitbit Web API server, so prompts and projects written against it keep working. The default (`google`) mode
145
+ is unchanged. In `fitbit` mode these tools are replaced by Fitbit-shaped versions (same names, `period` parameters and
146
+ **inclusive** end dates); everything else (`get_profile`, `get_exercises`, `get_identity`, `get_settings`,
147
+ `list_paired_devices`, `list_data_points`, `reconcile_data_points`) stays a Google proxy.
148
+
149
+ | Tool | Fitbit-style response | Notes |
150
+ |------|----------------------|-------|
151
+ | `get_weight` (`period`, `date?`) | `{ weight: [{ date, time, logId, weight }] }` | Pounds (follows the account unit). Duplicate weigh-ins from several sources are collapsed to one. No `bmi`/`fat`. |
152
+ | `get_sleep_by_date_range` | `{ sleep: [{ dateOfSleep, minutesAsleep, timeInBed, levels.summary.{deep,light,rem,wake} }] }` | Max 100 days. No sleep score or efficiency (the Fitbit API had neither). |
153
+ | `get_daily_activity_summary` | `{ activities: [], goals: {}, summary: { caloriesOut, steps, distances, floors, *ActiveMinutes, restingHeartRate, heartRateZones } }` | Miles. Exercise sessions and goals are not included. |
154
+ | `get_heart_rate` (`period`) / `get_heart_rate_by_date_range` | `{ 'activities-heart': [{ dateTime, value: { restingHeartRate, heartRateZones } }] }` | Zones: Out of Range / Fat Burn / Cardio / Peak with `min`, `max`, `minutes`, `caloriesOut`. |
155
+ | `get_hrv` / `get_hrv_by_date_range` | `{ hrv: [{ dateTime, value: { dailyRmssd, deepRmssd } }] }` | Milliseconds; max 30 days. |
156
+ | `get_activity_timeseries` | `{ 'activities-<resource>': [{ dateTime, value: '<string>' }] }` | `steps`, `distance`, `calories`, `activityCalories` (+ `tracker/` variants). `caloriesBMR` is not available. |
157
+ | `get_azm_timeseries` | `{ 'activities-active-zone-minutes': [...] }` | Total + fat burn / cardio / peak. |
158
+ | `get_food_log` / `get_nutrition` / `get_nutrition_by_date_range` | Fitbit food-log summary / `foods-log-caloriesIn`, `foods-log-water` | No individual food entries or goals. |
159
+
160
+ How the numbers are mapped (verified against a real day of Fitbit-era data):
161
+
162
+ - **Heart-rate zones:** Fitbit's Out of Range / Fat Burn / Cardio / Peak are Google's Light / Moderate / Vigorous / Peak.
163
+ Fat Burn minutes equal Active Zone Minutes fat burn (1x); Cardio and Peak minutes are Active Zone Minutes divided by 2
164
+ (they count double). Out of Range comes from time-in-zone. Calories per zone come from `calories-in-heart-rate-zone`
165
+ and the bpm bounds from the account's own `daily-heart-rate-zones`.
166
+ - **Sleep:** stage minutes come straight from Google's stage summary, which matched Fitbit's deep/REM numbers exactly.
167
+ The wake date (`dateOfSleep`) is derived from the sleep end time and its UTC offset.
168
+ - **Units and time zone:** weight, distance and water follow the account's Google Health unit settings; days are
169
+ interpreted in the account time zone (override with `COMPAT_TIME_ZONE`).
170
+ - **Known small differences:** Google re-derives some values, so a historical day can differ slightly from what Fitbit
171
+ returned at the time (e.g. a few steps or 1 bpm of resting heart rate). Fields that could not be provided are listed in a
172
+ top-level `_compat.notes` array when relevant.
173
+
174
+ ## Development
175
+
176
+ ```bash
177
+ npm run build # Compile TypeScript
178
+ npm test # Run tests
179
+ npm run lint # Check code quality
180
+ npm run format # Fix formatting
181
+ npm run dev # Run with MCP inspector
182
+ ```
183
+
184
+ **Architecture:** See [CLAUDE.md](CLAUDE.md) and [MIGRATION_PLAN.md](MIGRATION_PLAN.md).
@@ -0,0 +1,32 @@
1
+ import { registerTool, handleGoogleHealthCall } from './utils.js';
2
+ /**
3
+ * Registers account-level tools: identity, settings and paired devices.
4
+ * @param server The McpServer instance.
5
+ * @param getAccessTokenFn Function to retrieve the current access token.
6
+ */
7
+ export function registerAccountTools(server, getAccessTokenFn) {
8
+ registerTool(server, {
9
+ name: 'get_identity',
10
+ description: "Get the raw JSON response for the user's Google Health identity (legacyUserId and healthUserId). Returns an error if the Google Account is not linked to Google Health.",
11
+ parametersSchema: {},
12
+ handler: async () => handleGoogleHealthCall('users/me/identity', getAccessTokenFn, {
13
+ errorContext: 'identity',
14
+ }),
15
+ });
16
+ registerTool(server, {
17
+ name: 'get_settings',
18
+ description: "Get the raw JSON response for the user's Google Health settings (units, locale, time zone, stride settings).",
19
+ parametersSchema: {},
20
+ handler: async () => handleGoogleHealthCall('users/me/settings', getAccessTokenFn, {
21
+ errorContext: 'settings',
22
+ }),
23
+ });
24
+ registerTool(server, {
25
+ name: 'list_paired_devices',
26
+ description: 'Get the raw JSON response listing the trackers and smartwatches paired to the user (device version and type, battery level, last sync time, features).',
27
+ parametersSchema: {},
28
+ handler: async () => handleGoogleHealthCall('users/me/pairedDevices', getAccessTokenFn, {
29
+ errorContext: 'paired devices',
30
+ }),
31
+ });
32
+ }
@@ -1,25 +1,23 @@
1
- import { registerTool, CommonSchemas, handleFitbitApiCall } from './utils.js';
2
- // --- Tool Registration ---
1
+ import { registerTool, CommonSchemas, listDataPoints, buildRangeFilter, } from './utils.js';
3
2
  /**
4
- * Registers a Fitbit activities/exercises tool with the MCP server.
3
+ * Registers the exercise tool with the MCP server (Google Health `exercise` data type).
5
4
  * @param server The McpServer instance.
6
5
  * @param getAccessTokenFn Function to retrieve the current access token.
7
6
  */
8
7
  export function registerActivitiesTool(server, getAccessTokenFn) {
9
8
  registerTool(server, {
10
9
  name: 'get_exercises',
11
- description: "Get the raw JSON response for exercise and activity logs from Fitbit after a specific date. Requires 'afterDate' parameter in 'YYYY-MM-DD' format. Retrieves a detailed list of logged exercises and activities.",
10
+ description: 'Get the raw JSON response for exercise sessions from the Google Health API (data type "exercise"), filtered by the civil start time. Requires a start civil time; the end is optional and exclusive. Note: the API returns at most 25 exercises per page; use pageToken to continue.',
12
11
  parametersSchema: {
13
- afterDate: CommonSchemas.afterDate,
14
- limit: CommonSchemas.limit,
12
+ startTime: CommonSchemas.civilStartTime,
13
+ endTime: CommonSchemas.civilEndTime,
14
+ pageSize: CommonSchemas.pageSize,
15
+ pageToken: CommonSchemas.pageToken,
15
16
  },
16
- handler: async ({ afterDate, limit = 20 }) => {
17
- const endpoint = `activities/list.json?afterDate=${afterDate}&sort=asc&offset=0&limit=${limit}`;
18
- return handleFitbitApiCall(endpoint, { afterDate, limit }, getAccessTokenFn, {
19
- successDataExtractor: (data) => data.activities || [],
20
- noDataMessage: `after date '${afterDate}'`,
21
- errorContext: `after date '${afterDate}'`
22
- });
23
- }
17
+ handler: async ({ startTime, endTime, pageSize, pageToken, }) => listDataPoints('exercise', getAccessTokenFn, {
18
+ filter: buildRangeFilter('exercise.interval.civil_start_time', startTime, endTime),
19
+ pageSize,
20
+ pageToken,
21
+ }, `exercise from '${startTime}'${endTime ? ` to '${endTime}'` : ''}`),
24
22
  });
25
23
  }
@@ -1,5 +1,13 @@
1
1
  import { z } from 'zod';
2
- import { registerTool, CommonSchemas, handleFitbitApiCall } from './utils.js';
2
+ import { registerTool, CommonSchemas, dailyRollUp } from './utils.js';
3
+ export const ACTIVITY_DATA_TYPES = [
4
+ 'steps',
5
+ 'distance',
6
+ 'total-calories',
7
+ 'active-energy-burned',
8
+ 'floors',
9
+ 'active-minutes',
10
+ ];
3
11
  /**
4
12
  * Registers an activity time series tool with the MCP server.
5
13
  * @param server The McpServer instance.
@@ -8,28 +16,14 @@ import { registerTool, CommonSchemas, handleFitbitApiCall } from './utils.js';
8
16
  export function registerActivityTimeSeriesTool(server, getAccessTokenFn) {
9
17
  registerTool(server, {
10
18
  name: 'get_activity_timeseries',
11
- description: "Get the raw JSON response for activity time series data from Fitbit over a date range (max 30 days). Supports various resource paths like 'steps', 'distance', 'calories', 'activityCalories', 'caloriesBMR'.",
19
+ description: "Get the raw JSON response for daily activity roll-ups from the Google Health API (dailyRollUp) over a civil date range. Supports data types 'steps', 'distance', 'total-calories', 'active-energy-burned', 'floors', 'active-minutes'. startDate is inclusive, endDate is exclusive. Note: The API allows at most 90 days per request (14 days for 'total-calories' and 'active-minutes').",
12
20
  parametersSchema: {
13
- resourcePath: z
14
- .enum([
15
- 'steps',
16
- 'distance',
17
- 'calories',
18
- 'activityCalories',
19
- 'caloriesBMR',
20
- 'tracker/activityCalories',
21
- 'tracker/calories',
22
- 'tracker/distance'
23
- ])
24
- .describe("Activity resource to retrieve (e.g., 'steps', 'distance', 'calories')"),
21
+ dataType: z
22
+ .enum(ACTIVITY_DATA_TYPES)
23
+ .describe("Activity data type to roll up (e.g., 'steps', 'distance')"),
25
24
  startDate: CommonSchemas.startDate,
26
25
  endDate: CommonSchemas.endDate,
27
26
  },
28
- handler: async ({ resourcePath, startDate, endDate }) => {
29
- const endpoint = `activities/${resourcePath}/date/${startDate}/${endDate}.json`;
30
- return handleFitbitApiCall(endpoint, { resourcePath, startDate, endDate }, getAccessTokenFn, {
31
- errorContext: `resource '${resourcePath}' from ${startDate} to ${endDate}`
32
- });
33
- }
27
+ handler: async ({ dataType, startDate, endDate, }) => dailyRollUp(dataType, getAccessTokenFn, { startDate, endDate }, `data type '${dataType}' from ${startDate} to ${endDate}`),
34
28
  });
35
29
  }