Content
# Oura Ring MCP Server
[](https://opensource.org/licenses/MIT)
[](https://nodejs.org/)
[](https://modelcontextprotocol.io/)
A comprehensive Model Context Protocol (MCP) server for the [Oura Ring](https://ouraring.com/) 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?](#what-is-oura-ring)
- [Features](#features)
- [Quick Start](#quick-start)
- [Getting an Access Token](#getting-an-access-token)
- [Configuration](#configuration)
- [MCP Client Setup](#mcp-client-setup)
- [Available Tools (37 Total)](#available-tools-37-total)
- [Tool Reference](#tool-reference)
- [For AI Agents](#for-ai-agents)
- [Rate Limiting](#rate-limiting)
- [Project Structure](#project-structure)
- [Security](#security)
- [Troubleshooting](#troubleshooting)
- [Contributing](#contributing)
- [License](#license)
---
## What is Oura Ring?
[Oura Ring](https://ouraring.com/) 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](https://cloud.ouraring.com/v2/docs).
---
## 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
```bash
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](#getting-an-access-token) below.
### 3. Build
```bash
npm run build
```
### 4. Configure MCP Client
See [MCP Client Setup](#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
1. Go to [Oura Cloud Applications](https://cloud.ouraring.com/oauth/applications)
2. Click "New Application"
3. 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`
4. Select all the **Scopes** you want to access
5. Click "Create Application"
6. Copy your **Client ID** and **Client Secret**
### Step 2: Get Access Token
Use the included helper script:
```bash
node scripts/get-token.js YOUR_CLIENT_ID YOUR_CLIENT_SECRET
```
This will:
1. Open your browser to authorize the application
2. Exchange the authorization code for tokens
3. Display your access token and refresh token
### Step 3: Save Your Tokens
Add the tokens to your MCP configuration (see [MCP Client Setup](#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`
```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:
```json
{
"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
```json
{
"id": "abc123",
"age": 35,
"weight": 75.5,
"height": 1.80,
"biological_sex": "male",
"email": "user@example.com"
}
```
#### Daily Sleep
```json
{
"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
```json
{
"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
```json
{
"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_token` for pagination
### Quick Start for AI Agents
1. **Verify connectivity**: Call `get_personal_info` first
2. **Use date ranges**: Always specify `start_date` to limit data
3. **Handle empty data**: Empty arrays mean no data for that period
4. **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-DD` for 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_token` is 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](https://cloud.ouraring.com/v2/docs).
| 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
1. **Never commit tokens** — Use environment variables
2. **Use refresh tokens** — Enable automatic token renewal
3. **Test with sandbox** — Set `OURA_USE_SANDBOX=true` for development
4. **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
1. Check [Oura API Documentation](https://cloud.ouraring.com/v2/docs)
2. Open an issue on GitHub
3. Check [MCP Protocol Documentation](https://modelcontextprotocol.io/)
---
## Development
```bash
# 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
1. Fork the repository
2. Create a feature branch: `git checkout -b feature/my-feature`
3. Make changes and test: `npm run build`
4. Commit: `git commit -m "Add my feature"`
5. Push: `git push origin feature/my-feature`
6. Create a Pull Request
---
## API Reference
- [Oura API V2 Documentation](https://cloud.ouraring.com/v2/docs)
- [Oura Authentication Guide](https://cloud.ouraring.com/docs/authentication)
- [Model Context Protocol](https://modelcontextprotocol.io/)
---
## License
MIT License — see [LICENSE](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.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
mcp-labs
Repository of my experiments with MCP
arifOS
ArifOS — AAA MCP-governed constitutional kernel for AI agents.
TealFlowMCP
MCP server for building Teal R Shiny apps with AI assistance. Clinical trial...
blind_navigation
Travel Assistance System for the Visually Impaired is an AI-powered solution...
mcp-limitless-server
This is an MCP (Model Context Protocol) server that connects your Limitless...
MedMCP-Calc
The first benchmark for evaluating LLMs in realistic medical calculator...