Skip to main content
Glama
esowder22

Strava MCP Server

by esowder22
README.md
# Strava MCP Server

A small, **read-only** [Model Context Protocol](https://modelcontextprotocol.io)
server that gives Claude live access to your personal Strava data — activities,
splits, heart-rate/pace streams, zones, and lifetime totals — so it can coach
off your real training instead of manual exports.

Runs in Strava "single-player mode": it only ever connects **your own** account.

## What it exposes

All tools are reads. The server never creates, edits, or deletes anything on Strava.

| Tool | What it returns |
|------|-----------------|
| `get_athlete` | Your profile (name, location, weight, FTP if set) |
| `get_stats` | Lifetime, YTD, and last-4-weeks totals per sport |
| `list_activities` | Recent activities, paginated, with optional date filters |
| `get_activity` | Full detail for one activity (splits, pace, HR, power, elevation) |
| `get_activity_streams` | Time-series streams for detailed analysis |
| `get_athlete_zones` | Configured heart-rate and power zones |

## Prerequisites

- Python 3.10+
- A Strava account **with an active subscription** (required to create an API app)

## Setup

### 1. Create a Strava API application

1. Go to <https://www.strava.com/settings/api>.
2. Create an app. Set **Authorization Callback Domain** to `localhost`.
3. Note your **Client ID** and **Client Secret** (keep the secret private).

### 2. Install

```bash
git clone <your-repo-url> strava-mcp-server
cd strava-mcp-server
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
```

### 3. Configure credentials

```bash
cp .env.example .env
# edit .env: set STRAVA_CLIENT_ID and STRAVA_CLIENT_SECRET
```

### 4. Authorize (one time) to get a refresh token

```bash
python scripts/get_token.py
```

This opens your browser, catches the redirect on `localhost`, exchanges the code,
and prints a `STRAVA_REFRESH_TOKEN=...` line. Paste it into `.env`.

### 5. Register the server with Claude

**Claude Code** — copy `mcp.example.json` to `.mcp.json` in the repo root (adjust
the `python` path to your venv, e.g. `.venv/bin/python`, if needed), then start
Claude Code from this directory. Approve the server when prompted.

**Claude Desktop** — add the `strava` block from `mcp.example.json` to your
`claude_desktop_config.json` under `mcpServers`, using absolute paths:

```json
{
  "mcpServers": {
    "strava": {
      "command": "/absolute/path/to/strava-mcp-server/.venv/bin/python",
      "args": ["-m", "strava_mcp.server"],
      "cwd": "/absolute/path/to/strava-mcp-server"
    }
  }
}
```

Restart Claude Desktop. You should see the Strava tools appear.

### 6. Sanity check

```bash
python -m strava_mcp.server   # should start and wait on stdio; Ctrl-C to exit
```

## Security model

- **No secrets in git.** `.env`, `.strava_tokens.json`, and key files are
  gitignored. Only `.env.example` is tracked.
- **Read-only scope.** The app requests `read`, `activity:read_all`, and
  `profile:read_all` — no write scopes. The server issues only GET requests to
  data endpoints.
- **Token hygiene.** Access tokens (6-hour lifetime) are refreshed automatically
  from your refresh token. Strava rotates the refresh token on each exchange; the
  server persists the current one to `.strava_tokens.json` (chmod `600`,
  gitignored).
- **Rate limits.** Honors Strava's 200 req / 15 min and 2,000 / day limits with
  automatic backoff on HTTP 429.
- **Revoking access.** Remove the app anytime at
  <https://www.strava.com/settings/apps>. Delete `.strava_tokens.json` and `.env`
  to purge local credentials.

## Publish to GitHub

From the repo root (secrets are already gitignored, so this is safe):

The GitHub repo already exists at <https://github.com/esowder22/strava-mcp-server>,
so just wire up the remote and push:

```bash
git init
git add .
git status                     # confirm .env / .strava_tokens.json are NOT listed
git commit -m "Initial commit: read-only Strava MCP server"
git branch -M main
git remote add origin git@github.com:esowder22/strava-mcp-server.git
git push -u origin main
```

Prefer HTTPS over SSH? Use
`git remote add origin https://github.com/esowder22/strava-mcp-server.git` instead.

If the GitHub repo was created with a README/license and the push is rejected,
run `git pull --rebase origin main` once, then push again. Keep the repo
**private** — even though no secrets are committed, there's no reason to make it
public.

## Compatibility note

Written for the current `mcp` 2.x SDK (where `FastMCP` is `MCPServer`), with a
fallback import so it also runs on `mcp` 1.x. No code change needed either way.

## License

MIT — see [LICENSE](LICENSE).

TDQS

A4.2/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a clearly distinct resource or granularity: athlete profile, aggregate stats, activity list, activity detail, time-series streams, and zones. The only close pair, get_activity and get_activity_streams, is cleanly separated by summary detail vs. raw time-series data.

Naming Consistency5/5

All tool names follow a consistent verb_noun snake_case pattern, with five using get_ and one using list_activities. The lone list_ is still a standard retrieval verb, so the naming stays predictable and coherent.

Tool Count5/5

Six tools is a well-scoped size for a read-only Strava analytics server. Each tool covers a distinct part of the activity/athlete data surface without unnecessary duplication or bloat.

Completeness5/5

For the apparent purpose of retrieving athlete and activity data, the surface is complete: profile, aggregate stats, activity listing, detailed activity, streams, and zones. There are no dead ends for common queries like 'how fast was my last ride?' or 'what are my power zones?'

Maintenance

ActivityMaintained
ResponsivenessNo issues