Oura-MCP
This server connects Oura Ring data to conversational AI clients (ChatGPT, Claude, etc.), enabling natural-language queries about your health and wellness — all read-only, defaulting to the last 7 days with no arguments needed.
Sleep Scores: Daily sleep scores (0–100) with contributor breakdowns (deep sleep, REM, latency, timing).
Sleep Details: Per-night session data including bed/wake times, sleep stages in minutes, sleep latency, efficiency, night heart rate, HRV, and breathing rate.
Readiness Scores: Daily recovery scores with contributors like HRV balance, resting heart rate, sleep balance, and body temperature deviation — useful for "should I train today?"
Activity Tracking: Daily activity scores, step counts, active and total calories, and optionally minutes by intensity level.
Stress Monitoring: Daily stress summaries including high stress minutes, high recovery minutes, and an overall day verdict (e.g., "restored", "stressful").
Health Vitals: Slow-changing metrics like blood oxygen (SpO2), breathing disturbance index, resilience level, cardiovascular age, and VO2 max.
Workouts & Sessions: Logged workouts (type, intensity, calories, distance) and mind-body sessions (meditation, breathing, relaxation).
User Tags: Tags logged in the Oura app (caffeine, alcohol, sickness, custom notes) to correlate lifestyle factors with health outcomes.
Hourly Heart Rate: Aggregated avg/min/max bpm across day and night for up to 3 days.
Profile & Ring Status: User profile info (age, sex, height, weight) and ring details (model, firmware, battery level).
Most tools support a concise or detailed response format for token efficiency, and the server works in demo/sandbox mode without an Oura account.
oura-mcp
Ask your Oura Ring anything. In ChatGPT or Claude, in any language.
A remote MCP server that connects Oura Ring data to any MCP client. No UI, no app, no model of its own: the assistant you already pay for calls the tools and explains your data in whatever language you speak.
You: how did I sleep this week?
ChatGPT: Your week was uneven, averaging 65/100. Best night was June 29 (77) with strong deep sleep. The rough one was July 2 (47): little REM, low efficiency, and your bedtime drifted way off schedule. The main pattern to fix is sleep timing.
Get started in two clicks: download oura-mcp.mcpb from the latest release and double-click it — Claude Desktop installs the extension, and demo mode works instantly with zero setup (fake sample data, no Oura account needed). Connecting your own ring takes ~5 minutes: Run locally.
Things to try once connected:
Should I train hard today or take it easy?
Compare my sleep on workdays vs the weekend.
Did the late coffee I tagged yesterday show up in my night heart rate?
Какой у меня был пульс сегодня днём?How it works
flowchart LR
A["ChatGPT / Claude"] -- "MCP (Streamable HTTP)" --> B["oura-mcp"]
B -- "REST, read-only" --> C["Oura API v2"]One small Node.js process, stateless — a fresh MCP server instance per request. The client model picks the right tools, the server returns compact, pre-shaped JSON, the model does the talking. Curious how it's put together and why? See docs/ARCHITECTURE.md.
When you don't need this: if you want dashboards and charts, the Oura app already does that; if you want raw data for scripts, call the Oura API directly. This server exists for one thing: making your ring data conversational in the chat client you already use.
Related MCP server: oura-ring-mcp
Tools
Tool | Ask things like |
| "How did I sleep this week?" |
| "When did I fall asleep? How much deep sleep? Night heart rate?" |
| "Should I train today? Is my temperature elevated?" |
| "How many steps and calories yesterday?" |
| "How stressed was I on Monday?" |
| "What's my SpO2, VO2 max, cardiovascular age?" |
| "How was my run? Did I meditate this week?" |
| "Did coffee affect my sleep?" (reads tags you log in the Oura app) |
| "What was my pulse this afternoon?" (hourly aggregates) |
| "How charged is my ring?" |
All tools are read-only and marked with readOnlyHint, so ChatGPT does not nag you for confirmation on every call.
Designed for LLMs, not for dashboards
Task-oriented tools, not 1:1 endpoint wrappers. 18 Oura endpoints grouped into 10 tools that match how people actually ask questions.
Token-efficient responses. Durations converted to minutes server-side, units baked into field names (
deep_min,efficiency_pct), raw time series and internal IDs stripped. A tool response is 0.2–3 KB, not 50.response_format: concise | detailedon data-heavy tools. Concise by default, breakdowns on demand.Actionable errors. A too-wide heart rate query returns "ask for 3 days or less, or use oura_get_readiness for trends", not a 400.
Sane defaults. Every tool works with zero arguments (last 7 days).
Requirements
An Oura Ring with an active Oura subscription (the API returns 403 without one) — or nothing at all for the sandbox demo mode
Node 22+ or Docker
5 minutes to register your own Oura OAuth app (below)
Only for the remote path (ChatGPT, claude.ai web): any host with public HTTPS — a free-tier VM behind Caddy works fine. Avoid free tiers that sleep between requests: ChatGPT times out on cold starts
Why do I need my own Oura app?
Oura deprecated personal access tokens in December 2025, so an OAuth app is the only supported way to access your data — this is Oura's rule, not this project's. Registering one is free, instant, and needs no review for personal use. It is also the best part of the design: your tokens are issued to your app and live on your server, so your health data never depends on anyone else's infrastructure — including mine.
Run locally (Claude Desktop) — easiest start
No server to deploy: Claude Desktop starts oura-mcp itself as a local process.
Install (two clicks): download oura-mcp.mcpb from the latest release, double-click it, press Install. Done — demo mode works immediately (fake sandbox data, no Oura account), so you can try every tool before any setup. Claude will remind you the numbers are samples.
Connect your real ring (~5 minutes):
Create your own Oura app (free, instant, no review) at developer.ouraring.com/applications — set the redirect URI to exactly
http://localhost:8888/callbackIn Claude Desktop: Settings → Extensions → oura-mcp → Configure → paste the app's Client ID and Client Secret (the secret is stored in your OS keychain)
Ask Claude a health question — your browser opens the Oura consent page. Approve, ask again, and you're looking at your own data. Tokens stay on your machine (
~/.oura-mcp/, chmod 600).
Prefer a config-file setup, or using a different stdio client? The docker route works everywhere:
{
"mcpServers": {
"oura": {
"command": "docker",
"args": ["run", "-i", "--rm", "ghcr.io/rajskij/oura-mcp:latest", "node", "dist/src/stdio.js"]
}
}
}Ask Claude "how did I sleep this week?" — you'll get answers from Oura's sandbox data, which is exactly how the real thing behaves.
Register an OAuth app at developer.ouraring.com/applications (redirect URI
http://localhost:8888/callback) and put the credentials in an.envfile next to a copy of docker-compose.ymlOne-time browser consent, saves tokens to
./data:docker compose --profile setup up get-tokenPoint the same config at your credentials and tokens:
{
"mcpServers": {
"oura": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--env-file", "/absolute/path/to/.env",
"-v", "/absolute/path/to/data:/app/data",
"ghcr.io/rajskij/oura-mcp:latest",
"node", "dist/src/stdio.js"
]
}
}
}Running from source instead of Docker: npm install && npm run build, then use "command": "node", "args": ["/path/to/oura-mcp/dist/src/stdio.js"] (with cwd at the repo so data/tokens.json resolves).
Self-hosting (remote: ChatGPT, claude.ai web)
Docker (recommended)
# 1. Register an OAuth app at developer.ouraring.com/applications
# Redirect URI: http://localhost:8888/callback
# 2. Configure
curl -O https://raw.githubusercontent.com/Rajskij/oura-mcp/main/docker-compose.yml
curl -o .env https://raw.githubusercontent.com/Rajskij/oura-mcp/main/.env.example
# fill in .env: client id/secret, generate MCP_PATH_SECRET (openssl rand -hex 24)
# 3. Connect an Oura account (one-time browser consent on this machine)
docker compose --profile setup up get-token
# 4. Run
docker compose up -dKeep PORT=3000 in .env (or adjust the compose port mapping to match).
Needs Node 22+.
# 1. Register an OAuth app at developer.ouraring.com/applications
# Redirect URI: http://localhost:8888/callback
# 2. Configure
cp .env.example .env # fill in client id/secret, generate MCP_PATH_SECRET
# 3. Connect an Oura account (one-time browser consent)
npm install
npm run get-token
# 4. Run
npm run devWant to hack on it without a ring? OURA_SANDBOX=1 npm run dev serves Oura's sandbox data, no account needed.
Connect your chat client
Your MCP endpoint is https://your-host/mcp/<MCP_PATH_SECRET>.
Settings → Apps → Advanced settings → enable Developer mode
Settings → Apps → Create: name it, paste your MCP endpoint URL, auth = No auth
In a conversation, open the + menu → Developer mode → enable the app
Set up on desktop web; the app then works in mobile conversations too.
Settings → Connectors → Add custom connector
Paste your MCP endpoint URL → Add
Claude connects from Anthropic's cloud, so the server must be publicly reachable (no localhost).
Clients that only speak stdio can use the mcp-remote bridge:
{
"mcpServers": {
"oura": {
"command": "npx",
"args": ["mcp-remote", "https://your-host/mcp/<MCP_PATH_SECRET>"]
}
}
}Configuration
Variable | Required | Purpose |
| yes | Your Oura app's client id |
| yes | Your Oura app's client secret |
| yes | Long random URL path segment ( |
| no | HTTP port, default 3000 |
| no |
|
Troubleshooting
403 from every tool — no active Oura subscription on the connected account. The API requires one.
401 / "token expired, needs a reconnect" — the stored refresh token was lost or invalidated (Oura rotates it on every refresh; never run two copies of the server against the same
data/tokens.json). Re-runget-token.404 when connecting — the path secret in the URL doesn't match
MCP_PATH_SECRET. Copy the full endpoint URL again.ChatGPT: "Error creating connector" / timeouts — your host is asleep. ChatGPT aborts on cold starts (~60 s budget); use an always-on host.
resilience/vo2_maxcome back empty — Oura computes these after ~2 weeks of wear / a fitness test; the tools work, the account has no data yet.
Security & privacy
OAuth tokens never leave your server; the MCP client only sees tool results.
Read-only scopes; the Oura API has no write endpoints for health data, and neither does this server.
Your email is never returned by any tool.
The optional usage log records tool names and timings only, never health values.
Prompt injection: treat health conversations as sensitive. If a chat mixes this connector with untrusted content (web browsing, pasted documents), a malicious page can try to steer the model into calling tools and echoing your data into a reply it controls. The blast radius here is bounded — read-only tools, your own data — but the cleanest habit is simple: ask health questions in chats that aren't also browsing the web.
Status & roadmap
Self-hosted and single-user by design: your data flows directly between your server and Oura, which is also what Oura's API terms expect from personal integrations. It runs my household's ring today.
Coming next: a one-click Claude Desktop extension (.mcpb) and a free-tier Cloudflare Workers deploy button — same server, no VM needed. Open an issue if you want one of these sooner.
License
Available Tools
10 toolsoura_get_activityActivity: steps and caloriesARead-only
Daily activity: score (0-100), steps, active and total calories. response_format 'detailed' adds minutes by intensity (high/medium/low), sedentary and resting minutes, walking distance. Use for "how many steps", "how active was I", "did I move enough". Defaults to the last 7 days.
Inputs: end_date, start_date, response_format.
oura_get_heartrateHeart rate (hourly)ARead-only
Heart rate aggregated per hour (avg/min/max bpm and sample count) across day and night. Use for "what was my pulse today/this afternoon". For sleep-time heart rate prefer oura_get_sleep_detail. Range is capped at 3 days; defaults to the last 24 hours.
Inputs: end_datetime, start_datetime.
oura_get_profileProfile and ring statusARead-only
User profile (age, biological sex, height in meters, weight in kg) plus ring info: model, size, firmware and current battery level. Use for "how charged is my ring", "what does Oura know about me". Email is never returned.
Inputs: no named parameters.
oura_get_readinessReadiness scoresARead-only
Daily readiness scores (0-100) showing how recovered the body is, with contributors (HRV balance, resting heart rate, sleep balance, body temperature) and temperature deviation in °C. Use for "how recovered am I", "should I train today", "is my temperature elevated". Defaults to the last 7 days.
Inputs: end_date, start_date.
oura_get_sleepSleep scoresARead-only
Daily sleep scores (0-100) with contributor scores (deep sleep, REM, latency, timing, etc.). Use for "how did I sleep" questions. For bedtimes, sleep stages in minutes, or night heart rate use oura_get_sleep_detail instead. Defaults to the last 7 days.
Inputs: end_date, start_date.
oura_get_sleep_detailSleep details per nightARead-only
Per-night sleep sessions: bed and wake times, sleep stages in minutes (deep/REM/light/awake), latency, efficiency, night heart rate, HRV and breathing rate. Also returns bedtime recommendations when Oura has them. Use for "when did I fall asleep", "how much deep sleep", "what was my pulse at night". Defaults to the last 7 days.
Inputs: end_date, start_date, response_format.
oura_get_stressDaily stressARead-only
Daily stress summary: minutes of high stress, minutes of high recovery, and a day verdict (e.g. 'restored', 'normal', 'stressful'). Use for "how stressed was I", "did I recover today". Defaults to the last 7 days.
Inputs: end_date, start_date.
oura_get_tagsUser tagsARead-only
Tags the user logged in the Oura app: caffeine, alcohol, sickness, medication, custom notes, etc. Useful context when explaining why sleep or readiness changed. Read-only: tags can only be created in the Oura app. Defaults to the last 7 days.
Inputs: end_date, start_date.
oura_get_vitalsHealth vitalsARead-only
Slow-moving health metrics in one call: blood oxygen (SpO2 average % and breathing disturbance index), resilience level (how well the body handles stress long-term), cardiovascular age, and VO2 max. Use for "what is my SpO2 / vascular age / VO2 max / resilience". Sections the ring does not measure come back empty. Defaults to the last 7 days.
Inputs: end_date, start_date.
oura_get_workoutsWorkouts and sessionsARead-only
Workouts (activity type, intensity, calories, distance, start/end times) plus mind-body sessions (meditation, breathing, relaxation). Use for "how was my run", "did I work out", "did I meditate". Defaults to the last 7 days.
Inputs: end_date, start_date.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 10 tools
Each tool targets a distinct health metric (activity, heartrate, profile, readiness, sleep, sleep detail, stress, tags, vitals, workouts) with clear usage instructions, eliminating ambiguity.
All tools follow the consistent pattern 'oura_get_<noun>', using lowercase with underscores, making them predictable and easy to remember.
With 10 tools covering the main Oura features, the count is well-scoped for a health data API, not overwhelming nor insufficient.
The set covers all major Oura data types (activity, sleep, readiness, heartrate, stress, vitals, tags, workouts, profile), leaving no obvious gaps for typical health queries.
Maintenance
Related MCP Connectors
WHOOP recovery, strain, sleep and workouts in Claude via official WHOOP OAuth. Free, open source.
Connect your Oura Ring account securely in minutes. Enable authorized access to your sleep, activi…
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
Connect your wearables, rings and training apps, then ask your AI about your own health data.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceIntegrates Oura Ring health data with Claude Desktop, providing resources, tools, and advanced analytics for sleep, activity, readiness, and health trends.1-
- AlicenseBqualityDmaintenanceConnects your Oura Ring to AI assistants like Claude, providing human-readable insights about sleep, readiness, activity, and health metrics with smart analysis.27148 npm35MIT
- AlicenseAqualityBmaintenanceEnables users to access and query Oura ring health data, including sleep periods, readiness, activity, workouts, heart rate, stress, SpO2, resilience, and more, through Claude.ai or Claude Code using the Oura API v2 with OAuth 2.1 login.1927 npmMIT
- AlicenseAqualityCmaintenanceEnables an AI assistant to read your own Oura Ring data—sleep, readiness, activity, heart rate, SpO2, stress, workouts, and sessions—so you can ask natural-language questions and get summaries. It fetches data on demand from the Oura API v2, is read-only, and does not store or share data.6MIT