stravamcp
An MCP server that exposes Strava v3 API as read-only tools for AI agents. It covers athlete profiles, activities, stats, routes, segments, and rate limits, with OAuth2 authorization handled via a companion HTTP server.
README
strava-server
Two servers over one Strava client:
- an Express HTTP server that runs the OAuth 2.0 flow and exposes the Strava v3 API as JSON endpoints;
- an MCP server (stdio) that exposes the same data as tools for an AI agent.
Both share src/strava/* and the same token file, so you authorize once in the browser and the
MCP server picks the tokens up automatically.
1. Create a Strava API application
- Sign in at https://www.strava.com/settings/api and create an app (a Strava subscription is required).
- Set Authorization Callback Domain to
localhost. - Copy the Client ID and Client Secret.
New apps start in single-player mode — only your own account can authorize them, which is exactly what this server needs.
2. Configure
Copy-Item .env.example .env
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" # paste into SESSION_SECRET
Fill in STRAVA_CLIENT_ID and STRAVA_CLIENT_SECRET in .env.
.env and .tokens.json are gitignored — never commit them.
3. Run
npm install
npm run dev # HTTP server, watch mode
# or
npm run build; npm start
Then open http://localhost:3000/auth/login and click Authorize. Strava redirects back to
/auth/callback, the server exchanges the one-time code for a refresh token + access token, and
persists them to .tokens.json (mode 600). Access tokens expire every 6 hours; the server
refreshes them automatically before each request, so you only authorize once.
4. MCP server
npm run mcp # stdio, via tsx
# or
npm run build; npm run mcp:start
VS Code picks up .vscode/mcp.json automatically — open the Chat view, switch to
Agent mode and start the strava server. For other clients:
{
"mcpServers": {
"strava": {
"command": "node",
"args": ["C:/path/to/stravamcp/dist/mcp/index.js"],
"env": {
"STRAVA_CLIENT_ID": "...",
"STRAVA_CLIENT_SECRET": "..."
}
}
}
}
.env and the token file are resolved relative to the package directory, not the working
directory, so the MCP server works no matter where the client launches it from.
Tools
| Tool | Strava endpoint |
|---|---|
strava_auth_status |
Connection state, granted scopes, token expiry |
strava_get_athlete_summary |
Profile + totals + recent activities in one call |
strava_get_athlete |
GET /athlete |
strava_get_athlete_stats |
GET /athletes/{id}/stats |
strava_get_athlete_zones |
GET /athlete/zones |
strava_list_activities |
GET /athlete/activities (before/after accept ISO dates) |
strava_get_activity |
GET /activities/{id} |
strava_get_activity_laps |
GET /activities/{id}/laps |
strava_get_activity_zones |
GET /activities/{id}/zones |
strava_get_activity_streams |
GET /activities/{id}/streams (downsampled to max_points) |
strava_get_activity_comments |
GET /activities/{id}/comments |
strava_get_activity_kudoers |
GET /activities/{id}/kudos |
strava_list_clubs / strava_get_club |
GET /athlete/clubs, GET /clubs/{id} |
strava_get_gear |
GET /gear/{id} |
strava_list_routes / strava_get_route |
GET /athletes/{id}/routes, GET /routes/{id} |
strava_list_starred_segments / strava_get_segment |
GET /segments/starred, GET /segments/{id} |
strava_get_rate_limit |
Last-seen rate-limit headers |
All tools are read-only and annotated as such. Responses that would blow up an agent's context are trimmed by default: segment efforts and full-resolution polylines are opt-in, and streams are evenly downsampled (200 points by default).
If a tool reports "Not connected to Strava", run the HTTP server once and complete
/auth/login — the MCP server reads the same .tokens.json.
HTTP endpoints
Auth
| Method | Path | Description |
|---|---|---|
| GET | /auth/login |
Redirect to Strava's consent screen (CSRF-protected via a signed state cookie) |
| GET | /auth/callback |
Code → token exchange |
| GET | /auth/status |
Connection state, granted scope, token expiry |
| POST | /auth/logout |
Deauthorize with Strava and delete the local tokens |
Data
| Method | Path | Strava endpoint |
|---|---|---|
| GET | /api/me |
Aggregated profile + totals + last 10 activities (formatted in km/min) |
| GET | /api/athlete |
GET /athlete |
| GET | /api/athlete/stats |
GET /athletes/{id}/stats |
| GET | /api/athlete/zones |
GET /athlete/zones |
| GET | /api/athlete/clubs |
GET /athlete/clubs |
| GET | /api/athlete/routes |
GET /athletes/{id}/routes |
| GET | /api/activities |
GET /athlete/activities (page, per_page, before, after) |
| GET | /api/activities/:id |
GET /activities/{id} (include_all_efforts=true) |
| GET | /api/activities/:id/laps |
GET /activities/{id}/laps |
| GET | /api/activities/:id/zones |
GET /activities/{id}/zones |
| GET | /api/activities/:id/comments |
GET /activities/{id}/comments |
| GET | /api/activities/:id/kudos |
GET /activities/{id}/kudos |
| GET | /api/activities/:id/streams |
GET /activities/{id}/streams (keys=time,distance,heartrate) |
| GET | /api/clubs/:id |
GET /clubs/{id} |
| GET | /api/gear/:id |
GET /gear/{id} |
| GET | /api/routes/:id |
GET /routes/{id} |
| GET | /api/segments/starred |
GET /segments/starred |
| GET | /api/segments/:id |
GET /segments/{id} |
| GET | /api/rate-limit |
Last-seen X-RateLimit-* / X-ReadRateLimit-* values |
Example:
curl http://localhost:3000/api/me
curl "http://localhost:3000/api/activities?per_page=50&after=1704067200"
curl "http://localhost:3000/api/activities/123456789/streams?keys=time,heartrate,watts"
Scopes
STRAVA_SCOPE defaults to read,read_all,profile:read_all,activity:read_all:
profile:read_all— detailed athlete representation and/athlete/zonesactivity:read_all— "Only Me" activities, otherwise they are filtered outread_all— private routes and segments
If you change the scope you must re-run /auth/login; /auth/callback reports any scope the
athlete declined under missing_scope.
Rate limits
Default limits are 200 requests / 15 min and 2,000 / day. The client records the limit headers
from every response; a 429 is surfaced as a JSON error with the current usage. From the MCP
server, call strava_get_rate_limit before issuing a burst of requests.
Notes
/activities/{id}/zonesand/segment_effortsrequire a Strava subscription.- Tokens are stored on disk in plain JSON. Keep the file local; for a multi-user deployment
replace
src/strava/token-store.tswith an encrypted, per-user store.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。