Oura Ring MCP Server
  
A comprehensive Model Context Protocol (MCP) server for the Oura Ring API V2. Access sleep, activity, readiness, heart rate, stress, and other health data from your Oura Ring through AI assistants like Claude, ChatGPT, or Cursor IDE.
Security First: This server implements read-only operations only for user data. Your health information cannot be modified.
---
What is This?
This MCP server allows AI assistants to access your Oura Ring health data. When connected, you can ask questions like:
- "How did I sleep last night?"
- "What's my readiness score this week?"
- "Show me my heart rate trends"
- "Analyze my stress patterns"
Keywords: Oura Ring, MCP Server, Model Context Protocol, Sleep Tracking, Health Data, Wearable API, AI Integration, Claude, ChatGPT, Cursor
---
Table of Contents
- What is Oura Ring?
- Features
- Quick Start
- Getting an Access Token
- Configuration
- MCP Client Setup
- Available Tools (37 Total)
- Tool Reference
- For AI Agents
- Rate Limiting
- Project Structure
- Security
- Troubleshooting
- Contributing
- License
---
What is Oura Ring?
Oura Ring is a smart ring that tracks:
- Sleep - Sleep stages (deep, light, REM), sleep quality, timing
- Activity - Steps, calories, movement throughout the day
- Readiness - Recovery score based on sleep, activity, and body signals
- Heart Rate - Continuous heart rate and HRV (heart rate variability)
- Body Temperature - Skin temperature deviations
- Stress - Daytime stress and recovery patterns
- SpO2 - Blood oxygen saturation levels
This MCP server provides access to all this data through the Oura API V2.
---
Features
| Feature | Description | |---------|-------------| | 37 MCP Tools | Complete coverage of all Oura API V2 endpoints | | Read-only by design | Cannot modify user data | | OAuth2 Authentication | Secure token-based authentication with refresh token support | | Automatic Token Refresh | Automatically refreshes expired access tokens | | Sandbox Support | Test with mock data before using real data | | Rate Limiting | Built-in rate limiting with exponential backoff | | Token Sanitization | Access tokens are never exposed in logs or errors |
---
Quick Start
1. Clone and Install
git clone https://github.com/trenerok/oura-mcp-server.git
cd oura-mcp-server
npm install
2. Get OAuth2 Credentials
See Getting an Access Token below.
3. Build
npm run build
4. Configure MCP Client
See MCP Client Setup for Claude Desktop, Cursor IDE, or other clients.
---
Getting an Access Token
Oura uses OAuth2 for authentication. Personal access tokens were deprecated in December 2025.
Step 1: Create an OAuth2 Application
- Go to Oura Cloud Applications
- Click "New Application"
- Fill in the required fields:
- Display Name: Your app name (e.g., "My MCP Server")
- Description: Brief description
- Website: Your website or GitHub repo URL
- Privacy Policy: URL (can be your GitHub repo for personal use)
- Terms of Service: URL (can be your GitHub repo for personal use)
- Redirect URI:
http://localhost:8080/callback
- Select all the Scopes you want to access
- Click "Create Application"
- Copy your Client ID and Client Secret
Step 2: Get Access Token
Use the included helper script:
node scripts/get-token.js YOUR_CLIENT_ID YOUR_CLIENT_SECRET
This will:
- Open your browser to authorize the application
- Exchange the authorization code for tokens
- Display your access token and refresh token
Step 3: Save Your Tokens
Add the tokens to your MCP configuration (see MCP Client Setup).
---
Configuration
Environment Variables
| Variable | Required | Description | |----------|----------|-------------| | OURA_ACCESS_TOKEN | Yes* | OAuth2 access token for user data | | OURA_REFRESH_TOKEN | No | Refresh token for automatic token renewal | | OURA_CLIENT_ID | No | OAuth2 application client ID | | OURA_CLIENT_SECRET | No | OAuth2 application client secret | | OURA_USE_SANDBOX | No | Set to true for sandbox/mock data |
\ Required for user data endpoints \* Required for token refresh and webhook management
Automatic Token Refresh
If you provide OURA_REFRESH_TOKEN, OURA_CLIENT_ID, and OURA_CLIENT_SECRET, the server will automatically refresh your access token when it expires (typically after 24 hours).
---
MCP Client Setup
Claude Desktop
Add to your claude_desktop_config.json:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"oura": {
"command": "node",
"args": ["/absolute/path/to/oura-mcp-server/dist/index.js"],
"env": {
"OURA_ACCESS_TOKEN": "your_access_token",
"OURA_REFRESH_TOKEN": "your_refresh_token",
"OURA_CLIENT_ID": "your_client_id",
"OURA_CLIENT_SECRET": "your_client_secret"
}
}
}
}
Cursor IDE
Add to .cursor/mcp.json in your project directory:
{
"mcpServers": {
"oura": {
"command": "node",
"args": ["./dist/index.js"],
"env": {
"OURA_ACCESS_TOKEN": "your_access_token",
"OURA_REFRESH_TOKEN": "your_refresh_token",
"OURA_CLIENT_ID": "your_client_id",
"OURA_CLIENT_SECRET": "your_client_secret"
}
}
}
}
Other MCP Clients
Use similar configuration with the appropriate config file format for your client.
---
Available Tools (37 Total)
Overview by Category
| Category | Count | Tools | |----------|-------|-------| | Personal Info | 1 | User profile (age, weight, height) | | Sleep | 6 | Sleep sessions, daily scores, bedtime recommendations | | Activity | 2 | Daily activity, steps, calories burned | | Health Metrics | 14 | Heart rate, readiness, SpO2, stress, resilience, cardiovascular age, VO2 max | | Workouts | 4 | Workout sessions, meditation/breathing sessions | | Tags | 4 | User-created tags and enhanced tags | | Device | 4 | Ring configuration, rest mode periods | | Webhooks | 6 | Webhook subscription management |
Complete Tool List
Personal Info (1 tool)
| Tool | Description | |------|-------------| | get_personal_info | Get user profile: age, weight, height, biological sex, email |
Sleep (6 tools)
| Tool | Description | |------|-------------| | get_sleep | Detailed sleep sessions with stages (deep, light, REM), HRV, heart rate | | get_sleep_by_id | Single sleep session by document ID | | get_daily_sleep | Daily sleep scores with contributor breakdown | | get_daily_sleep_by_id | Single daily sleep document by ID | | get_sleep_time | Optimal bedtime recommendations | | get_sleep_time_by_id | Single sleep time document by ID |
Activity (2 tools)
| Tool | Description | |------|-------------| | get_daily_activity | Daily steps, calories, active time, MET minutes | | get_daily_activity_by_id | Single daily activity document by ID |
Health Metrics (14 tools)
| Tool | Description | |------|-------------| | get_heart_rate | Heart rate time series (BPM with timestamps) | | get_daily_readiness | Daily readiness scores with contributors | | get_daily_readiness_by_id | Single readiness document by ID | | get_daily_spo2 | Blood oxygen saturation (SpO2) data | | get_daily_spo2_by_id | Single SpO2 document by ID | | get_daily_stress | Daily stress levels and recovery time | | get_daily_stress_by_id | Single stress document by ID | | get_daily_resilience | Daily resilience scores | | get_daily_resilience_by_id | Single resilience document by ID | | get_daily_cardiovascular_age | Vascular age estimates | | get_daily_cardiovascular_age_by_id | Single cardiovascular age document by ID | | get_vo2_max | VO2 max estimates (cardiovascular fitness) | | get_vo2_max_by_id | Single VO2 max document by ID |
Workouts (4 tools)
| Tool | Description | |------|-------------| | get_workouts | Workout sessions (activity type, calories, distance, duration) | | get_workout_by_id | Single workout document by ID | | get_sessions | Meditation and breathing sessions with HRV data | | get_session_by_id | Single session document by ID |
Tags (4 tools)
| Tool | Description | |------|-------------| | get_tags | User-created tags for tracking behaviors | | get_tag_by_id | Single tag document by ID | | get_enhanced_tags | Enhanced tags with metadata and time ranges | | get_enhanced_tag_by_id | Single enhanced tag document by ID |
Device (4 tools)
| Tool | Description | |------|-------------| | get_ring_configuration | Ring details: color, size, firmware, hardware type | | get_ring_configuration_by_id | Single ring configuration by ID | | get_rest_mode_periods | Rest mode activation history | | get_rest_mode_period_by_id | Single rest mode period by ID |
Webhooks (6 tools) - Requires Client Credentials
| Tool | Description | |------|-------------| | list_webhook_subscriptions | List all webhook subscriptions | | get_webhook_subscription | Get a specific webhook by ID | | create_webhook_subscription | Create new webhook subscription | | update_webhook_subscription | Update existing webhook | | delete_webhook_subscription | Delete a webhook subscription | | renew_webhook_subscription | Renew webhook before expiration |
---
Tool Reference
Common Parameters
Date Range Parameters (most tools)
| Parameter | Format | Required | Description | |-----------|--------|----------|-------------| | start_date | YYYY-MM-DD | No | Start of date range | | end_date | YYYY-MM-DD | No | End of date range | | next_token | string | No | Pagination token for next page |
DateTime Parameters (heart rate only)
| Parameter | Format | Required | Description | |-----------|--------|----------|-------------| | start_datetime | ISO 8601 | No | Start datetime (e.g., 2024-01-01T00:00:00Z) | | end_datetime | ISO 8601 | No | End datetime | | next_token | string | No | Pagination token |
Example Responses
Personal Info
{
"id": "abc123",
"age": 35,
"weight": 75.5,
"height": 1.80,
"biological_sex": "male",
"email": "user@example.com"
}
Daily Sleep
{
"data": [
{
"id": "sleep123",
"day": "2024-01-15",
"score": 85,
"contributors": {
"deep_sleep": 80,
"efficiency": 90,
"latency": 85,
"rem_sleep": 75,
"restfulness": 82,
"timing": 95,
"total_sleep": 88
},
"timestamp": "2024-01-15T00:00:00.000+00:00"
}
],
"next_token": null
}
Daily Readiness
{
"data": [
{
"id": "ready123",
"day": "2024-01-15",
"score": 78,
"contributors": {
"activity_balance": 85,
"body_temperature": 100,
"hrv_balance": 72,
"previous_day_activity": 80,
"previous_night": 75,
"recovery_index": 90,
"resting_heart_rate": 82,
"sleep_balance": 70
},
"temperature_deviation": 0.1,
"timestamp": "2024-01-15T00:00:00.000+00:00"
}
],
"next_token": null
}
Heart Rate
{
"data": [
{
"bpm": 62,
"source": "awake",
"timestamp": "2024-01-15T08:30:00+00:00"
},
{
"bpm": 58,
"source": "rest",
"timestamp": "2024-01-15T08:35:00+00:00"
}
],
"next_token": null
}
---
For AI Agents
This section provides structured guidance for AI agents using this MCP server.
Server Capabilities
- Data Access: Read-only access to all Oura Ring health data
- Authentication: OAuth2 Bearer token with automatic refresh
- Real-time Data: Data is fetched live from Oura API
- Pagination: Large datasets return
next_tokenfor pagination
Quick Start for AI Agents
- Verify connectivity: Call
get_personal_infofirst - Use date ranges: Always specify
start_dateto limit data - Handle empty data: Empty arrays mean no data for that period
- Check null values: Many fields may be null if unavailable
Recommended Workflows
Health Dashboard
1. get_personal_info() → Get user profile
2. get_daily_readiness(start_date: "<7 days ago>") → Weekly readiness trend
3. get_daily_sleep(start_date: "<7 days ago>") → Weekly sleep scores
4. get_daily_activity(start_date: "<7 days ago>") → Weekly activity
5. get_daily_stress(start_date: "<7 days ago>") → Weekly stress patterns
Sleep Analysis
1. get_daily_sleep(start_date: "<30 days ago>") → Monthly sleep scores
2. get_sleep(start_date: "<7 days ago>") → Detailed sleep sessions with stages
3. get_sleep_time(start_date: "<7 days ago>") → Bedtime recommendations
Fitness Assessment
1. get_daily_activity(start_date: "<30 days ago>") → Activity trends
2. get_workouts(start_date: "<30 days ago>") → Workout history
3. get_vo2_max(start_date: "<30 days ago>") → Cardiovascular fitness
4. get_heart_rate(start_datetime: "<today>T00:00:00Z") → Today's heart rate
Stress & Recovery
1. get_daily_stress(start_date: "<7 days ago>") → Stress levels
2. get_daily_resilience(start_date: "<7 days ago>") → Resilience scores
3. get_daily_readiness(start_date: "<7 days ago>") → Recovery status
Key Metrics Explained
| Metric | Range | Meaning | |--------|-------|---------| | Sleep Score | 0-100 | Overall sleep quality (>85 = optimal) | | Readiness Score | 0-100 | Recovery level (>85 = ready for activity) | | Activity Score | 0-100 | Daily movement goal progress | | Stress (high) | seconds | Time in high stress state | | Recovery (high) | seconds | Time in recovery/rest state | | HRV | ms | Heart rate variability (higher = better recovery) | | Resting HR | bpm | Resting heart rate (lower = better fitness) |
Error Handling
| Error | Cause | Solution | |-------|-------|----------| | Access token not configured | Missing OURA_ACCESS_TOKEN | Add token to config | | 401 Unauthorized | Token expired | Server auto-refreshes if refresh token provided | | 403 Forbidden | Scope not authorized | Re-authorize with required scopes | | 429 Rate Limit | Too many requests | Server auto-retries with backoff | | Empty data: [] | No data for date range | Try different date range |
Important Notes
- Date Format: Use
YYYY-MM-DDfor dates - Datetime Format: Use ISO 8601 for
get_heart_rate(e.g.,2024-01-15T00:00:00Z) - Timezone: Data is returned in user's timezone
- Pagination: If
next_tokenis not null, more data is available - Null Values: Fields may be null if ring wasn't worn or data unavailable
---
Rate Limiting
The server implements automatic rate limiting per Oura API documentation.
| Limit | Value | |-------|-------| | Requests | 5000 per 5 minutes | | Algorithm | Token bucket with refill | | Retry | Exponential backoff (1s → 2s → 4s, max 30s) | | Max Retries | 3 attempts |
---
Project Structure
oura-mcp-server/
├── src/
│ ├── index.ts # MCP server entry point
│ ├── client.ts # Oura API client with auth & rate limiting
│ ├── rate-limiter.ts # Token bucket rate limiter
│ ├── types.ts # TypeScript type definitions
│ └── tools/
│ ├── index.ts # Tool aggregator
│ ├── personal-info.ts
│ ├── sleep.ts
│ ├── activity.ts
│ ├── health.ts
│ ├── workout.ts
│ ├── tags.ts
│ ├── device.ts
│ └── webhook.ts
├── scripts/
│ └── get-token.js # OAuth2 token helper
├── dist/ # Compiled JavaScript
├── package.json
├── tsconfig.json
├── .env.example
├── .gitignore
├── LICENSE
├── CHANGELOG.md
└── README.md
---
Security
Best Practices
- Never commit tokens — Use environment variables
- Use refresh tokens — Enable automatic token renewal
- Test with sandbox — Set
OURA_USE_SANDBOX=truefor development - Limit scopes — Only request OAuth2 scopes you need
Security Features
- Access tokens sanitized from all error messages
- Read-only API access (cannot modify data)
- Automatic token refresh (no manual token management)
- Rate limiting prevents API abuse
---
Troubleshooting
Common Issues
| Issue | Solution | |-------|----------| | Cannot find module | Run npm run build | | Access token not configured | Add OURA_ACCESS_TOKEN to env | | 401 Unauthorized | Token expired; add refresh token or get new token | | 403 Forbidden | Missing OAuth2 scope; re-authorize app | | Empty data returned | Check date range; ensure ring synced data | | Token not authorized for scope | Re-create OAuth2 app with required scopes |
Getting Help
- Check Oura API Documentation
- Open an issue on GitHub
- Check MCP Protocol Documentation
---
Development
# Install dependencies
npm install
# Build TypeScript
npm run build
# Watch mode (auto-rebuild)
npm run dev
# Run server
npm start
# Clean build
npm run clean
---
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make changes and test:
npm run build - Commit:
git commit -m "Add my feature" - Push:
git push origin feature/my-feature - Create a Pull Request
---
API Reference
---
License
MIT License — see LICENSE file.
---
Disclaimer
This software is provided "as is" without warranty. This project is not affiliated with or endorsed by Oura Health Oy.
Not medical advice. Oura Ring data is for informational purposes only and should not be used for medical diagnosis or treatment.






