Skip to main content
Glama
owenobyrne

Withings MCP Server

by owenobyrne

Withings MCP Server

A Model Context Protocol server that wraps the Withings Health API — including the full OAuth2 handshake and token refresh — so an MCP client (Claude, etc.) can read your smart-scale data: weight, body fat, muscle mass, bone mass, water, and more.

It runs as a remote, hosted server on AWS Lambda (Streamable-HTTP transport), with:

  • Withings credentials in SSM Parameter Store SecureString parameters (KMS-encrypted).

  • Withings tokens in DynamoDB (encrypted at rest), refreshed automatically.

  • A server-side /callback route that completes the Withings OAuth exchange for you.

  • Its own minimal OAuth 2.0 server guarding the MCP endpoint, so you connect it to Claude by pasting a client ID + secret — no custom headers required.

It also runs locally (single process, JSON-file token cache) for development.

Two OAuth flows, don't confuse them. (1) Claude → this server: the built-in OAuth authorization server (/authorize, /token) that lets Claude obtain an access token. (2) This server → Withings: the flow that links your Withings account (withings_start_authorization + /callback). You set up (1) once when adding the connector, and (2) once to link your scale.


Architecture

  Claude ──OAuth (id+secret)──▶  Lambda Function URL
                                   │
                    ┌──────────────┴────────────────────┐
                    │  Starlette ASGI app (Mangum)       │
                    │   /.well-known/oauth-*  discovery  │
                    │   /authorize /token     OAuth AS   │  ← Claude authenticates
                    │   /mcp        Streamable-HTTP      │──▶ tools (Bearer-protected)
                    │   /callback   Withings code→token  │
                    │   /health                          │
                    └───────┬────────────────────┬───────┘
                            │                    │
                  SSM SecureString          DynamoDB
            (withings + oauth client creds)  (withings tokens + oauth codes)
                            │
                            └──▶ Withings API (account.withings.com, wbsapi.withings.net)

Why Lambda + Streamable-HTTP: the transport runs stateless (one self-contained JSON request/response per call), which maps cleanly onto Lambda — no long-lived SSE connection to hold open. Tokens live in DynamoDB precisely because Lambda containers are ephemeral.

How the MCP OAuth works (Claude → this server)

The /mcp endpoint is protected by an access token, but you never paste a token anywhere. This server implements just enough of OAuth 2.0 for Claude's built-in client to obtain one:

  1. Claude hits /mcp, gets 401 with a WWW-Authenticate header pointing at the discovery metadata.

  2. Claude reads /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server.

  3. Claude runs the authorization-code + PKCE flow using the client ID/secret you configured, and receives an access token (+ refresh token) it stores and sends automatically on every call.

Security with minimal machinery: token issuance at /token requires the client secret (a confidential client), PKCE prevents code interception, and redirect_uri hosts are allow-listed so the server can't be abused as an open redirector. Access tokens are HMAC-signed with the client secret, so validating a request needs no database lookup.


Related MCP server: Withings MCP Server

Tools

Tool

Description

withings_connection_status

Whether an account is linked and when the token expires.

withings_start_authorization

Returns an authorization_url to open in a browser to grant access.

withings_get_measurements

Weight + body-composition groups, filterable by meastypes, start_date/end_date, days, limit.

withings_get_latest_weight

The most recent weigh-in with full body composition.

withings_list_measure_types

All Withings measurement type codes with names/units.

withings_disconnect

Delete the stored tokens.

Measurement values are returned already decoded (Withings sends value + unit exponent; the server computes value × 10^unit), e.g. {"weight": {"value": 70.5, "unit": "kg"}}.


Prerequisites

  1. A Withings developer account and application: developer.withings.comDashboard → create an app. Note the Client ID and Client Secret. You will add a Callback URL after the first deploy (step 5).

  2. AWS account with credentials configured (aws configure).

  3. AWS SAM CLI (brew install aws-sam-cli or install docs) and Python 3.12.


Deploy to AWS (Lambda)

1. Store secrets in SSM Parameter Store

These are KMS-encrypted SecureStrings (default aws/ssm key — no extra cost) and are never placed in the CloudFormation template or Lambda env vars.

WITHINGS_CLIENT_ID=xxxxxxxx \
WITHINGS_CLIENT_SECRET=yyyyyyyy \
./scripts/setup-ssm.sh

WITHINGS_CLIENT_ID/SECRET are from your Withings developer app. The script also generates an OAuth Client ID + Client Secret (for Claude → this server) and prints them — save these, you'll paste them into Claude in the last step. (Override with OAUTH_CLIENT_ID=... OAUTH_CLIENT_SECRET=..., or change the SSM prefix with SSM_PREFIX=....)

2. Build

sam build

3. First deploy (redirect URL not known yet)

cp samconfig.toml.example samconfig.toml   # edit region if needed
sam deploy --guided                        # accept defaults; leave PublicBaseUrl empty

When it finishes, note the stack Outputs:

  • FunctionUrl — e.g. https://abc123.lambda-url.eu-west-1.on.aws/

  • McpEndpoint — that URL + mcp

  • RedirectUri — that URL + callback

4. Register the callback in Withings

In your Withings app settings, add the RedirectUri from the outputs (exactly, including https:// and /callback) to the app's Callback URLs.

5. Redeploy with the public base URL

The server needs to know its own address to build the OAuth redirect_uri. Pass the FunctionUrl without a trailing slash:

sam deploy --parameter-overrides \
  "SsmPrefix=/withings-mcp PublicBaseUrl=https://abc123.lambda-url.eu-west-1.on.aws"

That's it — the server is live.


Connect an MCP client (Claude)

Add a custom / remote MCP connector pointing at the McpEndpoint (.../mcp). In the connector's Advanced / OAuth settings, paste the OAuth Client ID and OAuth Client Secret that setup-ssm.sh printed.

That's all the configuration — no headers, no tokens. When you enable the connector, Claude discovers the server's OAuth metadata, opens a browser to complete the authorization-code flow, and stores the resulting access token itself. It refreshes the token automatically when it expires.

If a client insists on Dynamic Client Registration and has no field for a client ID/secret, tell me — this server can add a minimal /register endpoint. The current design targets the "paste client ID + secret" path you asked for.

Once the connector is authenticated:

  1. Ask Claude to call withings_start_authorization.

  2. Open the returned authorization_url, sign in to Withings, approve.

  3. You're redirected to /callback, which stores your Withings tokens and shows a success page.

  4. Call withings_connection_status to confirm, then withings_get_latest_weight or withings_get_measurements.

Withings access tokens are refreshed automatically using the stored refresh token, so this is a one-time step.


Local development

python -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
cp .env.example .env          # fill in Withings client id/secret
python scripts/run_local.py   # serves http://localhost:8000

Register http://localhost:8000/callback as a callback URL in your Withings app and set PUBLIC_BASE_URL=http://localhost:8000 in .env. Tokens are cached to ~/.withings-mcp/tokens.json. The MCP endpoint is http://localhost:8000/mcp.

To skip the MCP OAuth handshake while poking at the server locally, set OAUTH_DISABLE=1 in .env (the /mcp endpoint is then unauthenticated — local use only).

Run the tests (no network/AWS needed):

pytest

Security notes

  • Secrets never leave SSM except as decrypted values inside the Lambda execution environment. The IAM role grants ssm:GetParameter* scoped to <prefix>/* and kms:Decrypt only ViaService ssm.

  • The MCP endpoint is OAuth-protected. The Function URL is AuthType: NONE (so Withings and Claude's browser flow can reach the public routes), but /mcp requires a valid access token this server issued. Tokens are HMAC-signed with the OAuth client secret and checked in constant time; rotate access by re-running setup-ssm.sh with a new OAUTH_CLIENT_SECRET (this also invalidates all previously issued tokens).

  • The OAuth authorization server is deliberately minimal but not loose: confidential client (secret required at /token), PKCE S256 enforced, and redirect_uri restricted to an allow-listed set of hosts (OAUTH_ALLOWED_REDIRECT_HOSTS). Authorization codes are single-use with a 5-minute TTL.

  • /callback (Withings) is public but CSRF-protected: it only accepts an OAuth state that this server issued (stored in DynamoDB with a 10-minute TTL) and consumes it once.

  • Tokens sit in DynamoDB with encryption at rest (AWS-owned KMS key by default). For a customer-managed key, add an SSESpecification with SSEType: KMS and your key ARN in template.yaml.

  • This is a single-user server ("my scale data"). To support multiple Withings accounts, key the token store by the Withings userid returned in the token response instead of the fixed tokens partition key.


Measurement type reference (common scale metrics)

Code

Metric

Unit

1

Weight

kg

5

Fat-free mass

kg

6

Fat ratio

%

8

Fat mass weight

kg

76

Muscle mass

kg

77

Hydration

kg

88

Bone mass

kg

170

Visceral fat

Call withings_list_measure_types for the full set (blood pressure, heart rate, SpO₂, temperature, pulse wave velocity, etc.).


License

MIT

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    -
    quality
    D
    maintenance
    Enables retrieval of health data from Withings smart scales including weight measurements and comprehensive body composition metrics like fat mass, muscle mass, and hydration levels. Supports multiple users, unit preferences, and OAuth authentication for secure access to personal health data.
    Last updated
    2
  • A
    license
    A
    quality
    A
    maintenance
    Provides read-only access to Withings health metrics including body composition, sleep, workouts, and ECG data with local SQLite caching and trend analysis. Features incremental synchronization, automatic OAuth token refresh, and supports all 200+ Withings measurement types for comprehensive health tracking.
    Last updated
    8
    GPL 3.0
  • A
    license
    -
    quality
    D
    maintenance
    An MCP server that connects Claude to Withings health data using OAuth 2.0. Provides 11 read-only tools to access body measurements, activity, sleep, heart rate, and device information from Withings devices.
    Last updated
    MIT

View all related MCP servers

Related MCP Connectors

  • MCP server for Withings health data — sleep, activity, heart, and body metrics.

  • Wger MCP — wraps wger Workout Manager REST API (free, no auth for read)

  • Brazilian Open Finance MCP — 30+ banks (Itaú, Nubank, etc.) to Claude/Cursor. Read-only.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/owenobyrne/mcp-withings'

If you have feedback or need assistance with the MCP directory API, please join our Discord server