Trainingpeaks
MCP server for programmatic access to your TrainingPeaks data
Ask AI about Trainingpeaks
Powered by Claude Β· Grounded in docs
I know everything about Trainingpeaks. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
trainingpeaks-mcp
An MCP (Model Context Protocol) server for accessing your TrainingPeaks training data. Works with Claude Desktop, ChatGPT, and other MCP-compatible clients.
Features
- 20 tools for accessing workouts, strength workouts, fitness metrics, peaks/PRs, power analysis, aerobic decoupling, workout plan compliance, ZWO workout generation, files, cache management, and date resolution
- FIT file caching: Downloaded FIT files are cached to disk (
~/.trainingpeaks-mcp/cache/fit/) β eliminates redundant downloads across sessions - Dual transport: stdio for Claude Desktop, HTTP for ChatGPT
- FIT file parsing: Extract structured data from downloaded FIT files
- Also usable as a standalone TypeScript library
Quick Start
One-Click Install (Claude Desktop)
- Download the latest
.mcpbfile from Releases - Double-click the
.mcpbfile β Claude Desktop will open and prompt you to install - Enter your TrainingPeaks credentials when prompted
That's it β no Node.js installation required. Claude Desktop bundles its own runtime.
Manual Configuration (Claude Desktop)
Requires Node.js 20+. Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"trainingpeaks": {
"command": "npx",
"args": ["trainingpeaks-mcp"],
"env": {
"TP_USERNAME": "your-email@example.com",
"TP_PASSWORD": "your-password"
}
}
}
}
Restart Claude Desktop. You can now ask Claude about your training data!
ChatGPT (via HTTP)
Requires Node.js 20+.
-
Clone and install:
git clone https://github.com/robertgregorywest/trainingpeaks-mcp.git cd trainingpeaks-mcp npm install -
Create
.envfile with your credentials:cp .env.example .env # Edit .env with your TrainingPeaks credentials -
Build and start the HTTP server:
npm run build npm run start:httpYou should see:
TrainingPeaks MCP HTTP server running on port 3000 -
Install ngrok (if not already installed):
macOS (Homebrew):
brew install ngrokWindows (Chocolatey):
choco install ngrokOr download directly from: https://ngrok.com/download
-
Create a free ngrok account and get your auth token:
- Sign up at https://dashboard.ngrok.com/signup
- Copy your auth token from https://dashboard.ngrok.com/get-started/your-authtoken
- Configure ngrok with your token:
ngrok config add-authtoken YOUR_AUTH_TOKEN
-
Start ngrok to expose your local server (in a new terminal):
ngrok http 3000ngrok will display output like:
Forwarding https://abc123.ngrok-free.app -> http://localhost:3000Copy the
https://...ngrok-free.appURL. -
Add the MCP connector in ChatGPT:
- Go to ChatGPT Settings β Connectors β Add Connector
- Enter your ngrok URL with
/mcppath:https://abc123.ngrok-free.app/mcp - Save the connector
-
Test by asking ChatGPT about your TrainingPeaks data!
Available Tools
| Tool | Description |
|---|---|
get_user | Get user profile including athlete ID |
get_athlete_id | Get just the athlete ID |
get_workouts | List workouts in a date range |
get_workout | Get single workout summary |
get_workout_details | Get workout with full metrics, intervals, laps, zones |
search_workouts | Search workouts by title (case-insensitive) within a number of days |
compare_intervals | Compare laps/intervals side-by-side across workouts with power/duration filters |
get_strength_workouts | Get strength workouts in a date range (sets, blocks, exercises, compliance) |
parse_fit_file | Parse FIT file and extract structured data |
get_fitness_data | Get CTL/ATL/TSB for date range |
get_current_fitness | Get today's fitness metrics |
get_peaks | Get peaks for specific sport and type |
get_workout_peaks | Get PRs from specific workout |
get_best_power | Compute best power from raw FIT file for arbitrary durations (e.g., 3min, 8min, 45min) |
get_power_duration_curve | Build a power-duration curve across cycling workouts in a date range |
get_aerobic_decoupling | Calculate aerobic decoupling (Pw:Hr) from a workout β measures cardiac drift |
assess_compliance | Assess workout plan compliance β compares prescribed plan against actual activity with per-step and summary metrics |
build_zwo_workout | Build a Zwift .zwo workout file from structured segments (warmup, intervals, steady, ramp, cooldown, freeride) |
clear_fit_cache | Clear all cached FIT files downloaded from TrainingPeaks |
get_current_date | Get current date in ISO, US, EU, or custom format |
Example Prompts
- "What workouts did I do last week?"
- "Show me my current fitness (CTL, ATL, TSB)"
- "What are my best 5-minute power efforts?"
- "Get details for my most recent ride including heart rate zones"
- "Download and parse the FIT file from yesterday's ride"
- "Search for all my tempo workouts in the last 30 days"
- "Compare the intervals across my last 3 threshold rides"
- "What's my best 3-minute and 8-minute power from yesterday's ride?"
- "Build my power-duration curve for the last 6 weeks"
- "What's the aerobic decoupling for my last long ride?"
- "How well did I follow the plan for yesterday's ride?"
- "Create a 5x5 VO2max workout at 300W with 50% FTP recovery for Zwift"
- "Build me a sweet spot session with 3x10min at 220W"
- "What is today's date?"
Environment Variables
Create a .env file from the example:
cp .env.example .env
Then edit .env with your TrainingPeaks credentials:
TP_USERNAME=your-email@example.com
TP_PASSWORD=your-password
| Variable | Description | Optional |
|---|---|---|
TP_USERNAME | TrainingPeaks email address | No |
TP_PASSWORD | TrainingPeaks password | No |
PORT | HTTP server port (default: 3000) | Yes |
TP_TEST_BIKE_WORKOUT_ID | Bike workout ID with FIT file, power, and HR data (for integration tests) | Yes |
Library Usage
You can also use this package as a standalone TypeScript library:
import { createClient } from "trainingpeaks-mcp";
const client = createClient();
// Get workouts for a date range
const workouts = await client.getWorkouts("2024-01-01", "2024-12-31");
// Get workout details with metrics
const details = await client.getWorkoutDetails(workouts[0].workoutId);
console.log(details.metrics);
// Get current fitness
const fitness = await client.getCurrentFitness();
console.log(`CTL: ${fitness.ctl}, ATL: ${fitness.atl}, TSB: ${fitness.tsb}`);
// Build a power-duration curve from the last 6 weeks of rides
const curve = await client.getPowerDurationCurve({
startDate: "2024-11-01",
endDate: "2024-12-15",
});
console.log(curve.curve.map((p) => `${p.durationLabel}: ${p.bestPowerWatts}W`));
// Aerobic decoupling analysis
const decoupling = await client.getAerobicDecoupling(workouts[0].workoutId);
console.log(
`Decoupling: ${decoupling.decouplingPercent}% β ${decoupling.interpretation}`,
);
// Workout plan compliance assessment
const compliance = await client.assessCompliance(workouts[0].workoutId);
console.log(
`Plan compliance: ${compliance.overallCompliance.powerComplianceAvg}%`,
);
// Clean up when done
await client.close();
Development
npm run build # Compile TypeScript
npm run lint # Run ESLint
npm run test # Run unit tests
npm run typecheck # Type-check without emitting
Integration Tests
Integration tests make real API calls to TrainingPeaks to verify all endpoints work correctly.
Prerequisites:
- Create
.envfile with your TrainingPeaks credentials (see Environment Variables)
Run integration tests:
npm run test:integration
What's tested:
- User API:
getUser,getAthleteId - Workouts API:
getWorkouts,getWorkout,getWorkoutDetails - Fitness API:
getCurrentFitness,getFitnessData - Peaks API:
getPeaks,getWorkoutPeaks - Files API:
downloadActivityFile
Tests are skipped automatically if credentials are not available.
How It Works
This library uses Playwright to automate browser login to TrainingPeaks, capturing the authentication token from API requests. The token is then used for subsequent API calls.
License
MIT
