_ registry / mcp streamable-http · checked 35m ago

TriPeak TSS Coach

https://tripeak.app

Registry code: 2a722137a0de47bd

api record

TriPeak is an endurance coaching platform: swim, bike, run, brick, strength and more, planned in TSS and tracked as fitness (CTL), fatigue (ATL) and form (TSB). Dates are YYYY-MM-DD. Two kinds of connection. A coach connection sees a roster and can plan for every athlete on it; somebody who coaches themselves is the coach of one athlete, and athlete_id may then be omitted. An athlete connection (a personal link from their coach) sees one plan: read it, log how sessions felt, add a race, update thresholds. A coach can run the whole practice from here, as in the app: add_athlete and…

endpoint
https://tripeak.app/mcp/v1
protocol
streamable-http ·2025-06-18
authentication
none observed
public key
none — nobody has proven they own this listing · is it yours? claim it
karma
0 · newcomer
_ is it live, free and safe measured by this hub
Is TriPeak TSS Coach live?
Yes — it answered the hub's last check (checked 35m ago). It answered 100% of checks over the last 30 days.
Is TriPeak TSS Coach free to use?
Yes — the hub reached it with no key and no payment.
What tools does TriPeak TSS Coach have?
49 tools: update_athlete, get_athlete_links, dismiss_threshold_finding, update_workout, list_athletes, sync_device, disconnect_device, get_upload_token, ….
Is TriPeak TSS Coach safe to connect?
The hub found no text in its card or tool descriptions aimed at the agent reading them. It measures what the server answers, not its code — grant it only the access its tools need.
reachable
live
uptime, 30 days
99.6%

90 days 99.3%· all time 99.3%

latency
779ms

last good check

priced tools
0

of 49 tools

_ answered our checks, 90 days 443 checks · signed record
  • degraded → live
  • live → degraded· timeout after 20000ms
  • degraded → live
  • degraded → live
  • live → degraded· timeout after 20000ms
_ what it is for
used for
  • plan endurance training weeks in tss
  • track athlete fitness and fatigue
  • analyze a completed workout
  • push planned workouts to garmin
  • review an athlete's weekly training
takes → gives
text, data → data, text
tools
13 reads11 changes data
_ usage and payments 30 days

Calls placed through this hub's router, from its own receipts. Every caller and every payer counts the same; the chain total is counted from three payers.

accounts
0

through this hub

calls served
0

successful

paid through this hub
0 USDC

what callers paid

_ what it can do 49 tools
1 open 48 never probed 1 of 49 classified

Price is per tool, not per server. An agent whose handshake is open can hold tools that demand a key or a payment, and one figure for the whole agent sends callers into a wall.

  • search reads open 14d ago

    Search the roster and the training plans for athletes, sessions and races matching a query. Returns ids to pass to fetch. Use it when you do not already have an athlete id.

    mcp-tool

    {
      "type": "object",
      "required": [
        "query"
      ],
      "properties": {
        "query": {
          "type": "string",
          "description": "Free text: an athlete name, a session title, a sport, or a date (YYYY-MM-DD)."
        }
      }
    }
    arguments 12 lines
  • update_athlete changes data unknown never probed

    Update an athlete's profile: name, email, bio, coach notes, thresholds (partial update, e.g. just ftpWatts), the target_races list, `email_opt_out` (true stops TriPeak's emails to them, as the profile's switch does), or `rules_json` — checked rules that apply to this athlete alone. target_races is replaced whole: send every race, not only the changed one. To change one race (a priority, a date) use update_goal_race instead. A field it does not know is refused, never ignored.

    mcp-tool

    {
      "type": "object",
      "required": [
        "patch"
      ],
      "properties": {
        "patch": {
          "type": "object",
          "description": "Fields to change. thresholds is a partial object, only the keys sent change (null clears one); its keys: ftpWatts (bike FTP, watts), weightKg (weight, kg), cssPaceSec100m (swim CSS, seconds per 100 m), runThresholdPaceSecKm (run threshold pace, seconds per km), maxHr (max heart rate, bpm), restingHr (resting heart rate, bpm), lthr (lactate threshold heart rate, bpm), cdA (aero drag area, m² (0.20–0.40)), crr (rolling resistance (0.0035–0.005)), carbsPerHour (race carb target, g/h), sex (\"male\" or \"female\"), birthYear (year of birth), poolLengthM (pool length, m (25 when unset)), wPrimeJ (W′, joules (15000–25000)). philosophy sets the coaching approach their weeks are planned under: polarised, pyramidal, threshold, sweetspot, aerobic-base or reverse (null for the app default). Writing a philosophy of the coach's own is set_training_philosophy, which validates it and selects it in one write; philosophy_custom is settable here too but has no effect on its own, because the document is only read when philosophy is 'custom'. Read tripeak://guide/philosophies before changing it — it is the coach's call, not a setting to tidy. rules_json holds the rules that are true about this athlete alone — \"swims Tuesday and Thursday when the lane is free\", \"no more than two hard days a week\" — in the same vocabulary as the coach's house rules (tripeak://guide/house-rules), and they are checked alongside them on every week written. Replaced whole, like the house rules: read the current list first. A rule that holds across the whole roster belongs in set_coaching_rules instead of being repeated on every athlete; something true about the person but not checkable — \"knee has been sore since June\" — belongs in notes."
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 16 lines
  • get_athlete_links reads unknown 14d ago

    Get the links to send an athlete: their web portal share link and their personal MCP connector URL (for connecting Claude or ChatGPT to their own plan).

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 10 lines
  • dismiss_threshold_finding unknown never probed

    Dismiss a threshold suggestion the coach has decided against — "FTP looks like 262 W, not 250" when they know the test ride was a one-off — as the profile's Dismiss does. It stops counting toward the athlete's attention and stops appearing in the bell, until the evidence moves to a different number. Pass the finding as list_athletes' attention.thresholdAudit or get_weekly_review's threshold_audit gives it (metric, direction, current, suggested).

    mcp-tool

    {
      "type": "object",
      "required": [
        "finding"
      ],
      "properties": {
        "finding": {
          "type": "object",
          "required": [
            "metric",
            "direction",
            "current"
          ],
          "properties": {
            "metric": {
              "type": "string"
            },
            "current": {
              "type": "number"
            },
            "direction": {
              "type": "string"
            },
            "suggested": {
              "type": "number"
            }
          }
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 34 lines
  • update_workout unknown never probed

    Change one or more fields of one session and nothing else: its sport (an inline skate that was roller skiing), title, date, description, structure, duration_min, planned_tss, intensity, status or coach_feedback — and the check-in a coach fills in for an athlete who told them by message: rpe, athlete_notes, completed_tss. day_order is its place in the day (0 first), what dragging it above another session sets. The recording and every field not named stay as they are. Use this rather than create_workouts to correct an existing session: create_workouts replaces the whole row. A field it does not know is refused, never ignored.

    mcp-tool

    {
      "type": "object",
      "required": [
        "workout_id",
        "patch"
      ],
      "properties": {
        "patch": {
          "type": "object",
          "properties": {
            "rpe": {
              "type": "integer",
              "maximum": 10,
              "minimum": 1,
              "description": "How hard it felt, 1–10, as the athlete said"
            },
            "date": {
              "type": "string",
              "description": "YYYY-MM-DD"
            },
            "sport": {
              "enum": [
                "swim",
                "bike",
                "run",
                "brick",
                "xcski",
                "rollski",
                "inlineskate",
                "strength",
                "other",
                "rest",
                "transition"
              ],
              "type": "string",
              "description": "xcski is cross-country skiing on snow, rollski roller skiing, inlineskate inline skating; all three are scored on heart rate."
            },
            "title": {
              "type": "string"
            },
            "status": {
              "enum": [
                "planned",
                "completed",
                "missed",
                "proposed"
              ],
              "type": "string",
              "description": "Use \"proposed\" for drafts the coach must approve — invisible to the athlete and outside the load model until accepted."
            },
            "day_order": {
              "type": "integer",
              "minimum": 0,
              "description": "Place in the day: 0 first"
            },
            "intensity": {
              "enum": [
                "recovery",
                "aerobic",
                "tempo",
                "sweetspot",
                "threshold",
                "vo2max",
                "anaerobic"
              ],
              "type": "string"
            },
            "structure": {
              "type": "string",
              "description": "The session itself, one block per line or comma — for every sport, not just the bike. duration_min and planned_tss are READ OUT OF THIS and overwritten, so do not also send them. The first line may be the session's name (\"VO2 max intervals\"); it becomes the title when none is sent. Amounts: 20' or 20min = minutes, 90s = seconds, 4:00 = min:sec, 400m and 5km = distance (m is METRES, never minutes). Targets are a fraction of that sport's threshold and always point the same way — 105% is harder in every sport, meaning 105% of threshold SPEED for run and swim. Also @ 300W, @ 4:00/km, @ 1:35/100m, @ CSS+3, and in any sport a heart rate: @ 140-150bpm, @ 85% LTHR, @ 75% HRmax (needs the athlete's LTHR or max HR; the watch gets a heart-rate target and the session is graded on heart rate). A DASH IS A RANGE to stay inside, in every unit: 88-92%, 290-310W, 3:55-4:05/km, 135-148bpm. A RAMP SAYS ramp: warmup 20' ramp 45-65% starts at 45% and ends at 65% (heart rate never ramps). Write ramp in warm-ups and cool-downs that build or ease, almost never in a rep; for a steady effort ONE value is clearest (@ 3:22/km). Repeats nest: 4x(12' @ 91%, 4' @ 50%); always state the recovery. \"20s rest\" is stopped rest. In a brick, a line reading just \"bike\" or \"run\" switches leg. Unparsable structures are rejected, so read tripeak://guide/interval-notation first. Examples: \"warmup 20' ramp 45-65%\\n4x(12' @ 91%, 4' @ 50%)\\ncooldown 10' ramp 60-40%\" and \"warmup 15' ramp 45-65%\\n6x(4' @ 3:22/km, 2' jog @ 60%)\\ncooldown 10' ramp 60-40%\"."
            },
            "description": {
              "type": "string"
            },
            "planned_tss": {
              "type": "number"
            },
            "duration_min": {
              "type": "number"
            },
            "athlete_notes": {
              "type": "string",
              "description": "The athlete's own words on the session"
            },
            "completed_tss": {
              "type": "number",
              "description": "TSS done, for a session with no recording"
            },
            "coach_feedback": {
              "type": "string"
            }
          },
          "description": "The fields to change, e.g. {\"sport\": \"rollski\"} or {\"date\": \"2026-10-20\", \"title\": \"Moved: Rollski GA1\"}."
        },
        "workout_id": {
          "type": "string"
        }
      }
    }
    arguments 99 lines
  • list_athletes reads unknown 14d ago

    List all athletes in your coaching roster with thresholds (FTP, CSS, run pace, HR), goal races, current training load (CTL/ATL/TSB, computed live), and an attention summary per athlete (flags such as missed sessions, ramp rate, deep fatigue, race-outlook problems, stale Garmin sync, nothing planned). Sorted by who needs attention most.

    mcp-tool

    {
      "type": "object",
      "properties": {}
    }
    arguments 4 lines
  • sync_device unknown never probed

    Pull an athlete's recent activities from one connected platform now, as the Connections panel's Sync does — garmin, wahoo, polar, coros or intervals. Matches them onto the plan the same way the nightly sync does. pull_garmin_activities is the Garmin one with more options.

    mcp-tool

    {
      "type": "object",
      "required": [
        "provider"
      ],
      "properties": {
        "days": {
          "type": "integer",
          "description": "How far back. Default 30."
        },
        "provider": {
          "enum": [
            "garmin",
            "wahoo",
            "intervals",
            "polar",
            "coros"
          ],
          "type": "string"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 26 lines
  • disconnect_device unknown never probed

    Forget an athlete's connection to one platform. The sessions already synced stay on the plan; what goes is the stored authorisation, and the nightly sync with it. Reconnecting needs the athlete (list_connections gives the link).

    mcp-tool

    {
      "type": "object",
      "required": [
        "provider"
      ],
      "properties": {
        "provider": {
          "enum": [
            "garmin",
            "wahoo",
            "intervals",
            "polar",
            "coros"
          ],
          "type": "string"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 22 lines
  • get_upload_token unknown never probed

    The token an athlete's upload app (HealthFit or RunGap on an Apple Watch, a phone Shortcut, curl) sends FIT files with, and the address it sends them to — as the Connections panel's "Upload from other apps" shows. rotate_upload_token replaces it.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 10 lines
  • rotate_upload_token unknown never probed

    Replace an athlete's upload token, as the Connections panel's "New token" does: the old one stops working at once, so the app that uploads needs the new one.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 10 lines
  • upload_activity_file unknown never probed

    Put a FIT file on an athlete's plan, as dropping it on the app's calendar does: it is read, priced in TSS from their thresholds, matched onto the session planned for that day (or added as an extra), and its recording kept so get_session_analysis and grade_session work on it. FIT only, as base64.

    mcp-tool

    {
      "type": "object",
      "required": [
        "file_base64"
      ],
      "properties": {
        "file_name": {
          "type": "string"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "file_base64": {
          "type": "string",
          "description": "The .fit file, base64-encoded"
        }
      }
    }
    arguments 19 lines
  • get_intensity_distribution reads unknown 14d ago

    How an athlete's training time is actually distributed across the three intensity zones, planned and completed, measured against the target their training philosophy sets, with Treff's polarisation index beside each split and the completed weeks one by one (hours, split, index, fit — the app's weekly distribution card). Sessions with a structure are counted block by block, so warmups, recoveries and swim rests land where they belong rather than being assumed; sessions without one are estimated from their label and reported separately. Use it after drafting a week to check the week against the philosophy rather than by eye, and over a longer window to see what the athlete has really been doing.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "to": {
          "type": "string",
          "description": "YYYY-MM-DD, inclusive."
        },
        "from": {
          "type": "string",
          "description": "YYYY-MM-DD, inclusive. Omit for the whole plan."
        },
        "scope": {
          "enum": [
            "planned",
            "completed",
            "both"
          ],
          "type": "string",
          "description": "Default both."
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 27 lines
  • get_session_streams reads unknown 14d ago

    Get the recorded metric streams of one completed session, whichever platform recorded it (parallel arrays: t = seconds from start, hr, speed m/s, elevation m, cumulative distance m, power W, and running dynamics where recorded), one sample every five seconds unless asked otherwise. Pass the session's workout_id; activity_id (the recording id) works too. To find a stretch — the slowest km, the 30 minutes with the lowest power — use find_session_windows.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "every": {
          "type": "number",
          "description": "Seconds between samples. Default 5; 1 for the raw recording."
        },
        "fields": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Which arrays: hr, speed, elevation, distance, power, cadence, lat, lon… All by default; t always."
        },
        "to_sec": {
          "type": "number",
          "description": "Window end."
        },
        "from_sec": {
          "type": "number",
          "description": "Window start, seconds from the start of the recording."
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "workout_id": {
          "type": "string",
          "description": "The session; its recording is found for you."
        },
        "activity_id": {
          "type": "string",
          "description": "Or the recording itself, e.g. \"garmin-24163033258\", \"intervals-i193392819\"."
        }
      }
    }
    arguments 37 lines
  • find_session_windows unknown 14d ago

    Find the stretch of a session's recording that stood out, wherever it began: the slowest kilometre of a run, the fastest 5 km, the 30 minutes of a ride with the lowest power, the 10 minutes with the highest heart rate. A window of a distance or a duration is slid across the whole recording sample by sample (not the watch's splits or laps), ranked by pace, speed, power, heart rate or cadence. Each stretch comes back with where it starts and ends (seconds and metres from the start), its pace, speed, average power, heart rate and cadence, and the climbing in it. Times include any stops inside the stretch.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "pick": {
          "enum": [
            "slowest",
            "fastest",
            "lowest",
            "highest"
          ],
          "type": "string",
          "description": "Which end. slowest = lowest = the minimum; fastest = highest = the maximum. Default slowest."
        },
        "count": {
          "type": "number",
          "description": "How many stretches, none overlapping. Default 1, at most 10."
        },
        "metric": {
          "enum": [
            "pace",
            "speed",
            "power",
            "hr",
            "cadence"
          ],
          "type": "string",
          "description": "What to rank the stretches by. Default pace."
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "distance_m": {
          "type": "number",
          "description": "Window by distance, e.g. 1000 for a kilometre. Give this or duration_sec."
        },
        "workout_id": {
          "type": "string",
          "description": "The session; its recording is found for you."
        },
        "activity_id": {
          "type": "string",
          "description": "Or the recording itself."
        },
        "duration_sec": {
          "type": "number",
          "description": "Window by time, e.g. 1800 for 30 minutes."
        }
      }
    }
    arguments 51 lines
  • add_life_event changes data unknown never probed

    Put a life event on an athlete's calendar: a night shift, a wedding, a week of travel, a cold. Not a session — it carries no load — but a reason the days it covers cannot hold normal training. impact says what still fits: no_training (nothing), easy_only (no quality), short_only (nothing over about 75 minutes), tired (as planned, but do not stack quality the next day). The plan response carries the events as life_events beside the sessions, and audit_plan holds a drafted week against them. Athletes can add their own from their portal or their own connector.

    mcp-tool

    {
      "type": "object",
      "required": [
        "starts_on",
        "kind",
        "impact",
        "title"
      ],
      "properties": {
        "kind": {
          "enum": [
            "work",
            "travel",
            "illness",
            "family",
            "other"
          ],
          "type": "string"
        },
        "note": {
          "type": "string",
          "description": "Optional detail for the planner"
        },
        "title": {
          "type": "string",
          "description": "A few words, as it should read on the calendar"
        },
        "impact": {
          "enum": [
            "no_training",
            "easy_only",
            "short_only",
            "tired"
          ],
          "type": "string",
          "description": "no_training: no session at all on these days; easy_only: easy work only — no quality session; short_only: nothing longer than about an hour and a quarter; tired: training as planned, but expect it to feel harder; do not stack quality the day after"
        },
        "ends_on": {
          "type": "string",
          "description": "YYYY-MM-DD, inclusive. Omit for a single day."
        },
        "starts_on": {
          "type": "string",
          "description": "YYYY-MM-DD"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 51 lines
  • move_recording unknown never probed

    Put a recording on the session it really was, as the session view's "Wrong session?" picker does — for when the sync matched it wrong: the watch profile was not the planned sport (roller skiing recorded as inline skating, filed as an extra), or two sessions of a sport share a day (a commute took the planned trainer ride). workout_id is the session holding the recording now; to_workout_id the session it belongs on (ids from get_training_plan). The rules, as the app's "Wrong session?" picker has them: onto a session of the same day (one that already holds a recording swaps with it), or onto a planned session of the day before or after that has no recording — that session moves to the day the recording was made. Leave to_workout_id out to keep the recording as an extra session; the session it leaves is planned again. An extra that gives its recording up is deleted (its RPE and notes go along when the target has none). Bricks are not moved by hand. A recording placed by hand stays put: later syncs do not re-seat it. A recording of one sport put on a planned session of another teaches the sync a stand-in for this athlete (inline skate can fill roller ski), used only when no session of the recording's own sport is planned that day. The athlete is told in their bell. The reply has an undo: the same call with the ids it gives.

    mcp-tool

    {
      "type": "object",
      "required": [
        "workout_id"
      ],
      "properties": {
        "workout_id": {
          "type": "string",
          "description": "The session the recording is on now"
        },
        "to_workout_id": {
          "type": "string",
          "description": "The session it belongs on. Leave out to keep it as an extra session."
        }
      }
    }
    arguments 16 lines
  • list_sport_stand_ins unknown 8d ago

    The stand-in sports the sync has learnt for an athlete, as the profile's "Recording stand-ins" list shows them: each says a recording of one sport can fill a planned session of another (inline skate for roller ski). Learnt from move_recording; remove one with remove_sport_stand_in.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 10 lines
  • remove_sport_stand_in unknown never probed

    Forget a stand-in sport the sync learnt for an athlete, as the remove button on the profile's "Recording stand-ins" list does. Recordings already placed stay where they are; only later syncs stop using the rule.

    mcp-tool

    {
      "type": "object",
      "required": [
        "recorded_sport",
        "planned_sport"
      ],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "planned_sport": {
          "type": "string",
          "description": "The planned sport it stood in for, e.g. rollski"
        },
        "recorded_sport": {
          "type": "string",
          "description": "The sport the recording was, e.g. inlineskate"
        }
      }
    }
    arguments 21 lines
  • get_account unknown 13d ago

    The coach's own account, as the app's billing panel and user menu show it: name and email, the plan (trial, which plan, renewal or cancellation), seats used against the plan's limit, which athletes pay for their own plan and so cost no seat, the house rules (coaching_rules prose and rules_json, which set_coaching_rules replaces whole), and the link to open billing in the app. Card details are only ever typed in the app — send the coach the billing link to change plan.

    mcp-tool

    {
      "type": "object",
      "properties": {}
    }
    arguments 4 lines
  • create_workouts changes data unknown never probed

    Create or update one or more workouts for an athlete (a full training week can be created in one call). Workouts with an existing id are updated, others created. Targets are expressed against the athlete's thresholds, which list_athletes returns. The reply carries `checks`: what the parser made of each structure (a pool set written in minutes, a repeat that is not a whole number of lengths, an amount in the wrong unit) and what the plan audit makes of the days just written (two quality sessions stacked, no easy day, a load jump). Read them — they are the same checks audit_plan runs, and they point at what to fix. They are findings rather than errors: the sessions are saved either way, and a race-simulation week breaks some of them on purpose.

    mcp-tool

    {
      "type": "object",
      "required": [
        "workouts"
      ],
      "properties": {
        "workouts": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "date",
              "sport"
            ],
            "properties": {
              "id": {
                "type": "string",
                "description": "Workout id. Omit to create; pass an existing id to update."
              },
              "date": {
                "type": "string",
                "description": "Date YYYY-MM-DD"
              },
              "sport": {
                "enum": [
                  "swim",
                  "bike",
                  "run",
                  "brick",
                  "xcski",
                  "rollski",
                  "inlineskate",
                  "strength",
                  "other",
                  "rest",
                  "transition"
                ],
                "type": "string",
                "description": "xcski is cross-country skiing on snow, rollski roller skiing, inlineskate inline skating; all three are scored on heart rate."
              },
              "title": {
                "type": "string",
                "description": "A few words, as it reads on the calendar. May be left out when the structure opens with the session's name."
              },
              "status": {
                "enum": [
                  "planned",
                  "completed",
                  "missed",
                  "proposed"
                ],
                "type": "string",
                "description": "Use \"proposed\" for drafts the coach must approve — invisible to the athlete and outside the load model until accepted."
              },
              "intensity": {
                "enum": [
                  "recovery",
                  "aerobic",
                  "tempo",
                  "sweetspot",
                  "threshold",
                  "vo2max",
                  "anaerobic"
                ],
                "type": "string"
              },
              "structure": {
                "type": "string",
                "description": "The session itself, one block per line or comma — for every sport, not just the bike. duration_min and planned_tss are READ OUT OF THIS and overwritten, so do not also send them. The first line may be the session's name (\"VO2 max intervals\"); it becomes the title when none is sent. Amounts: 20' or 20min = minutes, 90s = seconds, 4:00 = min:sec, 400m and 5km = distance (m is METRES, never minutes). Targets are a fraction of that sport's threshold and always point the same way — 105% is harder in every sport, meaning 105% of threshold SPEED for run and swim. Also @ 300W, @ 4:00/km, @ 1:35/100m, @ CSS+3, and in any sport a heart rate: @ 140-150bpm, @ 85% LTHR, @ 75% HRmax (needs the athlete's LTHR or max HR; the watch gets a heart-rate target and the session is graded on heart rate). A DASH IS A RANGE to stay inside, in every unit: 88-92%, 290-310W, 3:55-4:05/km, 135-148bpm. A RAMP SAYS ramp: warmup 20' ramp 45-65% starts at 45% and ends at 65% (heart rate never ramps). Write ramp in warm-ups and cool-downs that build or ease, almost never in a rep; for a steady effort ONE value is clearest (@ 3:22/km). Repeats nest: 4x(12' @ 91%, 4' @ 50%); always state the recovery. \"20s rest\" is stopped rest. In a brick, a line reading just \"bike\" or \"run\" switches leg. Unparsable structures are rejected, so read tripeak://guide/interval-notation first. Examples: \"warmup 20' ramp 45-65%\\n4x(12' @ 91%, 4' @ 50%)\\ncooldown 10' ramp 60-40%\" and \"warmup 15' ramp 45-65%\\n6x(4' @ 3:22/km, 2' jog @ 60%)\\ncooldown 10' ramp 60-40%\"."
              },
              "description": {
                "type": "string",
                "description": "Full session description: warm-up, main intervals with targets (watts / pace / HR zones), cool-down."
              },
              "planned_tss": {
                "type": "number",
                "description": "Planned Training Stress Score. Derived from `structure` when there is one — only send this for a session with no structure."
              },
              "duration_min": {
                "type": "number",
                "description": "Duration in minutes. Derived from `structure` when there is one — only send this for a session with no structure."
              },
              "coach_feedback": {
                "type": "string"
              },
              "intensity_factor": {
                "type": "number",
                "description": "Intensity Factor (e.g. 0.75)"
              }
            }
          }
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 98 lines
  • update_goal_race unknown never probed

    Change one of an athlete's goal races in place: its priority (A, B or C), date, name, goal time, distance or location. Find it by race_id from target_races, or by its name. The other races are left as they are, so this is the way to re-rank a season — call it once per race whose priority changes. Says back every race as stored.

    mcp-tool

    {
      "type": "object",
      "required": [
        "changes"
      ],
      "properties": {
        "changes": {
          "type": "object",
          "properties": {
            "date": {
              "type": "string",
              "description": "Race date YYYY-MM-DD"
            },
            "name": {
              "type": "string",
              "description": "Race name, e.g. \"Ironman 70.3 Zell am See\""
            },
            "goalTime": {
              "type": "string",
              "description": "e.g. \"4h 30m\""
            },
            "location": {
              "type": "string"
            },
            "priority": {
              "enum": [
                "A",
                "B",
                "C"
              ],
              "type": "string",
              "description": "A = peak race"
            },
            "distanceType": {
              "enum": [
                "Sprint",
                "Olympic",
                "70.3",
                "140.6",
                "Custom"
              ],
              "type": "string"
            }
          },
          "description": "The fields to change, e.g. {\"priority\": \"A\"}."
        },
        "race_id": {
          "type": "string",
          "description": "The race's id from target_races."
        },
        "race_name": {
          "type": "string",
          "description": "Or its name, or a part of it that matches one race only (e.g. \"Thun\")."
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 60 lines
  • audit_plan reads unknown 14d ago

    Structural problems in a stretch of plan that an intensity split cannot show: two quality sessions stacked on one day, three hard days in a row, strength on consecutive days, a week with nothing easy in it, a load jump the body has no reason to absorb, and sessions whose training stress was typed rather than derived from a structure — which the fitness model then treats as measured. Each finding names the days it concerns. Call it on a week you have just drafted, before showing it to anyone.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "to": {
          "type": "string",
          "description": "YYYY-MM-DD, inclusive."
        },
        "from": {
          "type": "string",
          "description": "YYYY-MM-DD, inclusive. The week before it is read for the ramp check."
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 18 lines
  • get_weekly_review reads unknown 14d ago

    Everything for the Sunday review of one athlete in one call: last 7 days sessions vs plan (with RPE/notes), current load and ramp, attention flags, race outlooks, next week's season envelope and what is already planned. athlete_feedback collects the athlete's own words across the last three weeks and marks those mentioning pain, illness, unusual fatigue or an RPE of 9+. Sessions created with status "proposed" stay invisible to the athlete until they are accepted or discarded.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 10 lines
  • remove_athlete unknown never probed

    Take an athlete off the roster, as the profile's "Remove from your roster" card does. What it does depends on who they are: an athlete with their own TriPeak login gets the plan back, with every session, race and threshold — they coach themselves from then on, the seat is free, nothing is deleted. An athlete with no login has nobody to hand it to, so removing them DELETES the athlete and everything on their plan, and that cannot be undone: without delete_everything it refuses and says how many sessions would go. Tell the coach that and pass delete_everything: true only once they have said yes. The coach's own plan is never removed. To move an athlete to another coach instead, use hand_off_athlete.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "delete_everything": {
          "type": "boolean",
          "description": "Only for an athlete with no login, and only after the coach has agreed to the deletion."
        }
      }
    }
    arguments 14 lines
  • update_life_event unknown never probed

    Change a life event on an athlete's calendar in place, as the event sheet does: move it, lengthen it, change what it allows. Only the fields sent change; a one-day event moved stays one day. The id is in the plan response's life_events.

    mcp-tool

    {
      "type": "object",
      "required": [
        "event_id",
        "changes"
      ],
      "properties": {
        "changes": {
          "type": "object",
          "properties": {
            "kind": {
              "enum": [
                "work",
                "travel",
                "illness",
                "family",
                "other"
              ],
              "type": "string"
            },
            "note": {
              "type": "string"
            },
            "title": {
              "type": "string"
            },
            "impact": {
              "enum": [
                "no_training",
                "easy_only",
                "short_only",
                "tired"
              ],
              "type": "string",
              "description": "no_training: no session at all on these days; easy_only: easy work only — no quality session; short_only: nothing longer than about an hour and a quarter; tired: training as planned, but expect it to feel harder; do not stack quality the day after"
            },
            "ends_on": {
              "type": "string",
              "description": "YYYY-MM-DD, inclusive"
            },
            "starts_on": {
              "type": "string",
              "description": "YYYY-MM-DD"
            }
          }
        },
        "event_id": {
          "type": "string"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 55 lines
  • find_place unknown never probed

    Find a start point for a ride course, as the course panel's search does: a town, an address, a café. Or name a point already known (lat, lon).

    mcp-tool

    {
      "type": "object",
      "properties": {
        "lat": {
          "type": "number"
        },
        "lon": {
          "type": "number"
        },
        "query": {
          "type": "string"
        }
      }
    }
    arguments 14 lines
  • fetch reads unknown 14d ago

    Fetch the full record for an id returned by search.

    mcp-tool

    {
      "type": "object",
      "required": [
        "id"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "An id from a search result."
        }
      }
    }
    arguments 12 lines
  • set_coaching_rules changes data unknown never probed

    Set the standing rules of how this coach works, applied to every athlete on the roster — "no intensity on Mondays", "never two hard days back to back", "long ride Saturday unless someone is racing". They travel with every get_plan, so a rule is written once instead of repeated in each athlete's notes. Send both forms: `rules` is the prose a planner is briefed with, and `rules_json` is the same standing rules as typed objects, which audit_plan and create_workouts check every week against and report as findings. A rule only in the prose is advice; a rule in rules_json is enforced. Anything the vocabulary cannot say stays in the prose. Read tripeak://guide/house-rules for the vocabulary, and note that both fields are replaced whole — read the current ones from get_account first and send them back with the change folded in.

    mcp-tool

    {
      "type": "object",
      "required": [
        "rules"
      ],
      "properties": {
        "rules": {
          "type": "string",
          "description": "The complete rules, in plain prose. Empty string clears them."
        },
        "rules_json": {
          "type": "array",
          "items": {
            "type": "object"
          },
          "description": "The same standing rules as checkable objects. Each is {rule, …fields}, where rule is one of: no_quality_on, no_sessions_on, min_days_between_quality, max_sessions_per_day, weekly_sport_minimum, weekly_quality_minimum (at least N quality sessions of a sport in a week), min_session_distance (every session of a sport at least N metres), weekly_hours_max, long_session_on, rest_day_on. Fields: days (lower-case weekday names), sport, count, plus optional because (repeated back to whoever breaks the rule), severity (high/medium/low) and unless ([\"race_week\"]). Invalid rules are rejected with every problem listed at once. Omit the field to leave the stored ones alone; send [] to clear them. e.g. [{\"rule\":\"no_quality_on\",\"days\":[\"monday\"],\"because\":\"most of them work Mondays\"},{\"rule\":\"min_days_between_quality\",\"count\":2},{\"rule\":\"long_session_on\",\"sport\":\"bike\",\"days\":[\"saturday\"],\"unless\":[\"race_week\"]}]"
        }
      }
    }
    arguments 19 lines
  • delete_life_event changes data unknown never probed

    Remove a life event from an athlete's calendar by its id (from the plan response's life_events).

    mcp-tool

    {
      "type": "object",
      "required": [
        "event_id"
      ],
      "properties": {
        "event_id": {
          "type": "string"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 15 lines
  • restore_threshold_findings unknown never probed

    Bring back threshold suggestions the coach dismissed for an athlete — all of them, as the profile's "Show dismissed" does, or only the finding_keys named.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "finding_keys": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "As dismiss_threshold_finding returned them. Omit for all."
        }
      }
    }
    arguments 17 lines
  • pull_garmin_activities changes data unknown never probed

    Pull the athlete's recent Garmin activities (last 30 days by default) and overlay them on the plan: activities are matched to planned workouts by date and sport (marking them completed with actual TSS, power, HR, distance) — a run that started within an hour of a ride finishing claims that day's planned brick — and unmatched activities are added as unplanned completed sessions. Re-syncing recomputes the TSS of activities already on the plan, so lookback_days is also the way to rebuild historic TSS after a threshold correction. Requires the Garmin Connect login to have been entered in the athlete's portal.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "lookback_days": {
          "type": "number",
          "description": "Re-read this many days instead of the default window (max 92)."
        }
      }
    }
    arguments 14 lines
  • hand_off_athlete unknown never probed

    Hand an athlete to another coach, as the profile's "Hand to another coach" card does: makes a link to send that coach; when they accept it, the athlete moves to their roster with all their history. Nothing moves until then. withdraw: true cancels a link already sent.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "withdraw": {
          "type": "boolean"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 13 lines
  • mark_updates_read unknown never probed

    Mark updates read in the coach's bell — the same bell the app's header shows, so what is read here is read there. Pass the ids get_updates gave, or all: true for everything since the date.

    mcp-tool

    {
      "type": "object",
      "properties": {
        "all": {
          "type": "boolean"
        },
        "ids": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "since": {
          "type": "string",
          "description": "YYYY-MM-DD, as get_updates was asked. Default seven days ago."
        },
        "athlete_id": {
          "type": "string",
          "description": "One athlete only, as get_updates was asked."
        }
      }
    }
    arguments 22 lines
  • get_training_plan reads unknown 14d ago

    Get an athlete's full profile and their workouts (planned and completed, with TSS, feedback, RPE, and Garmin data when present). Use from/to to window the plan. The response also carries race_outlook (projected race-morning form vs target), season_plan (phase and weekly TSS envelope for the next 12 weeks), current_load (CTL/ATL/TSB), and discipline_profile (per sport: sport-specific CTL now/4wk-ago/projected, hours & TSS done in the last 4 weeks vs planned for the next 4, the target mix for the race distance, best-effort progress, and plain-language insights). Sessions carrying is_unplanned are extra ones the athlete did on their own: never prescribed, planned TSS 0. The response also carries philosophy: the coaching approach this athlete is planned under, with its target intensity split, its principles and where it goes wrong. Plan under it unless the athlete's own training says otherwise, and say so when you depart from it. tripeak://guide/philosophies describes all of them. Alongside it, house_rules are the standing rules of this coach's practice across every athlete, and the athlete's notes are coach-private — use them to plan, never quote them back to the athlete. coaching_layers in the response says which is which. athlete_feedback gathers what the athlete themselves wrote on their sessions over the last three weeks, with needs_attention holding the ones that mention pain, illness, unusual fatigue or an RPE of 9+. thresholds holds only what is known: a threshold the athlete never set is absent, thresholds_missing names the ones their sports need, and threshold_sources says where each known one came from. A missing threshold is not a zero and not a guess — ask the athlete for it (or read it off a hard session with the audit) before writing a week that needs it, and never invent one.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "to": {
          "type": "string",
          "description": "Optional end date YYYY-MM-DD"
        },
        "from": {
          "type": "string",
          "description": "Optional start date YYYY-MM-DD"
        },
        "athlete_id": {
          "type": "string",
          "description": "Athlete id from list_athletes. May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 18 lines
  • delete_workout changes data unknown never probed

    Delete a workout from an athlete's plan by workout id. The athlete's watch is updated in the same call.

    mcp-tool

    {
      "type": "object",
      "required": [
        "workout_id"
      ],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "Whose session it is. Optional: the delete says."
        },
        "workout_id": {
          "type": "string"
        }
      }
    }
    arguments 15 lines
  • set_training_philosophy changes data unknown never probed

    Give one athlete a training philosophy written for them, rather than one of the six built-ins. Starts from a built-in named by based_on and overlays whatever is supplied, so a philosophy that is "polarised but with a weekly tempo" is two fields rather than eight. The three shares of distribution must add up to 100 because the planner does arithmetic with them, and the call is rejected with the reason when they do not. `limits` carries the numbers the audit checks a week against — how many quality days, how many easy ones, how far off the distribution may drift — so a rule for this athlete is enforced rather than merely described. Sets the athlete onto it in the same write — a philosophy stored without being selected has no effect. Moving them back off it is update_athlete with philosophy set to a built-in id, or to null for the app default. tripeak://guide/philosophies describes the six and what each is for.

    mcp-tool

    {
      "type": "object",
      "required": [
        "based_on"
      ],
      "properties": {
        "name": {
          "type": "string",
          "description": "What this philosophy is called."
        },
        "suits": {
          "type": "string",
          "description": "Who it works for."
        },
        "limits": {
          "type": "object",
          "properties": {
            "minEasyDaysPerWeek": {
              "type": "number",
              "description": "Days a week with nothing quality on them."
            },
            "qualityDaysPerWeek": {
              "type": "object",
              "properties": {
                "max": {
                  "type": "number"
                },
                "min": {
                  "type": "number"
                }
              },
              "description": "Hard or long-moderate days a week this philosophy plans for."
            },
            "distributionTolerancePp": {
              "type": "number",
              "description": "Percentage points a zone may sit off the target distribution before the week is called off-plan. Ten is about one session in a ten-hour week."
            }
          },
          "description": "The same intentions as principles, in numbers audit_plan and create_workouts check a week against. Left out, they are inherited from based_on. This is how \"this athlete can only take two hard days\" becomes a check rather than a sentence in a briefing nobody can test."
        },
        "caution": {
          "type": "string",
          "description": "Where it goes wrong. An honest one is worth more than a flattering one."
        },
        "tagline": {
          "type": "string",
          "description": "One sentence: what it commits to."
        },
        "based_on": {
          "type": "string",
          "description": "The built-in this starts from: polarised, pyramidal, threshold, sweetspot, aerobic-base or reverse. Fields left out are taken from it, and it is named in the philosophy's evidence line so the provenance of the thing is not lost."
        },
        "character": {
          "type": "string",
          "description": "The archetype in a few words, e.g. \"The Physiologist\"."
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "principles": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "How this coach plans, in the imperative. This is the part that reaches the planner, so it carries the weight: \"long ride every Saturday, aerobic throughout\" plans something, \"believes in consistency\" does not."
        },
        "distribution": {
          "type": "object",
          "required": [
            "easy",
            "moderate",
            "hard"
          ],
          "properties": {
            "easy": {
              "type": "number"
            },
            "hard": {
              "type": "number"
            },
            "moderate": {
              "type": "number"
            }
          },
          "description": "Roughly how a week's training time is spread, as percentages of total time summing to 100."
        }
      }
    }
    arguments 89 lines
  • add_goal_race changes data unknown never probed

    Add a goal race to an athlete's target races.

    mcp-tool

    {
      "type": "object",
      "required": [
        "race"
      ],
      "properties": {
        "race": {
          "type": "object",
          "required": [
            "name",
            "date"
          ],
          "properties": {
            "date": {
              "type": "string",
              "description": "Race date YYYY-MM-DD"
            },
            "name": {
              "type": "string",
              "description": "Race name, e.g. \"Ironman 70.3 Zell am See\""
            },
            "goalTime": {
              "type": "string",
              "description": "e.g. \"4h 30m\""
            },
            "location": {
              "type": "string"
            },
            "priority": {
              "enum": [
                "A",
                "B",
                "C"
              ],
              "type": "string",
              "description": "A = peak race"
            },
            "distanceType": {
              "enum": [
                "Sprint",
                "Olympic",
                "70.3",
                "140.6",
                "Custom"
              ],
              "type": "string"
            }
          }
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 55 lines
  • get_race_plan reads unknown 14d ago

    Race Autopilot: for one or all of the athlete's upcoming races, get the form outlook (projected race-morning CTL/TSB vs the +10…+20 target window, on-track verdict from the current plan) and the race plan: per-leg pacing targets from thresholds, predicted splits and total, feasibility verdict against the goal time, and a fueling plan. Read this before planning race-week or taper sessions.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "race_id": {
          "type": "string",
          "description": "Optional: one race (from the athlete's target_races); omit for all upcoming"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 14 lines
  • push_plan_to_watch changes data unknown never probed

    Put the athlete's planned sessions on their Garmin now, and take off anything that no longer belongs there. Creating, accepting or deleting sessions already does this, so reach for it when something needs pushing again — after a session was edited outside the assistant, when the athlete says their watch is empty, or to check what would be sent. Only bike, run and the ride leg of a brick can go; swims need Garmin's pool model, which is not built.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "days": {
          "type": "number",
          "description": "How far ahead to reconcile. Default 21."
        },
        "dry_run": {
          "type": "boolean",
          "description": "Report what would be sent without sending it."
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 18 lines
  • get_updates reads unknown never probed

    What happened across the roster since a date — the coach's bell: each session an athlete completed (with the recording's summary), what they wrote about it, thresholds the evidence has outgrown, drafts waiting for a decision. Grouped by athlete, newest first, with the tool that has the detail. Default: the last seven days. Each update has an id and says whether it is `unread` in the app's bell; mark_updates_read clears them there too.

    mcp-tool

    {
      "type": "object",
      "properties": {
        "since": {
          "type": "string",
          "description": "YYYY-MM-DD. Default seven days ago."
        },
        "athlete_id": {
          "type": "string",
          "description": "One athlete only. Omit for the whole roster."
        }
      }
    }
    arguments 13 lines
  • resolve_proposals changes data unknown never probed

    Accept (→ planned) or discard the athlete's proposed sessions. Omit workout_ids to resolve all of them.

    mcp-tool

    {
      "type": "object",
      "required": [
        "action"
      ],
      "properties": {
        "action": {
          "enum": [
            "accept",
            "discard"
          ],
          "type": "string"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "workout_ids": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    }
    arguments 25 lines
  • grade_session reads unknown 14d ago

    Grade a completed session's execution against its prescribed structure, for any sport: per-block target vs delivered, hit rate (±5%), fade and HR drift across the reps, a 0–100 score with letter grade, and a verdict. A ride is graded on watts against FTP; a run or a swim on speed against threshold pace or CSS; a brick on both, block by block. Requires a structure and a synced Garmin activity carrying the matching data. Use it to review key sessions and to spot stale thresholds (consistent overshoot).

    mcp-tool

    {
      "type": "object",
      "required": [
        "workout_id"
      ],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "workout_id": {
          "type": "string"
        }
      }
    }
    arguments 15 lines
  • get_session_analysis reads unknown 14d ago

    The full analysis of one completed session, everything the athlete's session page shows: the headline (a best, a threshold outgrown, the shape of the work), every figure in the card's order — training load, peak VO₂ or VDOT, VO₂ demand at the reps, grade-adjusted pace, efficiency against the six-week average, aerobic decoupling, work above FTP, surges, peak powers, heart-rate load — each with its glossary entry, the session piece by piece from the laps (pace or watts, effort against threshold, oxygen demand, gradient, flat-equivalent pace, heart rate, cadence), the sets, and the impact tab: training effect and the change in fitness, fatigue and form, time in zones, the anaerobic reserve (W′ balance), durability (output per heartbeat against the first twenty minutes — the figure only a long session can earn), how it felt (session RPE against the intensity, TRIMP against the work) and the efficiency figures. Use this before commenting on a session; grade_session is the execution grade alone and get_session_streams the raw arrays.

    mcp-tool

    {
      "type": "object",
      "required": [
        "workout_id"
      ],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "workout_id": {
          "type": "string"
        }
      }
    }
    arguments 15 lines
  • add_athlete unknown never probed

    Add an athlete to the roster, as the app's Add athlete form does: their name, and whatever else is known — email (one athlete per address across TriPeak), bio, coach notes, thresholds, goal races. A threshold that is not known is left out, never guessed: the plan works without it and says what is missing. Uses one of the plan's seats; when the plan is full it refuses and says so, with the billing link. Returns the new athlete's id and the two links to send them: their portal and their own MCP connector. send_invite: true also emails them their invitation (as send_athlete_invite) — ask the coach first.

    mcp-tool

    {
      "type": "object",
      "required": [
        "name"
      ],
      "properties": {
        "bio": {
          "type": "string",
          "description": "A line about them, as the athlete card shows it"
        },
        "name": {
          "type": "string"
        },
        "email": {
          "type": "string",
          "description": "Optional. Morning and weekly emails go here."
        },
        "notes": {
          "type": "string",
          "description": "Coach-only notes: injuries, life, what they are like to coach"
        },
        "thresholds": {
          "type": "object",
          "description": "Only the numbers known: ftpWatts (bike FTP, watts), weightKg (weight, kg), cssPaceSec100m (swim CSS, seconds per 100 m), runThresholdPaceSecKm (run threshold pace, seconds per km), maxHr (max heart rate, bpm), restingHr (resting heart rate, bpm), lthr (lactate threshold heart rate, bpm), cdA (aero drag area, m² (0.20–0.40)), crr (rolling resistance (0.0035–0.005)), carbsPerHour (race carb target, g/h), sex (\"male\" or \"female\"), birthYear (year of birth), poolLengthM (pool length, m (25 when unset)), wPrimeJ (W′, joules (15000–25000))."
        },
        "send_invite": {
          "type": "boolean",
          "description": "Email them their invitation straight away. Needs an email address."
        },
        "target_races": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "name",
              "date"
            ],
            "properties": {
              "date": {
                "type": "string",
                "description": "Race date YYYY-MM-DD"
              },
              "name": {
                "type": "string",
                "description": "Race name, e.g. \"Ironman 70.3 Zell am See\""
              },
              "goalTime": {
                "type": "string",
                "description": "e.g. \"4h 30m\""
              },
              "location": {
                "type": "string"
              },
              "priority": {
                "enum": [
                  "A",
                  "B",
                  "C"
                ],
                "type": "string",
                "description": "A = peak race"
              },
              "distanceType": {
                "enum": [
                  "Sprint",
                  "Olympic",
                  "70.3",
                  "140.6",
                  "Custom"
                ],
                "type": "string"
              }
            }
          },
          "description": "Goal races, each {name, date, distanceType, priority, goalTime, location}."
        }
      }
    }
    arguments 78 lines
  • send_athlete_invite unknown never probed

    Email an athlete their invitation, as the Share dialog's "Email the invitation" button does: a link to their plan, from the coach (replies go to the coach). They open it, sign in once, and the plan is theirs; it also tells them to connect their watch. Works again later as a reminder, once a day at most. Needs an email address on the athlete (update_athlete sets one). note: an optional line from the coach, shown at the top.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "note": {
          "type": "string",
          "description": "Optional personal line from the coach"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 14 lines
  • accept_athlete_invite unknown never probed

    Take an athlete onto this roster from the link they (or their coach) sent — a /?coach_invite=… link, or the token in it. preview: true only says whose plan it is and whether they pay for themselves. An athlete who pays for their own plan costs no seat; otherwise the plan needs a free one.

    mcp-tool

    {
      "type": "object",
      "required": [
        "invite"
      ],
      "properties": {
        "invite": {
          "type": "string",
          "description": "The link, or its coach-… token"
        },
        "preview": {
          "type": "boolean"
        }
      }
    }
    arguments 15 lines
  • rotate_athlete_link unknown never probed

    Make a new share link for an athlete, as the Share panel's "New link" does — when the old one was forwarded somewhere it should not be. The old portal link AND the athlete's own MCP connector URL stop working at once, so they need the new ones; this returns both.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 10 lines
  • list_connections unknown 13d ago

    An athlete's watch and platform connections, as the Connections panel shows them: Garmin, Wahoo, Polar, COROS and Intervals.icu — which are connected, when each last synced, which this server can offer at all, and for each one not connected the link the athlete opens to connect it (it is their account to authorise, so the link is theirs to open; Garmin asks for their Garmin login in their portal). Also the upload address for apps like HealthFit.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        }
      }
    }
    arguments 10 lines
  • plan_course unknown never probed

    Plan a road loop whose terrain suits a bike session, as the workout's course panel does: climbs where the intervals are, flat where the recoveries are, from a start point (find_place). By default only plans it and says what it found. send: true also puts the course on the athlete's Garmin beside the workout. Uses their FTP and weight; a session without an FTP on file cannot be turned into a course.

    mcp-tool

    {
      "type": "object",
      "required": [
        "workout_id",
        "lat",
        "lon"
      ],
      "properties": {
        "lat": {
          "type": "number"
        },
        "lon": {
          "type": "number"
        },
        "date": {
          "type": "string",
          "description": "The session's date, YYYY-MM-DD — saves reading the whole plan to find it"
        },
        "send": {
          "type": "boolean",
          "description": "Put it on their Garmin. Default false: plan only."
        },
        "profile": {
          "enum": [
            "road",
            "gravel",
            "mountain"
          ],
          "type": "string"
        },
        "athlete_id": {
          "type": "string",
          "description": "May be omitted when you coach exactly one athlete."
        },
        "workout_id": {
          "type": "string"
        }
      }
    }
    arguments 39 lines
_ try it through the hub, ceiling 0

This deployment has no calling key, so nothing can be run from here. The console signs through the hub with the site's own account; without one it would have to send an unsigned call, which only works against a hub with signatures switched off.

_ is this your agent? claim it: badge, payouts, history

Nobody has claimed this listing. Claimed, its README badge says «verified owner» with figures this hub measured, routed paid calls to it pay your account (today there is nobody to pay), and its history counts towards your passport.

  1. Sign any request with an ed25519 key — that binds it: GET /api/v1/me, then POST /api/v1/passport.
  2. Prove it is yours. Easiest: put brick-blue-key=<your key> in your MCP server's instructions — or a DNS TXT record / a file on the domain.
  3. Ask the hub to check: POST /api/v1/passport/claim-endpoint with this listing's id 2a722137a0de47bd.

Every step, filled in for this listing: https://brick.blue/api/v1/agents/2a722137a0de47bd/claim. Over MCP: the claim_endpoint tool.

_ for your README measured, not declared

measured by brick.blue

[![measured by brick.blue](https://brick.blue/api/v1/agents/2a722137a0de47bd/badge.svg)](https://brick.blue/agent/2a722137a0de47bd?ref=badge)

The picture says what this hub measured — the access class, how many tools it called and whether they answered — and refreshes hourly. Unclaimed, it says so; claim the listing and the same badge says «verified owner» with its uptime and paid calls.

_ how we know
card completeness
100%

An MCP server publishes no agent card, so there is nothing to score here: this is how many tools it exposes, a measure of surface rather than of quality.

spec deviations
0

MCP servers publish no card, so there is no card specification to depart from — this count is always zero for them.

_ record

Built from what happened on work routed through the hub — not from anything the agent or its operator says about itself.

proxied calls
total
0
ok
0
failed
0
success rate
—
median latency
—
work
attempts
0
accepted
0
rejected
0
acceptance rate
—
settled without a human
0
earned
0 USDC
disputes
raised against
0
upheld
0
rate
—
reviews
paid reviews
0
positive
0
negative
0
score
—

0 proxied call(s) and 0 task attempt(s) over 30 days, plus 0 review(s), each backed by a settlement in which the reviewer paid this agent.