withings-mcp
# withings-mcp
<!-- mcp-name: io.github.partymola/withings-mcp -->
[](https://github.com/partymola/withings-mcp/actions/workflows/ci.yml)
[](https://www.gnu.org/licenses/gpl-3.0)
[](https://www.python.org/downloads/)
[](https://pypi.org/project/withings-mcp/)
[](https://glama.ai/mcp/servers/partymola/withings-mcp)
MCP server for the [Withings Health API](https://developer.withings.com/) with OAuth, local SQLite cache, and trend analysis.
**What makes this different from other Withings MCP servers:**
- Local SQLite cache for fast offline queries and historical trend analysis
- Incremental sync - only fetches new data since last sync
- Broad Withings coverage: 17 body-composition metrics plus sleep, daily activity, workouts, and ECG/AFib
- Automatic OAuth token refresh (access tokens: 3h, refresh tokens: 1 year)
- Zero dependencies beyond `mcp` (HTTP via stdlib)
- Python 3.13+ (tested on 3.13 and 3.14, on Linux, macOS and Windows, in CI)
## Tools
| Tool | Description | Data source |
|------|-------------|-------------|
| `withings_sync` | Sync data from Withings API to local cache | Live API -> SQLite |
| `withings_get_body` | Body composition (weight, fat%, muscle, bone, BP, SpO2) | Local cache (auto-syncs if stale) |
| `withings_get_sleep` | Sleep summaries, or detailed phase time-series with `detail=True` | Cache (summary) / live (detail) |
| `withings_get_activity` | Daily steps, distance, calories, active time | Local cache (auto-syncs if stale) |
| `withings_get_workouts` | Workout sessions with type, duration, HR | Local cache (auto-syncs if stale) |
| `withings_get_heart` | ECG recordings and AFib detection | Live API (always) |
| `withings_get_devices` | Connected devices with battery status | Live API (always) |
| `withings_trends` | Period averages, weekly/monthly/quarterly trends, comparisons | Local cache (auto-syncs if stale) |
The cache-backed query tools auto-sync when their data is stale, and accept `live=True` to bypass the cache and fetch straight from the Withings API. `withings_get_heart` and `withings_get_devices` are always live. `withings_get_sleep(detail=True)` returns minute-by-minute sleep phases (live, up to 7 days per request).
## Prerequisites
- Python 3.13+ (tested on 3.13 and 3.14, on Linux, macOS and Windows, in CI)
- [uv](https://docs.astral.sh/uv/) (recommended) or pip
- A Withings developer account and registered application
## Installation
```bash
pip install withings-mcp
```
Or run it without installing with `uvx withings-mcp`. For development from a clone:
```bash
git clone https://github.com/partymola/withings-mcp.git
cd withings-mcp
uv venv --python 3.13 .venv
uv pip install -e .
```
## Setup
### 1. Register a Withings app
1. Go to https://developer.withings.com/dashboard
2. Create a new application
3. Set the callback URL to `http://localhost:8585`
4. Note your Client ID and Client Secret
### 2. Authenticate
```bash
.venv/bin/withings-mcp auth
```
This opens your browser for Withings authorization. After approving, tokens are saved locally in `config/`.
### 3. Register with Claude Code
```bash
claude mcp add -s user withings -- /path/to/withings-mcp/.venv/bin/withings-mcp
```
### 4. First sync
In Claude Code, say: "Sync my Withings data"
This runs `withings_sync` to populate the local cache. Subsequent syncs only fetch new data.
If anything does not work - no data where you expect it, a sync that stops happening - run `withings-mcp doctor`. It reports the paths and credentials actually in use and what needs fixing, without making an API call.
You can also sync from the command line without an MCP client:
```bash
.venv/bin/withings-mcp sync # all data types, last 30 days
.venv/bin/withings-mcp sync --types body,sleep # a subset
.venv/bin/withings-mcp sync --days 90 # deeper history on first sync
```
## CLI
```
withings-mcp Start the MCP server (stdio transport)
withings-mcp auth Interactive OAuth setup (opens the browser)
withings-mcp sync Sync data to the local cache (--types, --days)
withings-mcp doctor Check the setup and report what needs fixing
withings-mcp --version Print the installed package version
```
## Configuration
| Environment Variable | Default | Description |
|---------------------|---------|-------------|
| `WITHINGS_MCP_CONFIG_DIR` | `./config/` | Directory for credentials and tokens |
| `WITHINGS_MCP_DB_PATH` | `./withings.db` | SQLite database path |
## Example Prompts
- "Sync my Withings data"
- "Show my weight for the last 3 months"
- "How has my sleep changed this year?"
- "Compare my body composition this month vs last month"
- "What workouts did I do in March?"
- "What Withings devices do I have connected?"
- "Show my sleep trends quarterly"
## Development
```bash
# Install with dev dependencies
uv pip install -e . && uv pip install pytest
# Run tests (all use in-memory SQLite with fictional data)
.venv/bin/python -m pytest tests/ -v # .venv\Scripts\python on Windows
```
## Security
- **Read-only**: No tools modify data on Withings servers
- **Local storage**: Health data stays in your local SQLite database
- **Token storage**: OAuth tokens stored in `config/` (gitignored; created 0600 on POSIX - Windows ignores the mode and governs access by ACLs)
- **Error messages**: Never contain health data values - only status codes
- **Pre-commit hook**: An optional hook (`scripts/check-no-data.sh`) blocks database files and credentials from commits - install it with the one-liner in [CONTRIBUTING.md](https://github.com/partymola/withings-mcp/blob/main/CONTRIBUTING.md)
## Contributing
See [CONTRIBUTING.md](https://github.com/partymola/withings-mcp/blob/main/CONTRIBUTING.md) for development setup, the test workflow, and the pre-commit hook. Changes are tracked in [CHANGELOG.md](https://github.com/partymola/withings-mcp/blob/main/CHANGELOG.md).
## License
GPL-3.0-or-later
TDQS
Scored across 8 tools
Each tool targets a distinct data domain: activity, workouts, body composition, sleep, heart ECG, devices, and trend analysis. Cross-references are used effectively to prevent confusion between similar tools like activity vs workouts and body vs sleep.
Most tools follow a clear withings_get_<resource> pattern, making the set predictable. The exceptions are withings_sync and withings_trends, which break the get- verb pattern but are still understandable and not chaotic.
With 8 tools, the server is well-scoped for a health-data integration covering sync, raw data retrieval, and analysis. Each tool has a clear purpose and the count feels neither bloated nor thin.
The tool surface covers the major Withings health domains: activity, workouts, body composition, sleep, heart/ECG, devices, and trend analysis. The sync tool provides a reasonable update mechanism, and there are no obvious dead ends or missing lifecycle operations.