ouraring-mcp
Read-only access to your own Oura Ring data through MCP for natural-language queries and summaries.
Check whether Oura credentials are configured and list all readable collections/scopes.
Fetch your personal profile (age, weight, height, email).
Get daily summaries for sleep, readiness, activity, stress, SpO2, resilience, and cardiovascular age.
Read any supported Oura v2 collection: sleep sessions, sleep time, workouts, sessions, tags/enhanced tags, heart rate, rest mode periods, ring configuration/battery, VO2 max, and daily_* summaries.
Query by date range, fetch one document by ID, or get latest heart-rate/battery samples.
Generate a one-call recent summary over the last N days (default 7, max 90).
All tools are read-only; results return as JSON text, with caching for repeated date-range queries.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ouraring-mcp How did I sleep last night?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ouraring-mcp
MCP (Model Context Protocol) server that lets an AI assistant read your own Oura Ring data — sleep, readiness, activity, heart rate, SpO2, stress, workouts, sessions — so you can ask questions and get summaries in natural language. Personal, single-user, non-commercial use. Data is fetched on demand and not stored or shared.
Built for the Oura API v2 (api.ouraring.com), same stdio-MCP layout as
parksapi-mcp.
Tools
Tool | What it does | Oura scope(s) |
| Credential check (no network) | — |
| Every readable collection + required scope | — |
| Profile (age, weight, height, email) |
|
| Daily summaries: |
|
| Any collection: | per collection |
| Last N days (sleep + readiness + activity + stress) in one call |
|
All tools return JSON as text and are read-only. Unknown collections/types
return { isError: true } with a plain message, never a protocol error.
Date params are YYYY-MM-DD; heartrate also accepts ISO datetimes + latest.
Related MCP server: Oura Ring MCP Server
Requirements
Node 22+.
Setup
npm install
npm run buildOAuth2 (only method — Oura retired PATs Dec 2025)
Register at https://cloud.ouraring.com/oauth/applications with:
Redirect URI:
http://localhost:8080/callbackScopes:
email personal daily heartrate workout tag session spo2 ring_configuration stress heart_healthPrivacy / Terms: this repo's
PRIVACY.md/TERMS.md
Then:
npm run auth:oura # prints the authorize URL
# open the URL, approve, copy ?code= from the localhost redirect, then:
npm run auth:oura -- --code=PASTE_CODE_HEREauth:oura reads OURARING_CLIENT_ID/OURARING_CLIENT_SECRET from the
environment → local .env → ~/.hermes/.env, then prints
OURARING_ACCESS_TOKEN (short-lived) + OURARING_REFRESH_TOKEN (long-lived).
The server auto-refreshes via the refresh token when client credentials are present — no manual refresh needed.
Install in your tools
Build once (npm install && npm run build), then point any client at
dist/index.js via stdio with OURARING_REFRESH_TOKEN + OURARING_CLIENT_ID +
OURARING_CLIENT_SECRET in the environment (server auto-refreshes; access token alone expira rápido).
Replace /path/to/ouraring-mcp with your checkout below.
Claude Code
claude mcp add ouraring \
--env OURARING_REFRESH_TOKEN=... \
--env OURARING_CLIENT_ID=... \
--env OURARING_CLIENT_SECRET=... \
-- node /path/to/ouraring-mcp/dist/index.jsOr per-project .mcp.json (user scope: claude mcp add -s user ...):
{
"mcpServers": {
"ouraring": {
"command": "node",
"args": ["/path/to/ouraring-mcp/dist/index.js"],
"env": {
"OURARING_REFRESH_TOKEN": "...",
"OURARING_CLIENT_ID": "...",
"OURARING_CLIENT_SECRET": "..."
}
}
}
}Codex CLI (~/.codex/config.toml)
[mcp_servers.ouraring]
command = "node"
args = ["/path/to/ouraring-mcp/dist/index.js"]
[mcp_servers.ouraring.env]
OURARING_REFRESH_TOKEN = "..."
OURARING_CLIENT_ID = "..."
OURARING_CLIENT_SECRET = "..."OpenCode
opencode mcp add ouraring \
--env OURARING_REFRESH_TOKEN=... \
--env OURARING_CLIENT_ID=... \
--env OURARING_CLIENT_SECRET=... \
-- node /path/to/ouraring-mcp/dist/index.jsConfig-file equivalent (opencode.jsonc; v2 nests under mcp.servers,
older versions use flat mcp):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"servers": {
"ouraring": {
"type": "local",
"command": ["node", "/path/to/ouraring-mcp/dist/index.js"],
"environment": {
"OURARING_REFRESH_TOKEN": "...",
"OURARING_CLIENT_ID": "...",
"OURARING_CLIENT_SECRET": "..."
}
}
}
}
}Hermes (~/.hermes/config.yaml)
mcp_servers:
ouraring:
command: node
args:
- /home/hermes/github/ouraring-mcp/dist/index.js
env:
OURARING_REFRESH_TOKEN: "..."
OURARING_CLIENT_ID: "..."
OURARING_CLIENT_SECRET: "..."
enabled: trueThen restart the gateway. Verify with oura_status (no network call).
OpenClaw
openclaw mcp add ouraring \
--cwd /path/to/ouraring-mcp \
-- command node --arg /path/to/ouraring-mcp/dist/index.js
openclaw mcp doctor ouraring --probeSet the tokens via Settings → MCP (scoped config editor → environment
values), or OURARING_REFRESH_TOKEN + client credentials in the gateway environment.
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"ouraring": {
"command": "node",
"args": ["/path/to/ouraring-mcp/dist/index.js"],
"env": {
"OURARING_REFRESH_TOKEN": "...",
"OURARING_CLIENT_ID": "...",
"OURARING_CLIENT_SECRET": "..."
}
}
}
}Examples
{ "data_type": "sleep", "start_date": "2026-10-15", "end_date": "2026-10-22" }
{ "collection": "heartrate", "start_datetime": "2026-10-22T00:00:00Z", "latest": true }
{ "collection": "ring_battery_level", "start_datetime": "2026-10-21T00:00:00-04:00" }
{ "collection": "workout", "start_date": "2026-10-01", "end_date": "2026-10-22", "fields": "activity_type,calories" }
{ "collection": "VO2_Max", "start_date": "2026-09-22", "end_date": "2026-10-22" }
{ "days": 7 }Notes (checked against Oura's OpenAPI spec):
Collection names are case-insensitive, but the API path for VO₂max is case-sensitive upstream (
vO2_max) — the server maps it automatically.heartrateandring_battery_levelquery by ISO datetime +latest;ring_configurationtakes no date params; everything else takesstart_date/end_date. Single-doc fetch viadocument_idonly where the API offers it (not forenhanced_tag/heartrate/personal_info/ring_battery_level).fieldsselects response fields on most routes (notdaily_resilience,enhanced_tag,tag).Webhooks (
/v2/webhook/*) are out of scope: they need a public HTTPS URL and write operations — this server is read-only by design.
Privacy
See PRIVACY.md and TERMS.md: on-demand reads only, no sharing, single user. Revoke any time from your Oura dashboard.
Cold cache
Repeat date-range queries don't re-hit Oura: responses are cached in
./oura-cache.sqlite (node:sqlite, git-ignored — never committed) with
per-day coverage. The last 2 days always refetch (Oura keeps finalizing
them); older days are immutable — fetched once, served forever. Range queries
that end in the past and are fully covered use zero upstream calls
(cacheHit: true in the response). personal_info / ring_configuration
are cached 30 days, single-document fetches 7 days. Any SQLite error
disables the cache silently and the call goes straight to the API.
OURARING_CACHE_PATH=/tmp/oura.sqlite # default ./oura-cache.sqlite
OURARING_CACHE_ENABLED=0 # bypass cache, fail-soft
OURARING_PERSONAL_INFO_TTL_HOURS=720 # default 30d
OURARING_RING_CONFIGURATION_TTL_HOURS=720
OURARING_CACHE_TTL_HOURS=168 # default 7d for the rest(OURA_* aliases work for every knob above.)
Develop
npm test # build + vitest (offline unit, stdio protocol, opt-in live)
npm audit --audit-level=moderate # fail on moderate+ advisories (dev + prod deps)tests/live.test.ts calls the real API only when OURARING_ACCESS_TOKEN is set;
otherwise it passes with a skip note.
Every push is gated: npm run setup:hooks installs a pre-push hook that
rebuilds and runs the suite — a red test blocks the push. GitHub Actions
(.github/workflows/ci.yml) enforces the same on every push/PR, plus
npm audit (moderate+) so new advisories break the build before merge.
Dependency upgrades that fix audit findings must keep the suite green
(e.g. vitest 3 → 5); if a fix needs a breaking major, do it in its own commit
with the audit delta in the message.
Available Tools
6 toolsget_collectionARead-only
Read any Oura v2 collection: sleep sessions, workouts, guided sessions, tags, heartrate samples, sleep_time, rest_mode_period, ring_configuration, vo2_max, or daily_* summaries. One document via document_id, or a date range.
Inputs: collection (required), limit, fields, latest, +5 more.
get_dailyBRead-only
Daily summaries for sleep, readiness, activity, stress, spo2, resilience or cardiovascular_age. Best for questions like 'how did I sleep this week?'.
Inputs: data_type (required), limit, fields, end_date, +1 more.
get_personal_infoARead-only
Your Oura profile (age, weight, height, email). Scopes: personal, email.
Inputs: no named parameters.
get_recent_summaryARead-only
One-call overview of the last N days (sleep + readiness + activity + stress + spo2 daily summaries) for natural-language summaries like 'how was my week?'.
Inputs: days.
list_collectionsARead-only
List every Oura collection this server can read, with the OAuth scope each needs.
Inputs: no named parameters.
oura_statusARead-only
Check whether Oura credentials are configured (no network call).
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 6 tools
Each tool has a reasonably distinct intent, and descriptions proactively guide selection (get_daily 'best for how did I sleep this week', get_recent_summary for a one-call week overview). The only real overlap is that get_collection's daily_* option and get_daily both surface daily summaries, plus get_recent_summary is effectively a composite of those, but the convenience layering is explained well enough to choose correctly.
The surface follows a clear verb_noun pattern (list_collections, get_personal_info, get_daily, get_recent_summary, get_collection). oura_status is a minor deviation in style (server-prefixed noun_status), but it is still readable and unambiguous.
Six tools is well-scoped: a status check, a discovery helper, a profile reader, three tiers of data reads (single-day, multi-day summary, generic collection). The generic get_collection tool absorbs breadth so no per-resource tool sprawl is needed.
Read coverage is broad and essentially complete via get_collection (sleep, workouts, tags, heartrate, ring config, vo2_max, daily_*), plus profile and credentials status. The gap is that the surface is strictly read-only — no create/update operations for tags, workouts, or personal info — which limits write-oriented workflows.
Maintenance
Related MCP Connectors
Connect your wearables, rings and training apps, then ask your AI about your own health data.
Read sleep, readiness, activity, stress, heart rate and workouts from the Oura Ring.
Connect your Oura Ring account securely in minutes. Enable authorized access to your sleep, activi…
Connect your Oura Ring account and enable access to your wellness data in apps and automations. In…
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to access and analyze Oura Ring health data including sleep, readiness, activity, and stress metrics. Supports customizable queries, correlation analysis, and visualization capabilities for comprehensive health insights.-
- AlicenseNot gradedqualityDmaintenanceEnables access to Oura Ring health data including sleep patterns, activity metrics, readiness scores, heart rate, workouts, and stress measurements with AI-powered analysis and personalized recommendations.190 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to access Oura Ring health data including sleep, readiness, activity, heart rate, and workouts through OAuth2-authenticated API calls with automatic token refresh and smart caching.8 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to access your Oura Ring health data through OAuth2-authenticated API calls.8 npm9MIT