Strava MCP Server
# Strava MCP Server
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that provides full access to the Strava API v3. Connect Claude (or any MCP client) to your Strava fitness data — activities, athletes, clubs, segments, routes, streams, gear, and more.
## Features
- **30+ tools** covering all major Strava API v3 endpoints
- **Auto token refresh** — OAuth2 tokens are refreshed and cached automatically
- **Formatted responses** — distances in km, times in minutes, speeds in km/h
- **Convenience tools** — weekly/monthly summaries, filter by sport type
### Available Tools
| Category | Tools |
|----------|-------|
| **Activities** | Create, get details, comments, kudos, laps, list, zones, update |
| **Athletes** | Profile, zones, stats, update weight |
| **Clubs** | List, details, members, admins, activities |
| **Gear** | Get gear details (bikes & shoes) |
| **Routes** | List, details, GPX export, TCX export |
| **Segments** | Explore, starred, details, star/unstar |
| **Segment Efforts** | List efforts, effort details |
| **Streams** | Activity, route, effort, segment time-series data |
| **Uploads** | Upload status |
| **Summaries** | Weekly summary, monthly summary, filter by sport type, filter by date |
## Prerequisites
- Python 3.12+
- [uv](https://docs.astral.sh/uv/) (Python package manager)
- A Strava account
- A Strava API application (see setup below)
## Setup
### 1. Create a Strava API Application
1. Go to [https://www.strava.com/settings/api](https://www.strava.com/settings/api)
2. Create a new application:
- **Application Name**: anything (e.g. "MCP Server")
- **Category**: choose any
- **Website**: `http://localhost`
- **Authorization Callback Domain**: `localhost`
3. Note your **Client ID** and **Client Secret**
### 2. Clone and Install
```bash
git clone https://github.com/manojanasuri16/strava-mcp-server.git
cd strava-mcp-server
uv sync
```
### 3. Configure Environment
Create a `.env` file in the project root:
```env
STRAVA_CLIENT_ID=<your_client_id>
STRAVA_CLIENT_SECRET=<your_client_secret>
STRAVA_REFRESH_TOKEN=<your_refresh_token>
```
To get your refresh token, follow the **OAuth Authorization** steps below.
### 4. OAuth Authorization (Getting Your Refresh Token)
Strava uses OAuth2. You need to authorize the app once to get a refresh token.
**Step 1: Authorize in browser**
Open this URL in your browser (replace `YOUR_CLIENT_ID`):
```
https://www.strava.com/oauth/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=http://localhost&scope=read_all,activity:read_all,activity:write,profile:read_all,profile:write
```
**Step 2: Grab the authorization code**
After you click "Authorize", Strava redirects to:
```
http://localhost?code=AUTHORIZATION_CODE&scope=...
```
Copy the `code` value from the URL. This code is **single-use** and **expires in minutes**, so proceed quickly.
**Step 3: Exchange code for tokens**
**On Linux/macOS (bash):**
```bash
curl -X POST https://www.strava.com/api/v3/oauth/token \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET \
-d code=AUTHORIZATION_CODE \
-d grant_type=authorization_code
```
**On Windows (PowerShell):**
```powershell
Invoke-RestMethod -Method Post -Uri "https://www.strava.com/api/v3/oauth/token" -Body @{
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
code = "AUTHORIZATION_CODE"
grant_type = "authorization_code"
}
```
**Step 4: Save the refresh token**
The response will include `access_token`, `refresh_token`, and `expires_at`. Copy the `refresh_token` value into your `.env` file.
The server will automatically refresh the access token when it expires using this refresh token.
## Usage
### Test with MCP Inspector
The MCP Inspector provides a web UI to test your tools:
```bash
uv run mcp dev strava_server.py
```
1. Open the Inspector URL shown in the terminal
2. Click **Connect**
3. Go to the **Tools** tab
4. Try running a tool like `get_athlete_profile` or `get_recent_activities`
### Use with Claude Code (CLI)
From your project directory, register the server:
```bash
claude mcp add strava -- uv run strava_server.py
```
Then start a new Claude Code session and ask things like:
- "How was my running this week?"
- "Show me my last 10 activities"
- "What are my all-time cycling stats?"
- "Find popular running segments near Bangalore"
- "Create a manual yoga activity for today"
### Use with Claude Desktop
```bash
uv run mcp install strava_server.py
```
Or manually add to your config file:
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"strava": {
"command": "uv",
"args": ["run", "strava_server.py"],
"cwd": "/path/to/strava-mcp-server"
}
}
}
```
Restart Claude Desktop after saving.
### Use with ChatGPT Desktop
1. Open ChatGPT Desktop app
2. Go to **Settings** > **MCP**
3. Add a new server with:
- **Name:** `strava`
- **Command:** `uv run strava_server.py`
- **Working directory:** `/path/to/strava-mcp-server`
Restart ChatGPT Desktop after adding.
### Use with Cursor / VS Code
Add to `.cursor/mcp.json` or `.vscode/mcp.json` in your workspace:
```json
{
"servers": {
"strava": {
"command": "uv",
"args": ["run", "strava_server.py"],
"cwd": "/path/to/strava-mcp-server"
}
}
}
```
### Run Standalone
```bash
uv run strava_server.py
```
## Troubleshooting
### 401 Unauthorized Error
This is the most common issue. It means your access token is invalid.
**Cause 1: Stale cached tokens**
The server caches tokens at `~/.strava-mcp-tokens.json`. If this file contains expired/invalid tokens, the server will keep using them.
**Fix:**
```bash
# Linux/macOS
rm ~/.strava-mcp-tokens.json
# Windows (PowerShell)
Remove-Item "$HOME\.strava-mcp-tokens.json" -ErrorAction SilentlyContinue
```
Then restart the server.
**Cause 2: Invalid refresh token**
Your refresh token in `.env` may be expired or revoked. This happens if:
- You re-authorized the app and got a new refresh token (old one is invalidated)
- You revoked the app's access in Strava settings
- The token was never obtained properly
**Fix:** Redo the [OAuth Authorization](#4-oauth-authorization-getting-your-refresh-token) steps to get a fresh refresh token.
**Cause 3: Wrong client credentials**
Double-check your `STRAVA_CLIENT_ID` and `STRAVA_CLIENT_SECRET` in `.env` match what's shown at [https://www.strava.com/settings/api](https://www.strava.com/settings/api).
### 429 Rate Limit
Strava limits API requests to:
- 100 requests per 15 minutes
- 1,000 requests per day
The server returns a helpful error message when rate-limited. Wait a few minutes and try again.
### Token Refresh Fails on Startup
If the server crashes immediately with a token error, make sure:
1. Your `.env` file exists in the project root
2. All three variables are set (`STRAVA_CLIENT_ID`, `STRAVA_CLIENT_SECRET`, `STRAVA_REFRESH_TOKEN`)
3. There are no extra spaces or quotes around the values
### Missing Scopes
Some tools require specific OAuth scopes:
- `activity:read_all` — needed for activity details, streams
- `activity:write` — needed for creating/updating activities
- `profile:read_all` — needed for athlete zones
- `profile:write` — needed for updating weight
If a tool returns a 403 Forbidden error, you may need to re-authorize with the correct scopes. Use the authorization URL in Step 1 above (it includes all scopes).
## Project Structure
```
strava-mcp-server/
├── strava_server.py # Entry point (thin wrapper)
├── src/
│ └── strava_mcp/
│ ├── __init__.py # Package exports
│ ├── server.py # FastMCP instance & logging
│ ├── auth.py # OAuth2 token management
│ ├── client.py # HTTP helpers (GET, POST, PUT)
│ ├── formatters.py # Response formatting utilities
│ └── tools/
│ ├── __init__.py # Auto-imports all tool modules
│ ├── activities.py # Activity CRUD, laps, zones, comments, kudos
│ ├── athletes.py # Profile, stats, zones, weight
│ ├── clubs.py # Clubs, members, admins, activities
│ ├── gear.py # Bike & shoe details
│ ├── routes.py # Routes, GPX/TCX export
│ ├── segments.py # Segments, efforts, explore, star
│ ├── streams.py # Time-series data streams
│ └── extras.py # Summaries, filters, upload status
├── pyproject.toml # Project config and dependencies
├── uv.lock # Locked dependencies
├── .env # Your Strava credentials (not committed)
└── README.md # This file
```
## License
MIT
TDQS
Scored across 37 tools
Each tool targets a distinct resource and action, with clear separation between activities, segments, routes, clubs, athlete profiles, and summaries. Even similar tools like get_recent_activities and get_activities_by_date have unambiguous differences in filtering.
Most tools follow a consistent verb_noun pattern (e.g., create_activity, get_activity, update_activity), but a few like monthly_summary and weekly_summary deviate from this pattern, using noun_adjective instead.
With 37 tools, the server is on the heavy side. While it covers a broad domain, this number exceeds the recommended range and may overwhelm agents, making selection and navigation more difficult.
The tool set covers most CRUD operations for activities, segments, routes, clubs, and athlete data, plus exports and summaries. A notable gap is the absence of a delete activity tool, but overall the surface is comprehensive.