关于 Oura Ring
这款 MCP 服务让 AI 客户端以结构化摘要访问 Oura Ring 健康数据,提供每日统计与趋势,而非默认返回原始 API 数据。支持本地和托管部署。
主要功能
- 01睡眠、准备度与活动摘要
- 02HRV、心率和 SpO₂ 数据
- 03每日统计与趋势报告
- 04本地 stdio 和远程 HTTP 传输
- 05时区感知日期与 SQLite 缓存
适用场景
- 01查看指定时段的睡眠与准备度
- 02检查心率和压力变化
- 03比较活动与健康趋势
- 04在本地或网页客户端查看 Oura 摘要
MCP 相关
向 MCP 客户端提供 Oura 数据工具,以及 `oura://today`、`oura://yesterday` 和 `oura://week` 资源。支持本地 stdio 和远程 Streamable HTTP。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx my-oura-mcpOURA_CLIENT_IDClient ID of your Oura application from developer.ouraring.comOURA_CLIENT_SECRET密钥Client secret of your Oura applicationOURA_REDIRECT_URIOAuth redirect URI; must match the Oura application byte for byteOURA_API_MODEsandbox for Oura's synthetic data (no auth needed), production for your ownOURA_TZIANA timezone deciding what counts as today. Set it explicitly on servers, whose clocks run in UTCOURA_TOKEN_STORE密钥Where the OAuth flow stores tokens. Written by the server, not set by handOURA_PUBLIC_URLPublic https address, without a trailing slash. Enables OAuth 2.1 for Claude.ai and ChatGPT; leave empty for local or Bearer-token clientsOURA_OAUTH_ALLOWED_REDIRECT_ORIGINS密钥Comma-separated trusted OAuth redirect origins; defaults to Claude.ai and ChatGPTOURA_MCP_TOKEN密钥Shared secret guarding the HTTP endpoint. Required whenever the server binds to anything other than loopback; without it the server refuses to start本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
11收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| raw | boolean | 否 | |
| end_date | any | 否 | |
| days_back | any | 否 | |
| start_date | any | 否 |
详细介绍
my-oura-mcp
让 Claude、ChatGPT 和 Codex 访问你的 Oura Ring 数据:睡眠、 准备度、HRV、静息心率、活动、SpO₂、压力。
问一句“我上周睡得怎么样”,你的 MCP 客户端就会调用合适的工具并 返回摘要,而不是一大段 JSON:
{
"metric": "sleep_detail",
"period": { "start": "2026-07-23", "end": "2026-07-29", "days": 7 },
"stats": {
"total_h": { "mean": 7.1, "min": 5.9, "max": 8.4 },
"deep_h": { "mean": 1.3, "min": 0.9, "max": 1.8 },
"avg_hrv": { "mean": 42, "min": 31, "max": 55, "trend_per_week": 1.8 },
"efficiency": { "mean": 88, "min": 82, "max": 93 }
}
}
刚接触 MCP? Model Context Protocol 让 AI 客户端访问外部数据。 安装此服务并连接一次,然后用自然语言询问睡眠情况。 无需编写代码。
在 Claude Code 和 Codex 中可本地使用;部署到自己的服务后,也可在 claude.ai 和 ChatGPT 中远程使用。
Читать по-русски: README.ru.md
为什么还要做一个
- 默认精简。 工具返回每天的数据值和趋势统计,而非原始 API 负载。只需设置
raw=True,即可获取原始响应。 一个月的心率数据可缩减 10 倍以上。 - 一套代码,两种传输方式。 本地使用
stdio,远程使用streamable-http。只需切换一个标志,无需重写。 - 时区处理准确。 Oura 的某些端点会按内部 UTC 时间戳筛选数据,却返回本地
day字段;心率时间戳则以 UTC 返回。这两种情况都会悄悄丢失或错置 UTC 以外的数据。本服务已处理这些问题——请参阅时区处理。 - 应对不稳定的网络。 支持
next_token分页,通过指数退避重试断开的连接,并将 HTTP 状态码转换为说明修复方法的消息。 - 授权前先试用。 Oura 沙盒无需任何凭据即可使用。
快速开始
需要 uv。此步骤无需 Oura 令牌。
git clone https://github.com/AntVsl/oura_mcp && cd oura_mcp
cp .env.example .env
uv sync
检查数据是否正常流动(访问 Oura 沙盒,无需授权):
uv run python -m my_oura_mcp.smoke
在本地连接——服务会打印已填入绝对路径的命令,且不会自行写入任何内容:
uv run my-oura-mcp install
然后向客户端询问 Oura 摘要。get_status 工具会报告服务所处的模式。
工具
| 工具 | 返回内容 | 默认范围 |
|---|---|---|
get_daily_summary | 睡眠、准备度和活动评分 | 7 天 |
get_sleep | 睡眠阶段、效率、HRV、静息 HR、呼吸、体温 | 7 天 |
get_sleep_score | 仅每日睡眠评分——比 get_sleep 更轻量 | 7 天 |
get_readiness | 准备度评分、HRV 平衡、体温偏差 | 7 天 |
get_activity | 活动评分、步数、卡路里 | 7 天 |
get_heartrate | 按分钟记录的心率汇总为每日统计 | 3 天 |
get_spo2 | 睡眠期间的血氧、呼吸紊乱指数 | 7 天 |
get_stress | 负荷时间和恢复时间 | 7 天 |
get_heart_health | 心血管年龄、VO₂max | 30 天 |
get_tags | 你在 Oura 应用中输入的标签 | 30 天 |
get_status | 服务模式和授权状态 | — |
每个数据工具都可使用 days_back,或指定 start_date/end_date 日期范围(YYYY-MM-DD),还可通过 raw 获取 Oura 未经处理的响应。
使用你自己的数据
沙盒会返回合成数据。要使用你自己的数据,需要一个 Oura 应用和一次性授权——无需通过审核,新建的应用即可立即使用。
| 操作 | |
|---|---|
| 1 | 在 developer.ouraring.com 注册应用 |
| 2 | 将 OURA_CLIENT_ID 和 OURA_CLIENT_SECRET 填入 .env |
| 3 | 运行 uv run my-oura-mcp auth——打开浏览器,并以 600 模式存储令牌 |
| 4 | 在 .env 中设置 OURA_API_MODE=production |
注册时:重定向 URI 必须是 http://localhost:8765/callback,逐字节匹配。权限范围为 daily、heartrate、tag、spo2、stress、heart_health。其他内容可任意填写。
之后令牌会自动刷新。使用 my-oura-mcp auth --status 检查,使用 auth --logout 删除令牌。
个人访问令牌已无法使用:Oura 于 2025 年 12 月停止发放此类令牌。
刷新令牌只能使用一次。 每次刷新都会使旧令牌失效,因此两个实例共享一个令牌存储时会互相导致令牌失效。如果出现提示令牌只能使用一次的
400错误,请重新运行auth,并确保只运行一个实例。
配置
所有配置都放在 .env 中(参见 .env.example)。机密信息绝不会提交到 git。
| 变量 | 用途 |
|---|---|
OURA_CLIENT_ID / OURA_CLIENT_SECRET | Oura 应用凭据 |
OURA_REDIRECT_URI | 必须与应用中的设置完全一致 |
OURA_API_MODE | sandbox(合成数据)或 production |
OURA_TZ | 决定“今天”含义的时区。在服务器上必须显式设置 |
OURA_MCP_TOKEN | 用于保护 HTTP 端点的共享密钥;也是授权页面的密码 |
OURA_PUBLIC_URL | 公共 https 地址。设置后,即可为 Claude.ai 和 ChatGPT 启用 OAuth |
OURA_OAUTH_ALLOWED_REDIRECT_ORIGINS | 以逗号分隔的 OAuth 客户端来源;默认包括 Claude.ai 和 ChatGPT |
OURA_TOKEN_STORE | OAuth 流程写入令牌的位置。无需手动设置 |
OURA_CACHE_DB | SQLite 缓存文件。设为空值可禁用缓存 |
运行
同一份代码,支持两种传输方式:在本机与客户端一起运行时使用 stdio;在服务器上运行时使用 HTTP,让网页客户端和手机都能访问。
本地运行
| 客户端 | 命令 |
|---|---|
| Claude Code | claude mcp add --scope user oura -- uv --directory PATH run my-oura-mcp |
| Codex | codex mcp add oura -- uv --directory PATH run my-oura-mcp |
运行 uv run my-oura-mcp install 会打印这些命令,并自动填入绝对路径。--scope user 使服务可从任意目录访问;不加此参数时,只能从运行命令的目录访问。使用 claude mcp list / codex mcp list 验证。
不会向外部暴露任何内容,也不会使用网络。若要调试传输本身,可运行 uv run my-oura-mcp --transport http --port 8000——在环回地址上运行无需密钥。
在服务器上
这样一来,任何设备都能访问服务器,包括 Claude.ai 和 ChatGPT。docs/DEPLOY.md(俄语)中提供了分步说明:如何放行流量、如何迁移 Oura 授权,以及如何连接网页客户端。
| 客户端 | 连接方式 |
|---|---|
| Claude.ai、ChatGPT | OAuth。无需输入客户端 ID 或密钥——客户端会自行注册,授权页面会要求提供 OURA_MCP_TOKEN |
| Claude Code | claude mcp add --scope user --transport http oura URL --header "Authorization: Bearer TOKEN" |
| Codex | codex mcp add oura --url URL --bearer-token-env-var OURA_MCP_TOKEN |
OURA_PUBLIC_URL 会启用 OAuth:服务器将成为自己的授权服务器,并支持动态客户端注册,但仅限 https://claude.ai 和 https://chatgpt.com。其他客户端需要将其确切来源添加到 OURA_OAUTH_ALLOWED_REDIRECT_ORIGINS;在要求提供密钥之前,授权页面会显示客户端名称及其返回来源。
有两种暴露服务器的方式,选择并非无关紧要。Caddy 更简单,但其证书会进入证书透明度日志——这是一份公开日志,会暴露该地址托管了服务。Cloudflare Tunnel 则完全无需开放入站端口。如果同一台主机上运行着 VPN,就只能使用隧道。
如何选择
| stdio,本地 | HTTP,服务器上 | |
|---|---|---|
| 在此机器上使用 Claude Code 和 Codex | 是 | 是 |
| 其他设备 | 否 | 是 |
| Claude.ai、ChatGPT、手机 | 否 | 是,通过 OAuth |
| 需要域名和主机 | 否 | 是 |
| 数据会离开此机器 | 否 | 是,传到你的服务器 |
确保恰好只有一个运行中的实例:Oura 的刷新令牌只能使用一次,两个共享令牌存储的服务器会相互取消授权。
时区处理
Oura 的日期语义导致了三个独立的问题,它们都会悄无声息地丢失数据,而不是报错。如果你要自行基于此 API 构建应用,值得了解:
sleep和daily_activity按内部 UTC 时间戳筛选,而不是按 Oura 返回的day字段筛选。在 UTC+3 时,午夜后开始的一晚会落在前一个 UTC 日期:查询28..28会返回空结果,尽管day=28的记录明明存在。服务器会扩大时间范围,然后再按day筛选。已通过遍历所有端点验证;其他六个端点表现正常。heartrate返回 UTC 时间戳。 按该字符串的前十个字符分组,会将本地日期拆成两天,把本地时间 00:00–03:00 的数据推到前一天——而这恰好是你关心的静息心率。分组使用OURA_TZ。- Oura 每天会返回多条睡眠记录——包括夜间睡眠和午睡。随便选一条,可能会让 12 分钟的午睡取代一整晚睡眠。标记为
long_sleep的记录优先,否则选择时长最长的记录;午睡会单独报告为naps_h,因此其 HRV 不会与夜间睡眠的 HRV 求平均。
安全
.env、令牌存储和缓存均已列入.gitignore。提交前请检查:git status --porcelain。- 令牌存储和 SQLite 缓存文件仅授予所有者权限(
600)。 - HTTP 端点使用
OURA_MCP_TOKEN进行保护,并通过恒定时间比较进行验证。访问控制模型刻意保持简单:一个密钥、一个所有者,不区分用户。 - 如果在非环回地址上启动且未提供密钥,服务器会拒绝启动,而不会悄悄将健康数据暴露到开放互联网。试试看:
uv run my-oura-mcp --transport http --host 0.0.0.0。 /healthz特意保持开放——反向代理需要访问它,而且它只会返回ok。- Caddy 会从日志中移除
Authorization标头。
缓存
较早日期的数据会存入 SQLite。最近两个已完成日期的数据会在每次请求时重新检查,因为延迟同步可能会更新这些数据;更早的历史数据则直接从缓存读取,不会发起网络调用。
uv run my-oura-mcp cache --status # what is cached
uv run my-oura-mcp cache --clear # forget it
有三点值得注意。今天的数据从不缓存——Oura 仍在写入数据。空数据日也不会缓存:空数据日可能意味着“没有佩戴戒指”,也可能意味着“尚未同步”;第二种情况会在几小时内自行解决,而缓存的空数据则会一直保留。模式也是键的一部分,因此沙盒数据不会出现在生产环境中。
每分钟心率数据会绕过缓存:这些行没有 day 字段。
MCP 资源
支持资源的客户端可以读取 oura://today、oura://yesterday 和 oura://week。它们提供与工具相同的睡眠/准备度/活动摘要,无需手动选择参数。
附带使用配方的技能
skills/oura 提供了一个面向 Claude 的技能——不是更多工具,而是基于这些工具构建的工作流:睡眠是否真的在改善、今天是否适合承受负荷、状态不佳时身体发生了什么、日常习惯的改变是否有效。每个工作流都包含一系列调用和一种分析答案的方法,这是任何单个工具都无法实现的。
将其复制到客户端的技能目录即可安装:
cp -r skills/oura ~/.claude/skills/
测试会将配方与代码进行核对:如果某个字段名没有被任何工具返回,uv run pytest 就会报错,而不是悄无声息地让模型无所适从。
将这些仓库技能复制到 Codex 的技能目录后,Codex 也可以加载它们:
mkdir -p ~/.codex/skills
cp -R skills/oura skills/oura-mcp-maintenance ~/.codex/skills/
oura 通过 MCP 服务解读数据。oura-mcp-maintenance 则指导如何安全地修改此仓库及其 Claude/ChatGPT/Codex 集成。
遇到问题时
Claude 提示没有 Oura 工具。 服务未能连接。运行 claude mcp list 查看其状态。常见原因是使用了相对路径,但这里需要完整路径——uv run my-oura-mcp install 会打印正确的命令。
“授权未通过——没有令牌”。 服务处于 production 模式,但尚未登录 Oura。运行 uv run my-oura-mcp auth;运行 uv run my-oura-mcp auth --status 查看令牌状态。
VPS 上的服务返回 401。 OURA_MCP_TOKEN 不匹配。标头值会原样发送,因此 Bearer 一词和空格都属于值的一部分:应为 Bearer abc123,而不是 abc123。
返回的数据对应错误的日期。 未设置 OURA_TZ。服务的系统时钟几乎总是 UTC,因此“今天”会比你当地时间早或晚几个小时,夜间睡眠数据也会落在前一天。请明确设置,例如 OURA_TZ=Europe/Moscow。
“刷新令牌已被拒绝”。 Oura 的刷新令牌只能使用一次;如果第二个实例用掉了它,就会发生这种情况。确保只运行一个实例:VPS 启动后,也将本地 Claude Code 指向它。运行 my-oura-mcp auth 恢复。
对 api.ouraring.com 的请求因 SSL_ERROR_SYSCALL 或超时而失败。 通常问题不在服务端:客户端会采用退避策略重试四次。如果仍然无效,通常可以使用 VPN 解决。
claude.ai 无法连接到你的服务。 检查是否设置了 OURA_PUBLIC_URL,并确认它与连接器 URL 逐字符匹配,包括 https://,且末尾没有斜杠。启动横幅会显示 OAuth 是否已启动。除此之外,请参阅 docs/DEPLOY.md。
你在授权页面上点击“允许”后没有任何反应。 检查服务日志:如果 POST /oauth/consent 返回 303,之后却没有 POST /token,说明浏览器阻止了跳回 claude.ai 的跳转。这是 Content-Security-Policy 过于严格的表现——curl 无法复现,因为它完全不会执行 CSP 检查。
“请求已过期”/request expired。 授权请求存储在进程内存中,因此重启服务会使所有已打开的授权页面失效。问题不在密钥——返回 claude.ai 并重新开始连接即可。
开发
uv run pytest
测试不会访问网络;Oura 的响应由 respx 模拟。
工具测试通过 mcp.call_tool() 运行,而不是直接调用函数——有些 bug 只有在真实协议层才会出现,因为 MCP 客户端会将声明的默认值作为显式参数传递。
对于 Codex 和其他编码 Agent,仓库说明以及任务/审查结构见 AGENTS.md 和 docs/agents。
x86_64 macOS: cryptography 49+ 不为此平台提供 wheel,并会尝试从 Rust 源码构建。pyproject.toml 专门为此固定使用 48.0.0;Linux 和原生 arm64 不受影响。Apple Silicon 用户也可能遇到此问题:如果 Homebrew 安装在 /usr/local 而非 /opt/homebrew,就会触发——使用 file $(which python3) 检查。
网络不稳定: 如果对 api.ouraring.com 的请求因 SSL_ERROR_SYSCALL 失败或超时,问题通常不在服务端。客户端会通过退避机制尝试四次;若仍不行,请尝试使用 VPN。
请参阅 docs/ROADMAP.md,了解计划内容以及有意推迟的事项。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。