mcpField
W
whoop-mcp

whoop-mcp

本地服务
github.com/AshwanthramKL健康医疗026 周前更新

关于 whoop-mcp

whoop-mcp 是本地只读 MCP 服务,向 MCP 客户端提供 WHOOP v2 健身数据。它通过直接 OAuth 授权并使用本地 SQLite 缓存,可查询、同步和导出记录。

主要功能

  1. 01读取 WHOOP 个人资料和健身记录
  2. 02将数据缓存在本地 SQLite
  3. 03按需或增量同步记录
  4. 04通过 MCP 资源浏览缓存数据
  5. 05以 CSV、JSONL 或 Parquet 导出记录

适用场景

  1. 01查看每日睡眠、恢复和训练数据
  2. 02无需调用 API 查询缓存记录
  3. 03跟踪 WHOOP 记录的更新
  4. 04导出训练数据供外部分析

MCP 相关

向 MCP 客户端提供只读 WHOOP 数据工具,以及缓存记录的 JSON 资源。它直接向 WHOOP 进行身份验证,并将获取的数据保存在本地 SQLite 缓存中。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"ashwanthramkl-whoop": {
"command": "uvx",
"args": [
"whoop-mcp"
],
"env": {
"WHOOP_CLIENT_ID": "<WHOOP_CLIENT_ID>",
"WHOOP_CLIENT_SECRET": "<WHOOP_CLIENT_SECRET>",
"WHOOP_REDIRECT_URI": "<WHOOP_REDIRECT_URI>",
"WHOOP_LOG_LEVEL": "<WHOOP_LOG_LEVEL>",
"WHOOP_LOG_FILE": "<WHOOP_LOG_FILE>",
"WHOOP_LOG_JSON": "<WHOOP_LOG_JSON>"
}
}
}
}
启动命令uvx whoop-mcp
需要配置的环境变量
WHOOP_CLIENT_IDClient ID from your WHOOP developer app (https://developer-dashboard.whoop.com/apps/create).
WHOOP_CLIENT_SECRET密钥Client secret from your WHOOP developer app. Used for OAuth token refresh.
WHOOP_REDIRECT_URIOAuth redirect URI. Defaults to http://localhost:8000/callback — only change if you registered a different URI.
WHOOP_LOG_LEVELLog level (DEBUG / INFO / WARNING / ERROR). Default INFO.
WHOOP_LOG_FILEPath to the rotating log file. Set to empty string to disable file logging. Default ~/.whoop-mcp-server/logs/whoop-mcp.log.
WHOOP_LOG_JSONStructured JSON logs (true) vs human-readable (false). Default true.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypiwhoop-mcp0.8.5

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

WHOOP MCP Server

CI PyPI Python 3.10+ License: MIT MCP Tests

一个本地模型上下文协议(MCP)服务,为大模型提供对 WHOOP 健身数据的只读访问。身份验证通过你自己的 WHOOP 开发者应用直接使用 OAuth 完成,过程中不经过任何第三方代理。所有记录都会镜像到本地 SQLite 缓存 ~/.whoop-mcp-server/whoop.db 中,除服务自身向 WHOOP v2 API 发起的已认证调用外,数据绝不会离开你的设备。

当前版本:0.8.5 — 参见 CHANGELOG.md。

尚未达到 1.0 版本。 API 接口(工具名称、响应结构、错误代码)正在趋于稳定,但尚未冻结。在实际使用验证期间,0.x 次版本更新可能包含破坏性变更。补丁版本更新(0.8.x)仅修复错误。待接口在实际使用中稳定运行 2 周以上后,将发布 1.0.0。如果你基于此项目构建,请在 CI 中固定次版本。

只想试用一下? 复制 docs/AGENT_INSTALL_PROMPT.md 中的提示词,将其粘贴到 Claude Code / Claude Desktop / Cursor / Windsurf,Agent 就会端到端完成安装。

基于此代码库构建? 请从 AGENTS.md 和 docs/ARCHITECTURE.md 开始阅读——它们介绍了核心约定和一页式系统概览。

目录

项目简介

WHOOP MCP Server 是一个通过 stdio 使用 MCP 通信的小型 Python 进程。它向任何支持 MCP 的客户端(主要是 Claude Desktop 和 Claude Code)提供 WHOOP v2 数据(个人资料、身体测量、周期、恢复、睡眠、训练)。该服务为只读服务。它使用你自行注册的 OAuth 应用向 WHOOP 进行身份验证,因此令牌不会经过任何第三方服务。获取的 WHOOP 记录会写入本地 SQLite 缓存(权限模式为 0o600),后续读取无需联网且不产生额外请求;缓存文件也绝不会离开你的设备。

安装(通过 uvx 一行命令完成)

# 1. Create a WHOOP developer app (one-time, free, self-serve):
#    https://developer-dashboard.whoop.com/apps/create
#    Redirect URI:  http://localhost:8000/callback
#    Scopes:        read:profile read:body_measurement read:recovery
#                   read:cycles read:sleep read:workout offline

# 2. One-shot OAuth — opens browser, catches callback, saves encrypted tokens.
WHOOP_CLIENT_ID="<your client id>" \
WHOOP_CLIENT_SECRET="<your client secret>" \
  uvx --from whoop-mcp whoop-mcp-oauth

# 3. Register with Claude Code. The --env flags are required so the
#    server can refresh tokens when the 1-hour access token expires.
claude mcp add whoop --scope user \
  --env WHOOP_CLIENT_ID="$WHOOP_CLIENT_ID" \
  --env WHOOP_CLIENT_SECRET="$WHOOP_CLIENT_SECRET" \
  -- uvx --from whoop-mcp whoop-mcp

无需克隆、无需创建 venv、无需使用绝对路径。还没有 uv?安装一次即可: curl -LsSf https://astral.sh/uv/install.sh | sh(或运行 brew install uv)。

使用 Agent 安装

将 docs/AGENT_INSTALL_PROMPT.md 中的提示词粘贴到任何支持 MCP 的 Agent(Claude Code、Claude Desktop、Cursor、Windsurf、Zed、Aider)。Agent 会替你运行安装流程。

从源代码安装(用于开发)

git clone https://github.com/AshwanthramKL/whoop-mcp.git
cd whoop-mcp
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt
.venv/bin/pytest -q   # 183 tests, ~6s, all respx-mocked

然后使用 -- /abs/path/to/whoop-mcp/.venv/bin/python /abs/path/to/whoop-mcp/src/whoop_mcp_server.py 注册。

对于 Claude Desktop,将等效条目添加到 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS), 将 command 指向虚拟环境中的 Python,并将 args 指向 src/whoop_mcp_server.py。 如果想在干净环境中端到端快速检查安装流程(不包括浏览器 OAuth 流程), 请运行 ./scripts/fresh_install_check.sh。

快速开始

注册服务后,试试以下提示词:

  1. 同步缓存。“同步我过去 30 天的 WHOOP 数据。” Claude 会调用 sync_whoop() 并报告各资源的数量。
  2. 查看某一天。“给我昨天的 WHOOP 每日摘要。” Claude 会调用 get_whoop_daily_summary(date="YYYY-MM-DD"),并显示 合并后的周期 + 恢复 + 主要睡眠 + 训练记录。
  3. 导出。“将我缓存的所有训练导出到 ~/whoop-workouts.csv。” Claude 会调用 export_whoop(kind="workouts", format="csv", path="...")。

分析技能:whoop-insights

随仓库附带:skills/whoop-insights。

安装(一条命令):

whoop-mcp-install-skills            # writes to ~/.claude/skills/

该命令会从此仓库的 main 分支获取最新技能,并将其放到 Claude Code(以及 Cursor / Windsurf / Zed)会自动发现用户级技能的位置。重启 MCP 客户端会话,然后询问:

“我最近状态如何?运行 whoop-insights 技能。” “生成我的每周 WHOOP 报告。” “我是不是训练过度了?检查过去 30 天的数据。”

该技能会从缓存中提取 30 天的数据,计算个人基准值 (HRV、恢复、睡眠、负荷),基于证据标记异常,进行两项 相关性分析(睡眠→次日恢复、负荷→次日恢复),并可选择生成包含 Chart.js 可视化图表的独立 HTML 仪表板。每项结论都会引用具体日期和具体数值 ——该技能被要求绝不捏造信息。

对于直接在仓库中开发的人员,如果要迭代改进技能本身: whoop-mcp-install-skills --source ./skills 会从本地 工作树而非 GitHub 安装。

工具目录

共 17 个工具。所有列表工具都接受 ISO-8601 格式的 start / end,并自动分页。 每个读取工具都接受 fresh: bool = False——传入 True 可绕过 缓存并调用 WHOOP API,将响应写入缓存,并返回实时响应。错误会以结构化的 {"error": {...}} 封装形式返回; 工具不会抛出异常。

工具功能关键参数
get_whoop_auth_status报告 OAuth 令牌状态。如果其他工具返回 AUTH_FAILED,请先调用此工具。—
get_whoop_profile已验证身份的 WHOOP 用户资料(姓名、电子邮件)。fresh
get_whoop_body_measurement最新身体测量数据:身高、体重、最大心率。fresh
list_whoop_cycles指定时间范围内的生理周期。start、end、limit、fresh
get_whoop_cycle按整数 ID 获取一个周期。cycle_id、fresh
get_whoop_cycle_sleep获取与指定周期关联的睡眠记录。cycle_id、fresh
get_whoop_cycle_recovery获取与指定周期关联的恢复记录。cycle_id、fresh
list_whoop_recoveries指定时间范围内的恢复数据(HRV / RHR / 恢复评分)。start、end、limit、fresh
list_whoop_sleeps指定时间范围内的睡眠活动,包括小睡。start、end、limit、fresh
get_whoop_sleep按 UUID 获取一项睡眠活动。sleep_id、fresh
list_whoop_workouts训练记录及各区间时长(秒)。start、end、limit、fresh
get_whoop_workout按 UUID 获取一项训练记录。workout_id、fresh
get_whoop_daily_summary获取某个 UTC 日期的周期、恢复、主要睡眠和训练汇总。date
sync_whoop从 WHOOP API 刷新缓存。默认采用幂等增量同步。full、since、resources
get_whoop_events按时间顺序显示缓存资源的“最新动态”。since、until、resources、limit
export_whoop将缓存记录导出为 CSV / JSONL / Parquet。kind、format、path、start、end、overwrite
health_check综合状态(身份验证、API、缓存、架构)。不会抛出异常。live

错误代码:AUTH_FAILED、RATE_LIMITED、NOT_FOUND、UPSTREAM_ERROR、 VALIDATION_ERROR、CACHE_ERROR、CACHE_EMPTY、FILE_EXISTS、 EXPORT_ERROR、SYNC_ERROR。

MCP 资源

缓存也会作为只读 MCP 资源公开,因此客户端无需调用工具即可浏览日期范围内的数据。

URI内容
whoop://db/cycles/{start}/{end}[start, end) 内的缓存周期(日期格式为 YYYY-MM-DD)。
whoop://db/recoveries/{start}/{end}缓存的恢复数据。
whoop://db/sleeps/{start}/{end}缓存的睡眠数据(包括小睡)。
whoop://db/workouts/{start}/{end}缓存的训练记录。
whoop://db/profile最新的用户资料快照。
whoop://db/body_measurement最新的 body_measurement 快照。
whoop://db/sync_runs/{limit}最近的同步审计记录。
whoop://db/events/{since}从 since 开始的事件流,until = 当前时间。
whoop://db/events/{since}/{until}指定时间范围内的事件流。

所有资源均返回 application/json。无效输入会返回与工具相同的 {"error": {"code","message"}} 封装形式。

数据模型

响应经过扁平化处理:提取 WHOOP 的 score 封装层,将毫秒转换为秒(*_seconds,保留 1 位小数),将千焦转换为卡路里 (calories,四舍五入为整数),将心率字段重命名为 avg_hr_bpm / max_hr_bpm,并将睡眠阶段命名为 deep_sleep_seconds、 rem_sleep_seconds、light_sleep_seconds、awake_seconds、 in_bed_seconds。移除原始 user_id、v1_id 和各记录的 created_at。

score_state 约定。 WHOOP 评分并非总是已计算完成。当 score_state != "SCORED"(例如 PENDING_SCORE、UNSCORABLE)时,所有 派生评分字段均为 null,并保留顶层 score_state,以便调用方了解原因。

每种资源提供一条扁平化记录:

// Cycle
{
  "id": 123456,
  "start": "2026-04-20T04:00:00.000Z",
  "end": "2026-04-21T04:00:00.000Z",
  "timezone_offset": "+00:00",
  "score_state": "SCORED",
  "strain": 12.4,
  "avg_hr_bpm": 62,
  "max_hr_bpm": 168,
  "calories": 2810
}
// Recovery
{
  "cycle_id": 123456,
  "sleep_id": "bb68db7b-...",
  "score_state": "SCORED",
  "recovery_score": 74,
  "resting_heart_rate_bpm": 48,
  "hrv_rmssd_ms": 87.3,
  "spo2_pct": 97.4,
  "skin_temp_c": 33.1,
  "user_calibrating": false
}
// Sleep
{
  "id": "bb68db7b-...",
  "cycle_id": 123456,
  "start": "2026-04-20T03:10:00.000Z",
  "end": "2026-04-20T10:42:00.000Z",
  "nap": false,
  "score_state": "SCORED",
  "sleep_performance_pct": 88.0,
  "in_bed_seconds": 27120.0,
  "light_sleep_seconds": 12540.0,
  "rem_sleep_seconds": 5280.0,
  "deep_sleep_seconds": 6840.0,
  "awake_seconds": 1080.0
}
// Workout
{
  "id": "a91f...",
  "start": "2026-04-20T17:00:00.000Z",
  "end": "2026-04-20T17:48:00.000Z",
  "sport_name": "Running",
  "score_state": "SCORED",
  "strain": 9.3,
  "avg_hr_bpm": 142,
  "max_hr_bpm": 176,
  "calories": 511,
  "distance_meter": 8030.0,
  "zone_durations_seconds": {
    "zone_zero": 0.0, "zone_one": 120.0, "zone_two": 900.0,
    "zone_three": 1440.0, "zone_four": 420.0, "zone_five": 0.0
  }
}

同步模型

  • 缓存优先读取。 每个列表/获取工具默认从 SQLite 读取。 如果时间窗口为空,则会透明地触发定向同步并重新读取。
  • fresh=True 会绕过缓存,调用 WHOOP API,将结果写入缓存,并返回实时响应。
  • 增量同步 使用每种资源的 MAX(updated_at) 作为游标。 全新数据库会回退到最近 90 天。sync_whoop(full=True) 会为每种资源拉取从 2010-01-01 开始的数据(全新缓存时执行一次即可)。
  • 幂等。 如果上游没有新数据,重新运行 sync_whoop 不会产生任何操作。结合快照哈希去重(见下文),事件流将保持安静。
  • 快照哈希去重。 profile 和 body_measurement 是单例快照。写入前,服务会比较规范化原始负载的 SHA-256 值与已存储的数据块。字节完全相同的负载不会推进 updated_at,因此不会生成无关事件。

事件流

get_whoop_events(since, until=None, resources=None, limit=500) 是一个涵盖所有缓存资源的时间顺序事件流——纯缓存读取,不调用 API。时间窗口的两端均为开区间: updated_at > since AND updated_at < until。严格的 since 边界意味着你可以将返回的游标作为下一个 since 传入,而不会再次看到同一行。

每个事件都包含一条扁平记录:

{"resource": "sleeps",
 "id": "bb68db7b-...",
 "updated_at": "2026-04-20T14:12:33.123Z",
 "record": { "...flat sleep..." }}

响应:

{"status": "success", "count": 17,
 "since": "...", "until": "...",
 "events": [...],
 "next_cursor": null | "<opaque-base64>"}

next_cursor 是对最后一个返回事件的 updated_at|resource|id 进行 Base64 编码后得到的不透明值。将其作为 since 传回即可继续获取。使用完整三元组作为带并列项处理的下界,因此在分页边界处,共享同一 updated_at 的事件不会被跳过。仍支持将普通 ISO-8601 字符串作为 since(兼容 M5)。

也可通过 MCP 资源访问——参见上方的 MCP 资源表格。

导出

export_whoop(kind, format, path, start=None, end=None, overwrite=False) 会将扁平缓存记录写入磁盘。纯数据层操作——不会调用 API。 请先运行 sync_whoop()。

  • kind:cycles | recoveries | sleeps | workouts | all。 "all" 会为每种资源写入一个文件(cycles.*、recoveries.*,……) 到指定目录。
  • format:csv(RFC 4180,按字母顺序排序的表头,嵌套值以 JSON 编码)、jsonl(每行一条记录,键已排序)或 parquet(pyarrow,snappy)。
  • overwrite:默认为 False。如果目标位置已有内容, 则返回 FILE_EXISTS。设为 True 则会直接替换。

即使时间窗口为空,也会生成文件(仅含表头的 CSV/空 JSONL/ 空 Parquet),以便下游工具获得一致的产物。

不支持的内容

明确列出,避免有人白白提交 Issue。

请求原因
claude.ai(Web 应用)我们以 stdio MCP(本地子进程)的形式提供。claude.ai 需要远程 HTTPS MCP。托管部署也会破坏我们的单用户/仅限本地威胁模型。
Claude 移动应用同样受 stdio 限制。
向 WHOOP 写入数据(记录活动、更新体重等)本项目在设计上仅支持读取。要添加写入功能,就必须使用通过逆向工程得出的端点,这些端点不属于 WHOOP 稳定的 v2 API,过于脆弱,也有违反服务条款的风险。如果需要此功能,请参阅 jd1207/whoop-mcp。
多用户/共享服务一个用户、一个 WHOOP 账户、一台机器。缓存和加密令牌存放在 ~/.whoop-mcp-server/ 下;没有租户模型。
每个 WHOOP 开发者应用超过 10 名用户在获得应用级审批前,WHOOP 开发者应用的用户上限为 10 名。每位用户都应创建自己的开发者应用——免费且可自行操作。
推送通知/webhook事件流由缓存轮询驱动。如需主动告警,可使用现有的任意调度器,通过 cron 运行 sync_whoop + get_whoop_events。
Python < 3.10代码使用 X | Y 联合类型语法。较旧版本的 Python 无法执行 pip install。
Windows 专用安装路径代码可以运行,但 OAuth 回调(localhost:8000)和路径处理尚未在 Windows 上经过实际测试。目前已测试的平台为 Ubuntu + macOS。

更新

MCP 服务不会自动更新。安装时使用的版本就是固定的版本。 如何获取新版本取决于安装方式:

安装方式更新方法
uvx --from whoop-mcp whoop-mcp运行 uvx --refresh --from whoop-mcp whoop-mcp,或运行 uv cache clean whoop-mcp 后重新调用
uvx --from whoop-mcp@latest whoop-mcp缓存下次未命中时会自动更新(无需手动操作)
pipx install whoop-mcppipx upgrade whoop-mcp
pip install whoop-mcppip install --upgrade whoop-mcp
Git 克隆 + venvgit pull && pip install -r requirements.txt

之后运行 health_check()——其中的 pypi_update_available 组件 会确认 MCP 客户端当前运行的版本,以及是否已发布 更新版本。

破坏性变更政策:项目处于 0.x 阶段时,次版本更新 (0.8.x → 0.9.0)可能包含破坏性变更——相关内容始终会在 CHANGELOG.md 的 ### Changed 部分中说明。补丁版本更新 (0.8.3 → 0.8.5)仅修复 bug。发布 1.0.0 后, 破坏性变更必须提升主版本号。如果无法接受频繁变更,请固定到已知可用的 0.x.y 版本。

运维

  • 日志。 始终写入 stderr(结构化 JSON),并写入滚动文件 ~/.whoop-mcp-server/logs/whoop-mcp.log(每个文件约 1 MB,保留 5 个备份)。 可通过环境变量覆盖:WHOOP_LOG_LEVEL(默认值 INFO)、WHOOP_LOG_FILE (路径;空字符串表示禁用文件处理器)、WHOOP_LOG_JSON (默认值 true)。
  • health_check(live=True) 返回一个字典,包含五项组件检查 (auth、api_reachable、cache_readable、cache_writable、 schema_version),以及总体判定 healthy | degraded | unhealthy。live=False 会跳过网络探测。
  • 令牌刷新。 当访问令牌将在 5 分钟内过期时,会自动使用刷新令牌。异步刷新锁 可防止多个并发请求发现同一令牌过期时同时刷新。如刷新无法恢复, 请重新运行 whoop-mcp-oauth(安装后运行 pip install),或 .venv/bin/python src/setup_direct_oauth.py(从源码运行)。
  • 速率限制。 客户端会遵循 429 响应中的 Retry-After,并 采用指数退避策略重试。超过重试次数后,调用会返回 RATE_LIMITED—— 工具不会抛出异常。

安全与隐私

所有操作都在本地运行。OAuth 令牌使用位于 ~/.whoop-mcp-server/.encryption_key 的密钥加密后存储在 ~/.whoop-mcp-server/tokens.json 中。SQLite 缓存文件以 0o600 模式创建。没有第三方服务——唯一的出站网络 调用直接发送到 api.prod.whoop.com。日志不包含 令牌、刷新令牌、客户端密钥或原始 WHOOP 响应正文。 请参阅 PRIVACY.md,了解服务读取、写入、发送和记录的 完整清单,以及如何删除所有内容 (rm -rf ~/.whoop-mcp-server)。

开发

# Run the full test suite (183 tests).
.venv/bin/pytest -q

# Re-record fixtures (live calls, requires creds in env).
.venv/bin/python tests/record_fixtures.py

# Fresh-install smoke test (clones current HEAD into a tempdir and
# verifies the install path end-to-end, minus the browser OAuth flow).
bash scripts/fresh_install_check.sh

添加新工具。 在 src/whoop_mcp_server.py 中添加实现,并使用 @mcp.tool() 装饰器;如果响应具有新的结构,则在 src/whoop_models.py 中添加 Pydantic 模型;如果资源需要持久化,则在 src/whoop_store.py 中 添加缓存表;并在 tests/ 中添加测试。保留错误封装 (_error_payload / _map_error)——工具绝不抛出异常。

发布流程。 更新 src/__version__.py(唯一真实来源)→ 按照 Keep-a-Changelog 格式,在 CHANGELOG.md 顶部 添加新章节 → 确认 whoop_mcp_server.py 中的 SERVER_VERSION 已获取新值(test_version_import 测试可防止版本不一致)→ 更新 pyproject.toml 中的 version → 在 main 上创建标签 vX.Y.Z。

面向基于此仓库构建的 Agent

从这里开始:

  • AGENTS.md — 关键约定。文件布局、 错误封装规范、TDD 循环、禁止事项、发布流程。 编辑任何内容前请先阅读。
  • docs/ARCHITECTURE.md — 一页式系统 概览图。四层架构图、读写/同步/事件路径、不变量。
  • docs/AGENT_INSTALL_PROMPT.md — 最终用户提供给其 Agent 以进行安装的可直接复制粘贴的提示词。

人类贡献者:简要指南见 CONTRIBUTING.md。 测试套件约需 6 秒运行(.venv/bin/pytest -q);所有 HTTP 调用都由 respx 模拟,因此你可以离线迭代。

版本管理

当前版本:0.8.5(见 src/__version__.py)。语义化 版本控制。完整历史记录:CHANGELOG.md。

致谢

由 RomanEvstigneev/whoop-mcp-server (v0.1.x)分叉而来。从 v0.2.0 起进行了大幅重写,改用直接 WHOOP OAuth(无第三方代理)、WHOOP v2 API、经 Pydantic 扁平化的 响应、本地 SQLite 缓存与增量同步、缓存优先读取、 事件流、导出(CSV/JSONL/Parquet)、health_check 工具、结构化 JSON 日志,以及 190 多项测试(截至 0.8.5 为 190 项)。采用 MIT 许可——两条版权声明均见 LICENSE。


mcp-name: io.github.AshwanthramKL/whoop-mcp

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。