Skip to main content
Glama
julianbruegger

Strava MCP Broker

README.md
# Strava MCP Broker

An HTTP broker that exposes the [`r-huijts/strava-mcp`](https://github.com/r-huijts/strava-mcp) server over **MCP Streamable HTTP**, with per-user Strava OAuth2. Each user brings their own Strava API credentials — no shared app secrets needed.

## Quick Start (Hosted Version)

A public instance is running at **[strava-mcp.julian-bruegger.ch](https://strava-mcp.julian-bruegger.ch)**. No setup required.

1. Create a Strava API app at [strava.com/settings/api](https://www.strava.com/settings/api)
   - Set **Authorization Callback Domain** to `strava-mcp.julian-bruegger.ch`
2. Visit [strava-mcp.julian-bruegger.ch](https://strava-mcp.julian-bruegger.ch)
3. Enter your Strava **Client ID** and **Client Secret**, then click **Connect with Strava**
4. Authorize on Strava — you'll receive your personal MCP endpoint URL
5. Add the endpoint to Claude:
   - **Claude.ai**: Settings → Integrations → Add MCP server → paste the URL
   - **Claude Desktop**: Add to your `claude_desktop_config.json` (see [below](#connect-to-claude))
6. Manage your sessions anytime at [strava-mcp.julian-bruegger.ch/dashboard](https://strava-mcp.julian-bruegger.ch/dashboard)

---

## Self-Hosted Version

Host your own instance with Docker and Cloudflare Tunnel.

### Architecture

```
Claude.ai / Claude Desktop
        │  HTTPS (MCP Streamable HTTP)
        ▼
Cloudflare Tunnel
        │
        ▼
Docker: strava-mcp-broker  (Express server, port 3000)
        │  stdio JSON-RPC
        ▼
Docker: @r-huijts/strava-mcp-server  (child process per session)
        │  HTTPS
        ▼
Strava API v3
```

### Prerequisites

- A server with Docker + Docker Compose (e.g. Proxmox, VPS, Raspberry Pi)
- A domain managed by Cloudflare (free plan is fine)
- A free Cloudflare Zero Trust account ([one.dash.cloudflare.com](https://one.dash.cloudflare.com))

### Step 1 — Set Up Cloudflare Tunnel

1. Log in to [one.dash.cloudflare.com](https://one.dash.cloudflare.com)
2. Go to **Networks → Tunnels → Create a tunnel**
3. Choose **Cloudflared** as the connector type
4. Name your tunnel (e.g. `strava-mcp`)
5. On the "Install connector" page, choose **Docker** — copy the tunnel token
6. In **Public Hostname**, add a route:
   - **Subdomain**: `strava-mcp`
   - **Domain**: `yourdomain.com`
   - **Service**: `http://strava-mcp:3000` (Docker service name on the internal network)
7. Save the tunnel

### Step 2 — Configure and Deploy

```bash
git clone https://github.com/julianbruegger/strava-mcp-broker
cd strava-mcp-broker
cp env.example .env
```

Edit `.env`:

```env
PUBLIC_URL=https://strava-mcp.yourdomain.com
CLOUDFLARE_TUNNEL_TOKEN=eyJhIjoiM...   # from Step 1
SESSION_SECRET=<run: openssl rand -hex 32>
```

Deploy:

```bash
docker compose up -d --build
```

Check logs:

```bash
docker compose logs -f
```

You should see:

```
strava-mcp-broker  | Strava MCP broker running on http://0.0.0.0:3000
strava-mcp-broker  | Public URL: https://strava-mcp.yourdomain.com
strava-mcp-tunnel  | Registered tunnel connection
```

### Step 3 — Connect Your Strava Account

1. Go to [strava.com/settings/api](https://www.strava.com/settings/api) and create an app
   - Set **Authorization Callback Domain** to your tunnel domain (e.g. `strava-mcp.yourdomain.com`)
2. Open your broker URL in a browser
3. Enter your **Client ID** and **Client Secret**, then click **Connect with Strava**
4. Authorize on Strava — you'll receive your personal MCP endpoint URL

---

## Connect to Claude

### Option A — Claude.ai (recommended)

Go to **Settings → Integrations → Add MCP server** and paste your endpoint URL:

```
https://strava-mcp.yourdomain.com/mcp?session=YOUR_SESSION_TOKEN
```

### Option B — Claude Desktop

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):

```json
{
  "mcpServers": {
    "strava": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://strava-mcp.yourdomain.com/mcp?session=YOUR_SESSION_TOKEN"
      ]
    }
  }
}
```

Restart Claude Desktop. You'll see the Strava tools available.

---

## Available Tools (25+)

| Category | Tools |
|----------|-------|
| **Athlete** | `get-athlete`, `get-athlete-stats`, `get-athlete-zones` |
| **Activities** | `get-activities`, `get-activity`, `get-activity-laps`, `get-activity-streams`, `get-activity-photos`, `get-activity-comments`, `get-activity-kudoers`, `create-activity`, `update-activity`, `delete-activity` |
| **Routes** | `get-routes`, `get-route`, `list-athlete-routes`, `export-route-gpx`, `export-route-tcx` |
| **Segments** | `get-starred-segments`, `get-segment`, `get-segment-effort`, `explore-segments`, `star-segment` |
| **Clubs** | `get-clubs`, `get-club`, `get-club-activities` |
| **Gear** | `get-gear` |
| **Connection** | `connect-strava`, `disconnect-strava`, `check-connection` |

See [SKILL.md](SKILL.md) for detailed tool descriptions and usage guidelines.

---

## Dashboard

Each user gets a dashboard at `/dashboard` to manage their sessions:

- View all connected sessions
- See MCP endpoint URLs
- Delete individual sessions
- Delete all data at once

The dashboard is protected by a signed cookie set during Strava OAuth — no extra login needed.

---

## Maintenance (Self-Hosted)

### Update to latest strava-mcp-server version

```bash
docker compose build --no-cache
docker compose up -d
```

### Backup tokens

```bash
docker cp strava-mcp-broker:/data/tokens.db ./tokens-backup.db
```

---

## Security Notes

- Each user provides their own Strava API credentials — the broker stores no shared secrets
- Session tokens are random 256-bit hex strings — treat them like passwords
- Tokens are stored in SQLite at `/data/tokens.db` (mounted volume) — back it up
- Access tokens are refreshed automatically (Strava tokens expire every 6 hours)
- The `/mcp` endpoint is rate-limited (60 req/min per IP) and requires a valid session token
- Dashboard auth uses HMAC-signed cookies (30-day expiry, HttpOnly, SameSite)
- Cloudflare Tunnel handles TLS — no certificates needed on the server