Metadata-Version: 2.4
Name: tp-mcp-server
Version: 0.1.0
Summary: A Model Context Protocol server for TrainingPeaks with analytics focus
Project-URL: Homepage, https://github.com/banananovej-chuan/tp-mcp-server
Project-URL: Repository, https://github.com/banananovej-chuan/tp-mcp-server
Author: Viet Anh Chu
License: MIT
Keywords: analytics,cycling,fitness,mcp,training,trainingpeaks
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.12
Requires-Dist: browser-cookie3>=0.19.0
Requires-Dist: cryptography>=42.0.0
Requires-Dist: httpx>=0.25.0
Requires-Dist: keyring>=25.0.0
Requires-Dist: mcp[cli]>=1.4.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: dev
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest-mock>=3.12.0; extra == 'dev'
Requires-Dist: pytest>=8.3.5; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Description-Content-Type: text/markdown

# TrainingPeaks MCP Server

A [Model Context Protocol](https://modelcontextprotocol.io/) server for TrainingPeaks with an analytics focus — enabling real-time querying of training data, performance trends, CTL/ATL/TSB analysis, and training load optimization through Claude Desktop.

## Features

**13 tools** organized across 5 categories:

| Category | Tools | Description |
|----------|-------|-------------|
| Auth | `tp_auth_status`, `tp_refresh_auth` | Check/refresh authentication |
| Profile | `tp_get_profile` | Athlete profile + auto-detect ID |
| Workouts | `tp_get_workouts`, `tp_get_workout` | List and detail workouts |
| Fitness | `tp_get_fitness` | CTL/ATL/TSB with computed values |
| Peaks | `tp_get_peaks`, `tp_get_workout_prs` | Personal records by sport |
| Analytics | `tp_training_load_summary` | Weekly/monthly TSS, load ramp rate |
| | `tp_fitness_trend` | CTL trajectory, 7-day projection |
| | `tp_workout_analysis` | Efficiency factor, variability index |
| | `tp_performance_summary` | Sport-specific volume & consistency |
| | `tp_training_zones_distribution` | IF-based zone breakdown |

**Key feature**: CTL/ATL/TSB are computed from TSS using standard exponential weighted moving averages (42-day/7-day time constants), since the TP API doesn't return these values directly.

## Prerequisites

- **Python 3.12+**
- **[uv](https://docs.astral.sh/uv/)** (recommended) or pip
- **Claude Desktop** (to use the MCP server)
- A **TrainingPeaks** account with training data

## Installation

### Step 1: Clone the repository

```bash
git clone https://github.com/banananovej-chuan/tp-mcp-server.git
cd tp-mcp-server
```

### Step 2: Create a virtual environment and install dependencies

```bash
uv venv --python 3.12
uv pip install .
```

> **Note**: If you don't have `uv`, install it first: `curl -LsSf https://astral.sh/uv/install.sh | sh`

### Step 3: Get your TrainingPeaks auth cookie

This server authenticates using your browser's TrainingPeaks session cookie. Here's how to get it:

1. Open your browser and go to [trainingpeaks.com](https://trainingpeaks.com)
2. Log in to your account
3. Open **Developer Tools**:
   - **Mac**: `Cmd + Option + I`
   - **Windows/Linux**: `F12` or `Ctrl + Shift + I`
4. Click the **Application** tab (Chrome/Edge) or **Storage** tab (Firefox)
5. In the left sidebar, expand **Cookies** and click on `https://www.trainingpeaks.com`
6. Find the cookie named **`Production_tpAuth`**
7. Double-click its **Value** column and copy the entire value (it's a long string)

### Step 4: Configure the environment

```bash
cp .env.example .env
```

Open `.env` in a text editor and replace `your_cookie_value_here` with the cookie you copied:

```
TP_AUTH_COOKIE=V0014F_4tV2mrk...your_long_cookie_value...
```

### Step 5: Verify it works

```bash
uv run python -m tp_mcp_server
```

If authentication is successful, the server will start and wait for MCP connections. Press `Ctrl+C` to stop it.

## Claude Desktop Configuration

To use this server with Claude Desktop, you need to add it to Claude's MCP config file.

### 1. Find your config file

- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

If the file doesn't exist, create it.

### 2. Find your absolute path to the server

Run this command in the `tp-mcp-server` directory to get the full path:

```bash
echo "$(pwd)/.venv/bin/python"
```

This will output something like:
```
/Users/yourname/projects/tp-mcp-server/.venv/bin/python
```

### 3. Add the server config

Open the config file and add the following. **You must replace two values**:

1. Replace the `command` path with the output from step 2
2. Replace the `TP_AUTH_COOKIE` value with your cookie from the installation steps

```json
{
  "mcpServers": {
    "trainingpeaks": {
      "command": "/Users/yourname/projects/tp-mcp-server/.venv/bin/python",
      "args": ["-m", "tp_mcp_server"],
      "env": {
        "TP_AUTH_COOKIE": "your_Production_tpAuth_cookie_value"
      }
    }
  }
}
```

> **Important**: The `command` path must be an **absolute path** (starting with `/`). Do not use `~` or relative paths — Claude Desktop won't resolve them.

**Alternative** — if you have `uv` installed globally:

```json
{
  "mcpServers": {
    "trainingpeaks": {
      "command": "uv",
      "args": ["run", "--directory", "/Users/yourname/projects/tp-mcp-server", "python", "-m", "tp_mcp_server"],
      "env": {
        "TP_AUTH_COOKIE": "your_Production_tpAuth_cookie_value"
      }
    }
  }
}
```

### 4. Restart Claude Desktop

After saving the config file, fully quit and reopen Claude Desktop. You should see "trainingpeaks" listed as a connected MCP server (look for the hammer icon).

## Example Queries

Once connected in Claude Desktop, try:

- "What's my current fitness level?"
- "Show my training load trend for the last 3 months"
- "Analyze my last bike workout"
- "What are my power PRs?"
- "How is my training zone distribution this month?"
- "Compare my bike performance over the last 90 days"

## Refreshing Your Auth Cookie

The TrainingPeaks auth cookie expires periodically (typically every few days to weeks). When it expires:

1. You'll see authentication errors in Claude Desktop
2. Re-extract the cookie from your browser (repeat Step 3 from Installation)
3. Update the `TP_AUTH_COOKIE` value in both your `.env` file and Claude Desktop config
4. Restart Claude Desktop

## Architecture

```
src/tp_mcp_server/
├── server.py              # FastMCP entry point
├── mcp_instance.py        # Shared MCP instance
├── config.py              # Environment config
├── api/
│   ├── client.py          # Async httpx client, token management
│   └── endpoints.py       # API URL constants
├── auth/
│   ├── storage.py         # Cookie storage (env/keyring)
│   └── browser.py         # Browser cookie extraction
├── tools/
│   ├── auth.py            # Auth status/refresh
│   ├── profile.py         # Athlete profile
│   ├── workouts.py        # Workout list/detail
│   ├── fitness.py         # CTL/ATL/TSB data
│   ├── peaks.py           # Personal records
│   └── analytics.py       # Derived analytics
├── models/
│   ├── workout.py         # Workout models
│   ├── fitness.py         # Fitness models + CTL computation
│   ├── peaks.py           # PR models
│   └── profile.py         # Profile model
└── utils/
    ├── dates.py            # Date helpers
    └── formatting.py       # Output formatting
```

## Known Limitations

- **Internal API**: TrainingPeaks has no public API. This uses the same internal API as the web app, which could change without notice.
- **Cookie auth**: Requires periodic browser re-login to refresh the cookie.
- **Sport-level PRs**: The `/personalrecord/v2/athletes/{id}/{sport}` endpoint returns 500. PRs are aggregated from individual workouts instead.
- **CTL/ATL/TSB**: The API returns `"NaN"` for these values. They are computed locally from TSS data.
- **Rate limiting**: Requests are throttled to 150ms apart to avoid hitting TP rate limits.
