Skip to main content
Glama
test_withings.py9.36 kB
"""Test script for Withings MCP Server. This script helps you test the Withings API integration manually. It guides you through OAuth authentication and lets you test various API endpoints. """ import asyncio import os import sys from datetime import datetime, timedelta from pathlib import Path from dotenv import load_dotenv # Add src directory to Python path sys.path.insert(0, str(Path(__file__).parent.parent / "src")) from withings_mcp_server.auth import WithingsAuth # Load environment variables load_dotenv() async def test_oauth_flow(): """Test OAuth authentication flow.""" print("\n=== OAuth Authentication Test ===\n") auth = WithingsAuth() if not auth.client_id or not auth.client_secret: print("❌ Error: WITHINGS_CLIENT_ID and WITHINGS_CLIENT_SECRET must be set in .env file") return None # Check if we already have tokens if auth.access_token and auth.refresh_token: print("✓ Access token and refresh token found in environment") try: await auth.ensure_valid_token() print("✓ Token is valid (or refreshed successfully)") return auth except Exception as e: print(f"⚠ Token validation failed: {e}") print(" You may need to re-authenticate") # Generate authorization URL print("No valid tokens found. Starting OAuth flow...\n") auth_url = auth.get_authorization_url() print(f"1. Visit this URL in your browser:\n {auth_url}\n") print("2. Authorize the application") print("3. You will be redirected to your redirect URI with a 'code' parameter") code = input("\n4. Enter the authorization code: ").strip() if not code: print("❌ No code provided") return None try: tokens = await auth.exchange_code_for_token(code) print("\n✓ Authentication successful!") print(f"✓ Tokens automatically saved to {auth.env_file}") print(f"\nYour tokens:") print(f" ACCESS_TOKEN: {tokens['access_token'][:20]}...") print(f" REFRESH_TOKEN: {tokens['refresh_token'][:20]}...") return auth except Exception as e: print(f"\n❌ Authentication failed: {e}") return None async def test_user_info(auth: WithingsAuth): """Test getting user information.""" print("\n=== User Info Test ===\n") try: import httpx headers = auth.get_headers() async with httpx.AsyncClient() as client: response = await client.get( "https://wbsapi.withings.net/v2/user", headers=headers, params={"action": "getdevice"} ) data = response.json() if data.get("status") == 0: print("✓ User info retrieved successfully") print(f"\nDevices: {len(data.get('body', {}).get('devices', []))}") for device in data.get('body', {}).get('devices', []): print(f" - {device.get('type')}: {device.get('model')}") else: print(f"❌ API Error: {data}") except Exception as e: print(f"❌ Error: {e}") async def test_measurements(auth: WithingsAuth): """Test getting measurements.""" print("\n=== Measurements Test ===\n") try: import httpx headers = auth.get_headers() # Get measurements from last 30 days end_date = datetime.now() start_date = end_date - timedelta(days=30) async with httpx.AsyncClient() as client: response = await client.get( "https://wbsapi.withings.net/measure", headers=headers, params={ "action": "getmeas", "startdate": int(start_date.timestamp()), "enddate": int(end_date.timestamp()), } ) data = response.json() if data.get("status") == 0: measuregrps = data.get('body', {}).get('measuregrps', []) print(f"✓ Found {len(measuregrps)} measurement groups") # Show latest 5 measurements for grp in measuregrps[:5]: date = datetime.fromtimestamp(grp['date']) print(f"\n Date: {date.strftime('%Y-%m-%d %H:%M:%S')}") for measure in grp['measures']: mtype = measure['type'] value = measure['value'] * (10 ** measure['unit']) type_name = { 1: "Weight (kg)", 4: "Height (m)", 5: "Fat Free Mass (kg)", 6: "Fat Ratio (%)", 8: "Fat Mass Weight (kg)", 9: "Diastolic BP (mmHg)", 10: "Systolic BP (mmHg)", 11: "Heart Rate (bpm)", 12: "Temperature (°C)", 54: "SpO2 (%)", 76: "Muscle Mass (kg)", 88: "Bone Mass (kg)", }.get(mtype, f"Type {mtype}") print(f" - {type_name}: {value:.2f}") else: print(f"❌ API Error: {data}") except Exception as e: print(f"❌ Error: {e}") async def test_activity(auth: WithingsAuth): """Test getting activity data.""" print("\n=== Activity Test ===\n") try: import httpx headers = auth.get_headers() # Get last 7 days of activity end_date = datetime.now() start_date = end_date - timedelta(days=7) async with httpx.AsyncClient() as client: response = await client.get( "https://wbsapi.withings.net/v2/measure", headers=headers, params={ "action": "getactivity", "startdateymd": start_date.strftime("%Y-%m-%d"), "enddateymd": end_date.strftime("%Y-%m-%d"), } ) data = response.json() if data.get("status") == 0: activities = data.get('body', {}).get('activities', []) print(f"✓ Found {len(activities)} activity days") for activity in activities: print(f"\n Date: {activity.get('date')}") print(f" - Steps: {activity.get('steps', 0)}") print(f" - Distance: {activity.get('distance', 0)} m") print(f" - Calories: {activity.get('calories', 0)} kcal") print(f" - Elevation: {activity.get('elevation', 0)} m") else: print(f"❌ API Error: {data}") except Exception as e: print(f"❌ Error: {e}") async def test_sleep(auth: WithingsAuth): """Test getting sleep data.""" print("\n=== Sleep Test ===\n") try: import httpx headers = auth.get_headers() # Get last 7 days of sleep end_date = datetime.now() start_date = end_date - timedelta(days=7) async with httpx.AsyncClient() as client: response = await client.get( "https://wbsapi.withings.net/v2/sleep", headers=headers, params={ "action": "getsummary", "startdateymd": start_date.strftime("%Y-%m-%d"), "enddateymd": end_date.strftime("%Y-%m-%d"), } ) data = response.json() if data.get("status") == 0: series = data.get('body', {}).get('series', []) print(f"✓ Found {len(series)} sleep sessions") for sleep in series: start = datetime.fromtimestamp(sleep['startdate']) end = datetime.fromtimestamp(sleep['enddate']) duration = (end - start).total_seconds() / 3600 print(f"\n Date: {start.strftime('%Y-%m-%d')}") print(f" - Duration: {duration:.1f} hours") print(f" - Deep sleep: {sleep.get('deepsleepduration', 0) / 3600:.1f} hours") print(f" - Light sleep: {sleep.get('lightsleepduration', 0) / 3600:.1f} hours") print(f" - REM sleep: {sleep.get('remsleepduration', 0) / 3600:.1f} hours") print(f" - Wake up count: {sleep.get('wakeupcount', 0)}") else: print(f"❌ API Error: {data}") except Exception as e: print(f"❌ Error: {e}") async def run_tests(): """Run all tests.""" print("=" * 60) print("Withings MCP Server Test Script") print("=" * 60) # Test OAuth auth = await test_oauth_flow() if not auth: print("\n❌ Authentication failed. Cannot proceed with API tests.") return # Run API tests await test_user_info(auth) await test_measurements(auth) await test_activity(auth) await test_sleep(auth) print("\n" + "=" * 60) print("Tests completed!") print("=" * 60) def main(): """Main entry point.""" asyncio.run(run_tests()) if __name__ == "__main__": main()

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/schimmmi/withings-mcp-server'

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