Sports Tracker MCP Server
# Sports Tracker MCP Server (Unofficial)
[](https://opensource.org/licenses/MIT)
[](https://www.python.org/downloads/)
[](https://github.com/jlowin/fastmcp)
[](https://github.com/psf/black)
[](http://mypy-lang.org/)
Ask your AI assistant about your training: workouts, VO2Max trends, training load, recovery, and lifetime stats β answered with interactive cards.
> [!IMPORTANT]
> **Unofficial Project**: This project is an independent, open-source Model Context Protocol (MCP) server. It is **not affiliated with, endorsed by, sponsored by, or associated with Sports Tracking Technologies Ltd, Amer Sports, Suunto**, or any of their affiliates or subsidiaries. All registered trademarks, product names, and company logos are the property of their respective owners.
> [!NOTE]
> **Runs locally, always.** The server talks to Sports Tracker with a session key taken from your own browser. That key is tied to your account and never leaves your machine β so there is no hosted version of this server, and there cannot be one.
---
## π Quick start
### 1. Get your session key
Log in to [Sports Tracker Web](https://www.sports-tracker.com), open DevTools (`F12` / `Cmd+Option+I`) β **Network**, refresh the page, click any request to `api.sports-tracker.com`, and copy the value of the **`STTAuthorization`** request header.
<!-- Screenshot goes here: Network tab with the STTAuthorization header highlighted. -->
> [!WARNING]
> Treat this key like a password β it grants full access to your Sports Tracker account. Never paste it into an issue, a gist, or a shared config. It also **expires**: when tools start failing with an authentication error, repeat this step to get a fresh one.
### 2. Add the server
**Claude Code** β one command:
```bash
claude mcp add sports-tracker -e STT_SESSION_KEY=your_session_key_here \
-- uvx --from git+https://github.com/wilkar/sports-tracker-mcp sport-tracker-mcp
```
**Claude Desktop** β add to `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows: `%APPDATA%\Claude\claude_desktop_config.json`):
```json
{
"mcpServers": {
"sports-tracker": {
"command": "uvx",
"args": ["--from", "/path/to/the/repo", "sport-tracker-mcp"],
"env": {
"STT_SESSION_KEY": "your_session_key_here"
}
}
}
}
```
**Cursor / Antigravity** β add the same JSON block to your MCP settings (`mcp_config.json`).
Nothing to clone and no virtualenv to manage: [uv](https://github.com/astral-sh/uv) fetches and runs the server on demand. If your client reports `uvx: command not found`, use the absolute path from `which uvx` (e.g. `/opt/homebrew/bin/uvx`).
### 3. Ask it something
> *"How far did I run in the last 7 days?"*
That's it. If you get an answer, you're done.
---
## π οΈ Available MCP Tools
| Tool | UI Card | Description | Parameters |
| :--- | :---: | :--- | :--- |
| `get_recent_workouts` | β
| Fetch recent workouts with interactive sport and limit filters, clickable workout rows, and metrics. | `limit` (default: 10, supports 5, 10, 25, 'all'), `imperial` (default: false), `sport` (optional) |
| `get_workout_details` | β
| In-depth workout analysis with interactive time series charts (HR, altitude, speed), HR zones, ascent/descent, and Suunto extensions. | `workout_key` (required), `imperial` (default: false) |
| `get_training_load_and_recovery` | β
| Recovery gauge, cumulative recovery hours, TSS, PTE, and EPOC metrics. | *None* |
| `get_training_summary` | β
| Aggregated volume, distance, time, and calories across sports for the past *N* days. | `days` (default: 7), `imperial` (default: false) |
| `get_vo2_max_history` | β
| Aerobic capacity (VO2Max) trendline and fitness age progression extracted from workouts. | `limit` (default: 20) |
| `get_user_stats` | β
| Lifetime aggregate statistics and per-sport totals (distance, duration, calories, count). | `username` (optional), `imperial` (default: false) |
| `get_recent_activities_summary` | β
| Breakdown of sport frequency, total duration, and last performed dates over the past *N* days with interval selector. | `days` (default: 14) |
| `get_social_feed` | β (data-only) | Retrieve feed items from followed athletes or community members. | `limit` (default: 10), `imperial` (default: false) |
Cards render as interactive HTML in hosts that support MCP Apps (`io.modelcontextprotocol/ui`); every tool also returns plain structured data, so clients without UI support lose nothing.
### More things to ask
- *"How much running and cycling have I logged over the past 14 days? Break it down by distance, time, and pace."*
- *"Give me a detailed breakdown of my latest workout, including heart rate zones, elevation gain, and Suunto metrics in imperial units."*
- *"What is my current recovery time, TSS, and EPOC? Am I ready for a tempo run today?"*
- *"Plot my VO2Max and fitness age progression over my last 20 workouts."*
---
## βοΈ Configuration reference
| Variable | Required | Default | Description |
| :--- | :--- | :--- | :--- |
| `STT_SESSION_KEY` | **Yes** | β | Your session token (the `STTAuthorization` header). |
| `STT_BASE_URL` | No | `https://api.sports-tracker.com/apiserver/v1` | Sports Tracker API base endpoint. |
Pass both through your MCP client's `env` block (as in [Quick start](#2-add-the-server)); the server reads them from the process environment at startup.
> [!NOTE]
> **On `STT_BASE_URL`**: your session token is sent as a header to whatever host this names. Leave it at the default unless you are deliberately pointing at a trusted local debugging proxy.
---
## π§βπ» Development
```bash
git clone https://github.com/wilkar/sports-tracker-mcp.git
cd sports-tracker-mcp
uv sync
```
Run the server from the clone:
```bash
STT_SESSION_KEY="your_key" uv run sport-tracker-mcp
# or keep it in a local .env (cp .env.example .env):
uv run --env-file .env sport-tracker-mcp
```
Point an MCP client at your working copy by swapping the `--from` target for an absolute path:
```bash
claude mcp add sports-tracker-dev -e STT_SESSION_KEY=your_key \
-- uvx --from /absolute/path/to/sports-tracker-mcp sport-tracker-mcp
```
Tests, types and formatting:
```bash
uv run pytest
uv run mypy .
uv run isort --check .
uv run black --check .
```
Inspect the tool schemas:
```bash
uv run fastmcp list src/sport_tracker_mcp/server.py
uv run fastmcp dev inspector src/sport_tracker_mcp/server.py
```
### Project structure
```text
src/sport_tracker_mcp/
βββ client.py # Async HTTP client with TTL cache & error handling
βββ config.py # Environment variable resolution
βββ constants.py # Activity ID mappings
βββ formatting.py # Unit conversions (metric/imperial), pace, duration
βββ models.py # Pydantic schemas for workouts, stats, load & recovery
βββ server.py # FastMCP server, tool registration & UI cards
βββ tools.py # Tool implementations
βββ ui.py # HTML rendering for tool-result cards
```
---
## πΊοΈ Roadmap
- [ ] **`get_routes`**: List saved and recorded GPS routes with distances, speeds, and activity types.
- [ ] **`get_route_details`**: GPS track waypoints, elevation profiles, and polyline coordinates for a route.
- [ ] **`export_workout_gpx`**: Download standardized GPX XML track files for activities.
- [ ] **`get_user_following`**: Retrieve followers and followed athlete profiles.
---
## π License
This project is licensed under the [MIT License](LICENSE).
TDQS
Scored across 8 tools
Most tools have clearly distinct purposes: social feed, workout lists, detailed workout metrics, user stats, VO2Max history, and recovery are easy to tell apart. The only mild ambiguity is between get_training_summary and get_recent_activities_summary, since both aggregate data over the past N days, though their metric focus differs.
All tools follow a consistent get_<noun_phrase> snake_case pattern, making the set predictable and easy to navigate. There are no mixed conventions or vague verbs.
Eight tools is well-scoped for a read-only sports tracking analytics server. Each tool represents a meaningful query surface without unnecessary redundancy or overwhelming breadth.
The read-only query surface is quite complete for analytics: recent workouts, detailed workout metrics, summaries, user stats, VO2Max history, recovery, and social feed are all covered. The main gap is the total absence of write operations like logging a workout or updating user data, though that may be acceptable if the server is intended only as a data retrieval layer.