git clone https://github.com/ljcl/strava-mcp{
"mcpServers": {
"strava-mcp": {
"command": "node",
"args": ["/path/to/strava-mcp/dist/index.js"],
"env": {
"STRAVA_CLIENT_SECRET": "<strava_client_secret>",
"PUBLIC_URL": "<public_url>"
}
}
}
}STRAVA_CLIENT_SECRETPUBLIC_URLMCP Servers overview
# Strava MCP
[](https://github.com/ljcl/strava-mcp/actions/workflows/ci.yml)
[](https://ljcl.github.io/strava-mcp/)
[](./LICENSE)
A Model Context Protocol (MCP) server that supplements the official Strava MCP connector. It adds write access, segments, routes, photos, derived analysis, and interactive visualizations that the official connector does not provide.
## Features
- Write and update activities (title, description, sport type, gear, flags)
- Explore, view, star, and manage segments
- Fetch per-activity photos, zone breakdowns, and running summaries
- List and view details of saved routes
- Export routes (GPX/TCX) and activity tracks (GPX built from streams)
- AI-friendly JSON responses via MCP
- Interactive activity charts (heart rate, power, altitude, pace) rendered in MCP-compatible hosts
- Automatic token refresh
- Streamable HTTP transport for remote deployment
Browse the UI components in the [live Storybook](https://ljcl.github.io/strava-mcp/).
## Quick Start (Docker)
### 1. Create a Strava API Application
1. Go to [strava.com/settings/api](https://www.strava.com/settings/api)
2. Create a new application:
- Enter your application details (name, website, description)
- Set "Authorization Callback Domain" to your public URL hostname (e.g., `strava-mcp.example.com`)
- Note your **Client ID** and **Client Secret**
### 2. Configure Environment
```bash
cp .env.example .env
```
Edit `.env` with your values:
```env
STRAVA_CLIENT_ID=your_client_id
STRAVA_CLIENT_SECRET=your_client_secret
PUBLIC_URL=https://your-public-url.example.com
```
### 3. Start the Server
```bash
docker compose up -d
```
> **Prefer a prebuilt image?** Instead of building locally you can pull the published image:
>
> ```bash
> docker pull ghcr.io/ljcl/strava-mcp:latest
> ```
>
> Point your `docker-compose.yml` `image:` at `ghcr.io/ljcl/strava-mcp:latest` (and drop the
> `build:` block) to run it without a local build.
> **Note on the `./data` bind mount:** the image is distroless and runs as the non-root user
> **UID 65534**. Tokens are persisted to the host-mounted `./data` directory, so it must be
> writable by that UID or token persistence fails on first run:
>
> ```bash
> mkdir -p data
> sudo chown -R 65534:65534 data
> ```
>
> Alternatively, swap the bind mount for a named volume in `docker-compose.yml`
> (e.g. `strava-data:/app/data`), which Docker initializes with the correct ownership.
### 4. Authorize with Strava
Visit `https://your-public-url/auth/start` in your browser. After authorizing, tokens are saved automatically.
Check status anytime at `https://your-public-url/auth/status`.
If you set `MCP_AUTH_TOKEN` (recommended for tunnel-exposed servers — see
[Securing the endpoint](#securing-the-endpoint)), append it to both URLs as
`?token=<MCP_AUTH_TOKEN>`.
### 5. Connect to Claude Desktop
Add to your Claude configuration (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
```json
{
"mcpServers": {
"strava": {
"type": "url",
"url": "https://your-public-url/mcp",
"headers": { "Authorization": "Bearer your-mcp-auth-token" }
}
}
}
```
The `headers` entry is only needed when `MCP_AUTH_TOKEN` is set (recommended
for tunnel-exposed servers — see [Securing the endpoint](#securing-the-endpoint)).
Restart Claude Desktop to load the new configuration.
Using a different MCP client? See [Client configuration](#client-configuration) for Claude Code, Cursor, and VS Code.
## Connecting to AI Tools
Most AI tools (Claude Desktop, Claude Code, etc.) need an HTTPS URL to reach your MCP server. Since the server runs on your local network, you'll need a tunnel to expose it.
### Tailscale Funnel (Recommended)
[Tailscale Funnel](https://tailscale.com/kb/1223/funnel) exposes a local port to the internet over HTTPS with no configuration:
```bash
tailscale funnel --bg 3000
# → https://your-machine.tail1234.ts.net
```
Set `PUBLIC_URL` in your `.env` to the resulting URL.
### Cloudflare Tunnel
```bash
cloudflared tunnel --url http://localhost:3000
```
### Securing the endpoint
A tunnel makes `/mcp` reachable by anyone who discovers the URL — including the
`update-activity` write tool. Set `MCP_AUTH_TOKEN` to a long random secret
(e.g. `openssl rand -hex 32`) and the server requires
`Authorization: Bearer <token>` on every `/mcp` request, returning 401
otherwise. Each client snippet below shows where the header goes. Without
`MCP_AUTH_TOKEN` the endpoint stays open (unchanged behaviour) and the server
logs a startup warning when `PUBLIC_URL` is configured.
The secret also gates the OAuth web routes: `/auth/start` and `/auth/status`
require it (in the browser, open `/auth/start?token=<MCP_AUTH_TOKEN>`), so a
stranger cannot start an authorization flow against your server or read your
athlete id and token expiry. `/auth/callback` stays open for Strava's
redirect but only accepts callbacks carrying the single-use `state` nonce
minted by your own `/auth/start`, so it cannot be used to overwrite your
stored tokens with someone else's account.
### Architecture
```text
AI Tool (Claude Desktop, Claude Code, etc.)
│ HTTPS
HTTPS Tunnel (Tailscale / Cloudflare)
│ HTTP (localhost:3000)
Strava MCP Server (Docker / Bun)
│ HTTPS
Strava API
```
### Client configuration
The server works with any MCP client that supports the Streamable HTTP transport. In every
snippet below, replace `https://your-public-url` with your tunnel URL (or `http://localhost:3000`
for local development), and include the `Authorization` header only if you set `MCP_AUTH_TOKEN`.
#### Claude Code
```bash
claude mcp add --transport http strava https://your-public-url/mcp \
--header "Authorization: Bearer your-mcp-auth-token"
```
#### Cursor
Add to `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` for all projects):
```json
{
"mcpServers": {
"strava": {
"url": "https://your-public-url/mcp",
"headers": { "Authorization": "Bearer your-mcp-auth-token" }
}
}
}
```
#### VS Code
Add to `.vscode/mcp.json` in your workspace (or run **MCP: Add Server** from the command palette):
```json
{
"servers": {
"strava": {
"type": "http",
"url": "https://your-public-url/mcp",
"headers": { "Authorization": "Bearer your-mcp-auth-token" }
}
}
}
```
#### Other clients (generic Streamable HTTP)
Any client that speaks [Streamable HTTP](https://modelcontextprotocol.io/docs/concepts/transports)
can connect to the `/mcp` endpoint directly:
- POST JSON-RPC messages to `https://your-public-url/mcp` with an
`Accept: application/json, text/event-stream` header.
- If `MCP_AUTH_TOKEN` is set, also send `Authorization: Bearer <token>`
on every request.
- The `initialize` response includes an `Mcp-Session-Id` header; echo it on every
subsequent request in the same session.
## Using alongside the official Strava MCP
Strava's official MCP connector handles activity discovery and basic reads. This server supplements it with everything the official connector does not offer: writing to activities, segments, routes and GPX/TCX export, photos, derived analysis, and interactive visualizations.
### Install both
- Official: `claude mcp add --transport http strava-mcp https://mcp.strava.com/mcp` (or via claude.ai Connectors / Claude Desktop).
- This server: see the install steps above.
### Who does what
| Capability | Official | This server |
| ---------- | -------- | ----------- |
| List / read activities, streams, profile, zones, gear, clubs, training plan | yes | no (use official) |
| Update activities, star segments | no | yes |
| Segment detail / search / efforts | no | yes |
| Routes plus GPX/TCX export | no | yes |
| Activity GPX export (synthesized from streams) | no | yes |
| Activity photos | no | yes |
| Athlete stats, per-activity zones, best efforts, running summary, training load, compare | no | yes |
| Interactive chart / cadence / route-map / activity-segments apps | no | yes |
### Caveats
- The official connector requires a Strava subscription and currently runs only in Anthropic clients.
- With the duplicate reads removed, this server now effectively assumes the official connector is installed for activity discovery. The aggregate analysis tools (`get-best-efforts`, `get-training-load`) fetch their own activity lists, but per-activity tools (`get-running-summary`, `compare-activities`, `get-activity-zones`, etc.) need an activity id from the official `list_activities`.
- The two use separate rate-limit quotas, so running both spreads API load.
### Recommended workflow
Use the official connector to discover and read activities, then use this server to write, explore segments, manage and export routes, and visualize. The model can pass activity ids from official `list_activities` directly into this server's tools.
## Local Development
For running without Docker or Tailscale Funnel:
### Prerequisites
- [Bun](https://bun.sh/) runtime
- A Strava Account
### Setup
```bash
bun install
# Run the setup script for localhost-based OAuth
cd apps/server
bun run setup-auth
# Start the development server (server + MCP App watchers)
cd ../..
bun run dev
```
The setup script will guide you through the OAuth flow using `localhost` as the redirect URI.
### Configure Claude Desktop (Local)
```json
{
"mcpServers": {
"strava": {
"type": "url",
"url": "http://localhost:3000/mcp"
}
}
}
```
## Environment Variables
| Variable | Required | Description |
| ---------------------- | -------- | ---------------------------------------------------------- |
| `STRAVA_CLIENT_ID` | Yes | Your Strava Application ClienWhat people ask about strava-mcp
What is ljcl/strava-mcp?
+
ljcl/strava-mcp is mcp servers for the Claude AI ecosystem with 0 GitHub stars.
How do I install strava-mcp?
+
You can install strava-mcp by cloning the repository (https://github.com/ljcl/strava-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is ljcl/strava-mcp safe to use?
+
ljcl/strava-mcp has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.
Who maintains ljcl/strava-mcp?
+
ljcl/strava-mcp is maintained by ljcl. The last recorded GitHub activity is from today, with 51 open issues.
Are there alternatives to strava-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy strava-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/ljcl-strava-mcp)<a href="https://claudewave.com/repo/ljcl-strava-mcp"><img src="https://claudewave.com/api/badge/ljcl-strava-mcp" alt="Featured on ClaudeWave: ljcl/strava-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!