252 lines
8.5 KiB
Markdown
252 lines
8.5 KiB
Markdown
# 🚴 Strava MCP Server
|
|
|
|
A production-ready **Model Context Protocol (MCP) server** that exposes the Strava API v3 as MCP-compatible tools, resources, and prompts — enabling AI agents and LLM-based applications to query your Strava training data through a standardized interface.
|
|
|
|
Built with [FastMCP](https://github.com/jlowin/fastmcp) and the [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk), compatible with MCP Inspector, Claude Desktop, and any MCP-compliant client.
|
|
|
|
---
|
|
|
|
## ✨ Features
|
|
|
|
- 🛠️ **25+ MCP Tools** covering all major Strava API read endpoints (including athlete profile & stats)
|
|
- 💬 **2 MCP Prompts** for structured AI-driven training analysis
|
|
- 🔄 **Fully Automated OAuth** — authentication flow integrated directly as an MCP tool with auto-rotation
|
|
- 🐳 **Docker-Ready** — highly optimized multi-stage Docker build utilizing `uv`
|
|
- 🌐 **Streamable HTTP transport** for broad client compatibility (SSE)
|
|
- 🔒 **Read-only** — no write operations, safe to use with AI agents
|
|
|
|
---
|
|
|
|
## 📋 Table of Contents
|
|
|
|
- [Requirements](#requirements)
|
|
- [Installation & Deployment](#installation--deployment)
|
|
- [Docker (Recommended)](#docker-recommended)
|
|
- [Local Python (uv)](#local-python-uv)
|
|
- [Strava API Setup](#strava-api-setup)
|
|
- [Connecting with MCP Inspector](#connecting-with-mcp-inspector)
|
|
- [MCP Primitives](#mcp-primitives)
|
|
- [Project Structure](#project-structure)
|
|
- [CI/CD (Gitea Actions)](#cicd-gitea-actions)
|
|
- [Known Strava API Limitations](#known-strava-api-limitations)
|
|
- [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## Requirements
|
|
|
|
- A [Strava account](https://www.strava.com) with API access
|
|
- A [Strava API Application](https://www.strava.com/settings/api)
|
|
- **Docker** (for containerized deployment) OR **Python 3.10+** & [uv](https://github.com/astral-sh/uv) (for local execution)
|
|
|
|
---
|
|
|
|
## Installation & Deployment
|
|
|
|
### Docker (Recommended)
|
|
|
|
The project includes a highly optimized, deterministic Dockerfile powered by `uv`.
|
|
|
|
```bash
|
|
# Clone the repository
|
|
git clone https://git.hnrx.net/hnrx/strava-mcp-server.git
|
|
cd strava-mcp-server
|
|
|
|
# Build the image
|
|
docker build -t strava-mcp-server:latest .
|
|
|
|
# Run the container (injecting your .env file)
|
|
docker run --rm -p 8000:8000 --env-file .env strava-mcp-server:latest
|
|
```
|
|
|
|
### Local Python (uv)
|
|
|
|
```bash
|
|
git clone https://git.hnrx.net/hnrx/strava-mcp-server.git
|
|
cd strava-mcp-server
|
|
|
|
# Install dependencies and start the server
|
|
uv run strava-mcp
|
|
```
|
|
|
|
### Run on the fly with `uvx` (No git clone required)
|
|
|
|
You can run the server directly from the repository without cloning it manually by using `uvx`. `uv` will download it into a temporary isolated environment and execute it:
|
|
|
|
```bash
|
|
# Set up your .env file in the current directory first!
|
|
uvx --from git+https://git.hnrx.net/hnrx/strava-mcp-server.git strava-mcp
|
|
```
|
|
|
|
*(If you are already inside the cloned directory, you can also just run `uvx --from . strava-mcp`)*
|
|
|
|
---
|
|
|
|
## Strava API 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
|
|
3. Set **Authorization Callback Domain** to `localhost`
|
|
4. Note your **Client ID** and **Client Secret**
|
|
|
|
### 2. Configure Environment
|
|
|
|
Copy the example environment file:
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
Edit `.env` and fill in your Client ID and Secret:
|
|
```env
|
|
STRAVA_CLIENT_ID=your_client_id_here
|
|
STRAVA_CLIENT_SECRET=your_client_secret_here
|
|
```
|
|
|
|
### 3. Authenticate (The Magic Way ✨)
|
|
|
|
You **do not** need to manually fiddle with OAuth tokens. The server includes an interactive MCP tool to handle authentication!
|
|
|
|
1. Start the server (`docker run ...` or `uv run strava-mcp`).
|
|
2. Connect to the server via an MCP Client (like Claude Desktop or MCP Inspector).
|
|
3. Call the `get_new_oauth_token` MCP tool.
|
|
4. Your browser will open for you to authorize the app. The server will intercept the callback locally, generate your tokens, and automatically save the `STRAVA_REFRESH_TOKEN` to your `.env` file!
|
|
|
|
> **Required OAuth Scopes:**
|
|
> `activity:read_all,profile:read_all,read`
|
|
|
|
---
|
|
|
|
## Connecting with MCP Clients
|
|
|
|
The server listens on **port 8000** by default and exposes an SSE endpoint:
|
|
`http://localhost:8000/mcp`
|
|
|
|
### Claude Desktop
|
|
|
|
Add to your `claude_desktop_config.json`:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"strava": {
|
|
"url": "http://localhost:8000/mcp",
|
|
"transport": "streamable-http"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### MCP Inspector
|
|
|
|
1. Open [MCP Inspector](https://inspector.modelcontextprotocol.io/)
|
|
2. Select transport: **Streamable HTTP**
|
|
3. Enter URL: `http://localhost:8000/mcp`
|
|
4. Click **Connect**
|
|
|
|
---
|
|
|
|
## MCP Primitives
|
|
|
|
### Tools
|
|
|
|
#### 🔐 Authentication
|
|
| Tool | Description |
|
|
|------|-------------|
|
|
| `get_new_oauth_token` | Starts the interactive browser OAuth2 flow to generate and save your initial Refresh Token |
|
|
|
|
#### 🏃 Athlete
|
|
| Tool | Description |
|
|
|------|-------------|
|
|
| `get_athlete_profile` | Full athlete profile: name, city, country, follower count, gear list |
|
|
| `get_athlete_stats` | Training totals: all-time, year-to-date, and last 4 weeks for runs, rides, and swims |
|
|
| `get_athlete_zones` | Heart rate and power zones |
|
|
|
|
#### 🚴 Activities
|
|
| Tool | Description |
|
|
|------|-------------|
|
|
| `list_activities` | Paginated activity list with optional time range filters |
|
|
| `get_activity_details` | Full activity details incl. segment efforts |
|
|
| `get_activity_laps` | Lap splits |
|
|
| `get_activity_zones` | Heart rate and power zones for a specific activity |
|
|
| `get_activity_comments` | Comments on an activity |
|
|
| `get_activity_kudoers` | Athletes who gave kudos |
|
|
| `get_activity_streams` | Raw GPS/sensor data streams |
|
|
|
|
*(Note: Additional tools exist for Clubs, Routes, Segments, Segment Efforts, and Gear. See MCP Inspector for full details.)*
|
|
|
|
### Prompts
|
|
|
|
Prompts pre-structure AI conversations with the right tool-calling instructions.
|
|
|
|
- **`analyze_activity`**: Triggers a structured analysis of a specific activity including summary, performance metrics, and key takeaways.
|
|
- **`training_summary`**: Generates a training load report for the last N weeks (volume, trends, recommendations).
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
strava-mcp-server/
|
|
├── Dockerfile # Multi-stage optimized uv build
|
|
├── src/
|
|
│ └── strava_mcp_server/ # Installable Python package
|
|
│ ├── __init__.py
|
|
│ ├── main.py # Server entrypoint → strava-mcp
|
|
│ ├── strava_client.py # Strava API client with auto token rotation
|
|
│ └── tools/ # Modularized MCP tools directory
|
|
│ ├── __init__.py # Tool registry
|
|
│ ├── activities.py
|
|
│ ├── athlete.py
|
|
│ ├── auth.py # OAuth automation flow
|
|
│ └── ...
|
|
├── .gitea/
|
|
│ └── workflows/ # Gitea Actions CI/CD Pipeline
|
|
├── tests/
|
|
├── pyproject.toml
|
|
└── .env
|
|
```
|
|
|
|
---
|
|
|
|
## CI/CD (Gitea Actions)
|
|
|
|
This repository includes a pre-configured Gitea Action (`.gitea/workflows/cicd.yml`) that automatically:
|
|
1. **Lints** the codebase using `ruff` on every push/PR.
|
|
2. **Builds & Pushes** the Docker container to the local Container Registry (`git.hnrx.net`) upon a successful merge to `main`.
|
|
|
|
---
|
|
|
|
## Known Strava API Limitations
|
|
|
|
| Endpoint | Status | Reason |
|
|
|----------|--------|--------|
|
|
| `GET /segments/{id}/leaderboard` | `403 Forbidden` | Requires Strava API partnership |
|
|
| `GET /segment_efforts/{id}` | `403 Forbidden` | Requires Strava API partnership |
|
|
| `GET /athlete/zones` | `401 Unauthorized` | Requires `profile:read_all` OAuth scope |
|
|
|
|
> **Workaround for segment efforts:** Use `get_activity_details` to access segment efforts embedded in activity data. The `segment_efforts[]` array contains effort IDs, times, heart rate, power, and PR/KOM ranks.
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### `[Errno 48] Address already in use`
|
|
Port 8000 is occupied by a previous server process:
|
|
```bash
|
|
lsof -ti :8000 | xargs kill -9
|
|
```
|
|
|
|
### ModuleNotFoundError / iCloud Sync Issues (macOS)
|
|
If you are developing locally on macOS and your `strava-mcp-server` directory is located inside `Documents/` or `Desktop/`, **iCloud Drive** will constantly sync and delete files inside your virtual environment (`.venv`), leading to missing packages.
|
|
**Solution:** Move the project out of iCloud or rename the folder to end in `.nosync` (e.g. `strava-mcp-server.nosync`).
|
|
|
|
### 401 Unauthorized
|
|
Your refresh token has expired or been revoked. Simply run the `get_new_oauth_token` MCP tool again to re-authenticate!
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
MIT
|