一个作为Strava API桥梁的TypeScript服务器,使大型语言模型(LLMs)能够通过自然语言交互访问用户的活动、路线、路段和运动员数据。
8.1k 查看 · 2026-07-07 更新
简介
一个作为Strava API桥梁的TypeScript服务器,使大型语言模型(LLMs)能够通过自然语言交互访问用户的活动、路线、路段和运动员数据。
简介
一个作为Strava API桥梁的TypeScript服务器,使大型语言模型(LLMs)能够通过自然语言交互访问用户的活动、路线、路段和运动员数据。
Strava MCP 服务器
此项目使用 TypeScript 实现了一个 Model Context Protocol (MCP) 服务器,作为与 Strava API 的桥梁。它将 Strava 数据和功能以“工具”的形式暴露出来,大型语言模型 (LLMs) 可以通过 MCP 标准来利用这些工具。
功能
- 🏃 访问最近的活动、个人资料和统计数据。
- 📊 获取详细的活动流(功率、心率、踏频等)。
- 🗺️ 探索、查看、收藏和管理路段。
- ⏱️ 查看详细的活动和路段努力信息。
- 📍 列出并查看保存路线的详细信息。
- 💾 将路线导出为 GPX 或 TCX 格式到本地文件系统。
- 🤖 通过 MCP 提供 AI 友好的 JSON 响应。
- 🔧 使用 Strava API V3。
自然语言交互示例
向您的 AI 助手提出以下问题,以与您的 Strava 数据进行互动:
最近的活动和个人资料:
- “显示我最近的 Strava 活动。”
- “我最近三次骑行是什么?”
- “获取我的 Strava 个人资料信息。”
- “我的 Strava 用户名是什么?”
活动流和数据:
- “获取昨天早上跑步的心率数据。”
- “显示我上次骑行的功率数据。”
- “周末世纪骑行时我的踏频是多少?”
- “获取上周四晚上锻炼的所有流数据。”
- “显示我攀登 Mt. Diablo 的海拔剖面。”
统计数据:
- “今年我在 Strava 上的跑步统计数据是什么?”
- “我总共骑了多少公里?”
- “显示我所有时间的游泳总里程。”
特定活动:
- “给我最后一次跑步的详细信息。”
- “周二间歇训练的平均功率是多少?”
- “我昨天通勤时是否使用了我的 Trek 自行车?”
俱乐部:
- “我在哪些 Strava 俱乐部里?”
- “列出我加入的俱乐部。”
路段:
- “列出我在科罗拉多州博尔德附近标记的路段。”
- “显示我最喜欢的路段。”
- “获取‘Alpe du Zwift’路段的详细信息。”
- “金门公园附近有没有好的跑步路段?”
- “在博尔德旗杆山附近找到具有挑战性的爬坡路段。”
- “为我标记‘Flagstaff Road Climb’路段。”
- “取消标记‘Lefthand Canyon’路段。”
路段努力:
- “显示我本月在‘Sunshine Canyon’路段的努力情况。”
- “列出我今年一月到六月在 Box Hill 路段的尝试。”
- “获取我在 Alpe d'Huez 个人记录的详细信息。”
路线:
- “列出我保存的 Strava 路线。”
- “显示我的路线的第二页。”
- “我的 Boulder Loop 路线的海拔增益是多少?”
- “获取我的‘Boulder Loop’路线的描述。”
- “将我的‘Boulder Loop’路线导出为 GPX 文件。”
- “将我周日早上的路线保存为 TCX 文件。”
高级提示示例
这是一个更高级的提示示例,用于创建您 Strava 活动的专业自行车教练分析:
You are Tom Verhaegen, elite cycling coach and mentor to world champion Mathieu van der Poel. Analyze my most recent Strava activity. Provide a thorough, data-driven assessment of the ride, combining both quantitative insights and textual interpretation. Begin your report with a written summary that highlights key findings and context. Then, bring the raw numbers to life: build an interactive, visually striking dashboard using HTML, CSS, and JavaScript. Use bold, high-contrast colors and intuitive, insightful chart types that best suit each metric (e.g., heart rate, power, cadence, elevation). Embed clear coaching feedback and personalized training recommendations directly within the visualization. These should be practical, actionable, and grounded solely in the data provided—no assumptions or fabrications. As a bonus, sprinkle in motivational quotes and cheeky commentary from Mathieu van der Poel himself—he's been watching my rides with one eyebrow raised and a smirk of both concern and amusement. Goal: Deliver a professional-grade performance analysis that looks and feels like it came straight from the inner circle of world-class cycling.
此提示将创建您最近一次 Strava 活动的个性化分析,包括专业教练反馈和自定义可视化仪表板。
⚠️ 重要设置步骤
为了成功与 Claude 集成,请严格按照以下顺序执行这些步骤:
- 安装服务器及其依赖项
- 在 Claude 的配置中配置服务器
- 完成 Strava 认证流程
- 重启 Claude 以确保正确加载环境变量
跳过步骤或不按顺序执行可能会导致 Claude 无法正确读取环境变量。
安装与设置
- 先决条件:
- Node.js(推荐 v18 或更高版本)
- npm(通常随 Node.js 一起提供)
- 一个 Strava 账户
1. 从源代码安装
-
克隆仓库:
git clone https://github.com/r-huijts/strava-mcp.git cd strava-mcp -
安装依赖项:
npm install -
构建项目:
npm run build
2. 配置 Claude 桌面版
更新您的 Claude 配置文件:
{ "mcpServers": { "strava-mcp-local": { "command": "node", "args": [ "/absolute/path/to/your/strava-mcp/dist/server.js" ] // Environment variables are read from the .env file by the server } } }
请确保将 /absolute/path/to/your/strava-mcp/ 替换为实际的安装路径。
3. Strava 认证设置
setup-auth.ts 脚本简化了与 Strava API 的认证设置。请仔细按照以下步骤操作:
创建 Strava API 应用程序
- 前往 https://www.strava.com/settings/api
- 创建一个新的应用程序:
- 输入您的应用程序详细信息(名称、网站、描述)
- 重要:将“授权回调域名”设置为
localhost - 记下您的客户端 ID 和客户端密钥
运行设置脚本
# In your strava-mcp directory npx tsx scripts/setup-auth.ts
根据提示完成认证流程(详细说明见下方的认证部分)。
4. 重启 Claude
完成上述所有步骤后,重启 Claude 桌面版以使更改生效。这可以确保:
- 加载新的配置
- 正确读取环境变量
- 正确初始化 Strava MCP 服务器
🔑 环境变量
| 变量 | 描述 |
|---|---|
| STRAVA_CLIENT_ID | 您的 Strava 应用程序客户端 ID(必需) |
| STRAVA_CLIENT_SECRET | 您的 Strava 应用程序客户端密钥(必需) |
| STRAVA_ACCESS_TOKEN | 您的 Strava API 访问令牌(在设置过程中生成) |
| STRAVA_REFRESH_TOKEN | 您的 Strava API 刷新令牌(在设置过程中生成) |
| ROUTE_EXPORT_PATH | 保存导出路线文件的绝对路径(可选) |
令牌处理
该服务器实现了自动刷新令牌的功能。当初始访问令牌过期(通常为 6 小时后),服务器将自动使用存储在 .env 中的刷新令牌获取新的访问令牌和刷新令牌。这些新令牌随后会在运行中的进程和 .env 文件中更新,确保持续运行。
你只需要运行一次 scripts/setup-auth.ts 脚本来进行初始设置。
配置导出路径(可选)
如果你打算使用 export-route-gpx 或 export-route-tcx 工具,你需要指定一个目录来保存导出的文件。
编辑你的 .env 文件,并添加/更新 ROUTE_EXPORT_PATH 变量:
# Optional: Define an *absolute* path for saving exported route files (GPX/TCX) # Ensure this directory exists and the server process has write permissions. # Example: ROUTE_EXPORT_PATH=/Users/your_username/strava-exports ROUTE_EXPORT_PATH=
将占位符替换为你希望的导出目录的绝对路径。确保该目录存在并且服务器有权限写入该目录。
API 参考
服务器公开了以下 MCP 工具:
get-recent-activities
获取已认证用户的最近活动。
- 何时使用: 当用户询问他们的最近锻炼、活动、跑步、骑行等时。
- 参数:
perPage(可选):- 类型:
number - 描述: 要检索的活动数量。
- 默认值: 30
- 类型:
- 输出: 最近活动的格式化文本列表(名称、ID、距离、日期)。
- 错误: 缺失/无效令牌、Strava API 错误。
get-athlete-profile
获取已认证运动员的个人资料信息。
- 何时使用: 当用户询问他们的个人资料详情、用户名、位置、体重、是否为高级会员等时。
- 参数: 无
- 输出: 包含个人资料详情的格式化文本字符串。
- 错误: 缺失/无效令牌、Strava API 错误。
get-athlete-stats
获取已认证运动员的活动统计数据(最近、年度至今、历史总计)。
- 何时使用: 当用户询问他们的总体统计数据、跑步/骑行/游泳总数、个人记录(最长骑行、最大爬升)等时。
- 参数: 无
- 输出: 根据用户测量偏好格式化的统计数据摘要文本。
- 错误: 缺失/无效令牌、Strava API 错误。
get-activity-details
通过其 ID 获取特定活动的详细信息。
- 何时使用: 当用户询问由其 ID 确定的特定活动的详细信息时。
- 参数:
activityId(必需):- 类型:
number - 描述: 活动的唯一标识符。
- 类型:
- 输出: 根据用户测量偏好格式化的包含详细活动信息(类型、日期、距离、时间、速度、心率、功率、装备等)的文本字符串。
- 错误: 缺失/无效令牌、无效的
activityId、Strava API 错误。
list-athlete-clubs
列出已认证运动员所属的俱乐部。
- 何时使用: 当用户询问他们加入的俱乐部时。
- 参数: 无
- 输出: 俱乐部的格式化文本列表(名称、ID、运动项目、成员数、位置)。
- 错误: 缺失/无效令牌、Strava API 错误。
list-starred-segments
列出已认证运动员标记的路段。
- 使用时机: 当用户询问关于他们收藏或喜欢的路段时。
- 参数: 无
- 输出: 收藏路段的格式化文本列表(名称、ID、类型、距离、坡度、位置)。
- 错误: 缺少/无效的令牌、Strava API 错误。
get-segment
根据 ID 获取特定路段的详细信息。
- 使用时机: 当用户要求获取通过其 ID 标识的特定路段的详细信息时。
- 参数:
segmentId(必填):- 类型:
number - 描述: 路段的唯一标识符。
- 类型:
- 输出: 包含详细路段信息的格式化文本字符串(距离、坡度、海拔、位置、星级、努力次数等),尊重用户的测量偏好。
- 错误: 缺少/无效的令牌、无效的
segmentId、Strava API 错误。
explore-segments
在给定的地理区域内(边界框)搜索热门路段。
- 使用时机: 当用户想要在特定地理区域内查找或发现路段,可选地按活动类型或爬坡类别进行过滤。
- 参数:
bounds(必填):- 类型:
string - 描述: 逗号分隔:
south_west_lat,south_west_lng,north_east_lat,north_east_lng。
- 类型:
activityType(可选):- 类型:
string("running"或"riding") - 描述: 按活动类型过滤。
- 类型:
minCat(可选):- 类型:
number(0-5) - 描述: 最小爬坡类别。需要
activityType: 'riding'。
- 类型:
maxCat(可选):- 类型:
number(0-5) - 描述: 最大爬坡类别。需要
activityType: 'riding'。
- 类型:
- 输出: 找到的路段的格式化文本列表(名称、ID、爬坡类别、距离、坡度、海拔)。
- 错误: 缺少/无效的令牌、无效的
bounds格式、无效的过滤组合、Strava API 错误。
star-segment
为已验证的运动员收藏或取消收藏特定路段。
- 使用时机: 当用户明确要求收藏、设为喜欢、取消收藏或取消喜欢通过其 ID 标识的特定路段时。
- 参数:
segmentId(必填):- 类型:
number - 描述: 路段的唯一标识符。
- 类型:
starred(必填):- 类型:
boolean - 描述:
true表示收藏,false表示取消收藏。
- 类型:
- 输出: 确认操作和路段的新收藏状态的成功消息。
- 错误: 缺少/无效的令牌、无效的
segmentId、Strava API 错误(例如,未找到路段、速率限制)。
get-segment-effort
根据 ID 获取特定路段努力的详细信息。
- 使用时机: 当用户请求获取特定段落努力的详细信息时,通过其ID标识。
- 参数:
effortId(必填):- 类型:
number - 描述: 段落努力的唯一标识符。
- 类型:
- 输出: 包含详细努力信息的格式化文本字符串(段落名称、活动ID、时间、距离、心率、功率、排名等)。
- 错误: 缺失/无效令牌, 无效的
effortId, Strava API 错误。
list-segment-efforts
列出经过身份验证的运动员在给定段落上的努力,可按日期过滤。
- 使用时机: 当用户请求列出他们在特定段落上的努力或尝试,可能是在一个日期范围内。
- 参数:
segmentId(必填):- 类型:
number - 描述: 段落的ID。
- 类型:
startDateLocal(可选):- 类型:
string(ISO 8601 格式) - 描述: 过滤从该日期时间之后开始的努力。
- 类型:
endDateLocal(可选):- 类型:
string(ISO 8601 格式) - 描述: 过滤在该日期时间之前结束的努力。
- 类型:
perPage(可选):- 类型:
number - 描述: 每页结果数。
- 默认值: 30
- 类型:
- 输出: 匹配段落努力的格式化文本列表。
- 错误: 缺失/无效令牌, 无效的
segmentId, 无效的日期格式, Strava API 错误。
list-athlete-routes
列出由已验证身份的运动员创建的路线。
- 使用时机: 当用户请求查看他们创建或保存的路线时。
- 参数:
page(可选):- 类型:
number - 描述: 分页的页码。
- 类型:
perPage(可选):- 类型:
number - 描述: 每页的路线数量。
- 默认值: 30
- 类型:
- 输出: 路线的格式化文本列表(名称、ID、类型、距离、海拔、日期)。
- 错误: 缺失/无效令牌, Strava API 错误。
get-route
使用路线ID获取特定路线的详细信息。
- 使用时机: 当用户请求获取通过其ID标识的特定路线的详细信息时。
- 参数:
routeId(必填):- 类型:
number - 描述: 路线的唯一标识符。
- 类型:
- 输出: 包含路线详情的格式化文本字符串(名称、ID、类型、距离、海拔、预计时间、描述、段落数量)。
- 错误: 缺失/无效令牌, 无效的
routeId, Strava API 错误。
export-route-gpx
将特定路线导出为GPX格式并保存到本地。
- 使用时机: 当用户明确要求将特定路线导出或保存为 GPX 文件时。
- 前提条件: 服务器上必须正确配置
ROUTE_EXPORT_PATH环境变量。 - 参数:
routeId(必需):- 类型:
number - 描述:路线的唯一标识符。
- 类型:
- 输出: 表示保存位置的成功消息,或者错误消息。
- 错误: 缺失/无效的令牌、缺失/无效的
ROUTE_EXPORT_PATH、文件系统错误(权限、磁盘空间)、无效的routeId、Strava API 错误。
export-route-tcx
将特定路线以 TCX 格式导出并保存到本地。
- 使用时机: 当用户明确要求将特定路线导出或保存为 TCX 文件时。
- 前提条件: 服务器上必须正确配置
ROUTE_EXPORT_PATH环境变量。 - 参数:
routeId(必需):- 类型:
number - 描述:路线的唯一标识符。
- 类型:
- 输出: 表示保存位置的成功消息,或者错误消息。
- 错误: 缺失/无效的令牌、缺失/无效的
ROUTE_EXPORT_PATH、文件系统错误(权限、磁盘空间)、无效的routeId、Strava API 错误。
get-activity-streams
从 Strava 活动中检索详细的时序数据流,非常适合用于分析锻炼指标、可视化路线或进行详细的活动分析。
-
When to use: When you need detailed time-series data from an activity for:
- Analyzing workout intensity through heart rate zones
- Calculating power metrics for cycling activities
- Visualizing route data using GPS coordinates
- Analyzing pace and elevation changes
- Detailed segment analysis
-
Parameters:
id(required):- Type:
number | string - Description: The Strava activity identifier to fetch streams for
- Type:
types(optional):- Type:
array - Default:
['time', 'distance', 'heartrate', 'cadence', 'watts'] - Available types:
time: Time in seconds from startdistance: Distance in meters from startlatlng: Array of [latitude, longitude] pairsaltitude: Elevation in metersvelocity_smooth: Smoothed speed in meters/secondheartrate: Heart rate in beats per minutecadence: Cadence in revolutions per minutewatts: Power output in wattstemp: Temperature in Celsiusmoving: Boolean indicating if movinggrade_smooth: Road grade as percentage
- Type:
resolution(optional):- Type:
string - Values:
'low'(~100 points),'medium'(~1000 points),'high'(~10000 points) - Description: Data resolution/density
- Type:
series_type(optional):- Type:
string - Values:
'time'or'distance' - Default:
'distance' - Description: Base series type for data point indexing
- Type:
page(optional):- Type:
number - Default: 1
- Description: Page number for paginated results
- Type:
points_per_page(optional):- Type:
number - Default: 100
- Special value:
-1returns ALL data points split into multiple messages - Description: Number of data points per page
- Type:
-
Output Format:
- Metadata:
- Available stream types
- Total data points
- Resolution and series type
- Pagination info (current page, total pages)
- Statistics (where applicable):
- Heart rate: max, min, average
- Power: max, average, normalized power
- Speed: max and average in km/h
- Stream Data:
- Formatted time-series data for each requested stream
- Human-readable formats (e.g., formatted time, km/h for speed)
- Consistent numeric precision
- Labeled data points
- Metadata:
-
Example Request:
{ "id": 12345678, "types": ["time", "heartrate", "watts", "velocity_smooth", "cadence"], "resolution": "high", "points_per_page": 100, "page": 1 } -
Special Features:
- Smart pagination for large datasets
- Complete data retrieval mode (points_per_page = -1)
- Rich statistics and metadata
- Formatted output for both human and LLM consumption
- Automatic unit conversions
-
Notes:
- Requires activity:read scope
- Not all streams are available for all activities
- Older activities might have limited data
- Large activities are automatically paginated
- Stream availability depends on recording device and activity type
-
Errors:
- Missing/invalid token
- Invalid activity ID
- Insufficient permissions
- Unavailable stream types
- Invalid pagination parameters
get-activity-laps
检索特定 Strava 活动中记录的圈数。
-
使用时机:
- 分析活动不同段落(圈)的表现变化。
- 比较圈时间、速度、心率或功率输出。
- 了解活动是如何结构化的(例如,间歇训练)。
-
参数:
id(必填):- 类型:
number | string - 描述:Strava 活动的唯一标识符。
- 类型:
-
输出格式: 包含每个圈的详细信息的文本摘要,包括:
- 圈索引
- 圈名称(如果有)
- 经过时间(格式为 HH:MM:SS)
- 移动时间(格式为 HH:MM:SS)
- 距离(公里)
- 平均速度(公里/小时)
- 最高速度(公里/小时)
- 总爬升高度(米)
- 平均心率(如果有,单位为 bpm)
- 最大心率(如果有,单位为 bpm)
- 平均踏频(如果有,单位为 rpm)
- 平均功率(如果有,单位为 W)
-
示例请求:
{ "id": 1234567890 } -
示例响应片段:
活动圈数摘要 (ID: 1234567890): 圈 1:热身圈 时间:15:02(移动:14:35) 距离:5.01 公里 平均速度:20.82 公里/小时 最高速度:35.50 公里/小时 爬升高度:50.2 米 平均心率:135.5 bpm 最大心率:150 bpm 平均踏频:85.0 rpm 圈 2:间歇 1 时间:05:15(移动:05:10) 距离:2.50 公里 平均速度:29.03 公里/小时 最高速度:42.10 公里/小时 爬升高度:10.1 米 平均心率:168.2 bpm 最大心率:175 bpm 平均踏频:92.1 rpm 平均功率:280.5 W(传感器) ... -
注意事项:
- 对于公开/关注者的活动需要
activity:read权限范围,对于私有活动需要activity:read_all权限范围。 - 圈数据的可用性取决于记录设备和活动类型(例如,手动活动可能没有圈)。
- 对于公开/关注者的活动需要
-
错误:
- 缺失/无效令牌
- 无效的活动 ID
- 权限不足
- 未找到活动
get-athlete-zones
检索已验证运动员配置的心率和功率区间。
- 何时使用: 当用户询问关于他们的心率区间、功率区间或训练区间设置时。
- 参数: 无
- 输出格式:
返回两个文本块:
- 一个格式化的摘要,详细说明配置的区间:
- 心率区间:自定义状态、区间范围、时间分布(如果可用)
- 功率区间:区间范围、时间分布(如果可用)
- 由 Strava API 返回的完整的原始 JSON 数据。
- 一个格式化的摘要,详细说明配置的区间:
- 示例响应片段(摘要):
**运动员区间:** ❤️ **心率区间** 自定义区间:否 区间1:0 - 115 bpm 区间2:115 - 145 bpm 区间3:145 - 165 bpm 区间4:165 - 180 bpm 区间5:180+ bpm ⚡ **功率区间** 区间1:0 - 150 W 区间2:151 - 210 W 区间3:211 - 250 W 区间4:251 - 300 W 区间5:301 - 350 W 区间6:351 - 420 W 区间7:421+ W 时间分布: - 0-50: 0:24:58 - 50-100: 0:01:02 ... - 450-∞: 0:05:43 - 注意事项:
- 需要
profile:read_all范围权限。 - 并非所有运动员都配置了区间。
- 需要
- 错误:
- 缺失/无效的令牌
- 权限不足(缺少
profile:read_all范围 - 403 错误) - 需要订阅(如果 Strava 更改了 API 访问规则)
贡献
欢迎贡献!请随时提交 Pull Request。
许可证
本项目采用 MIT 许可证 - 详情见 LICENSE 文件。(假设为 MIT 许可证,如有不同请更新)
来源
- 来源:github
- 链接:https://github.com/r-huijts/strava-mcp