Skip to main content
Glama

update_athlete_profile

Destructive

Edit the athlete's profile — FTP (watts), running threshold pace, max/threshold HR, power/pace/HR zone boundaries, AND the about-you fields (birthdate, sex, heightCm, weightKg, weeklyHours, availableDays 0=Mon..6=Sun, experience). Every field is OPTIONAL: pass only what changes; everything else is preserved (safe partial update). Confirm new numbers with the athlete before writing (a changed FTP/weight moves every target). To set custom zones pass a sport's zoneBounds (5 strictly-ascending upper bounds) — that flips it to Manual; pass autoZones:true to revert. Same for hrZoneBounds/autoHrZones. Setting birthdate refreshes the age-based HRmax estimate unless maxHr was set manually — writing a sport's maxHr marks it manual, and autoMaxHr:true hands it back to the estimate. Server-validated; rejects an invalid edit instead of writing a broken profile. Only touches the profile, never the calendar or library. Read with get_athlete_profile first.

Input Schema

NameRequiredDescriptionDefault
ftpNocycling FTP, watts
kitNo
runNorunning thresholds + zones
sexNo
sftNothe athlete's CYCLING submaximal fatigue test (SFT): the fixed load they hold in the warm-up, which get_fatigue_tests then finds in every ride. null = stop tracking. The standard protocol (Science to Sport, what intervals.icu detects) is about 110% of FTP for 3 min (sec 180) — get_fatigue_tests proposes it — agree it with them, and do not change it mid-season — a new value starts a new baseline.
bikeNocycling thresholds + zones
prefsNo
healthNoonly what they told you; needs their consent
sftRunNothe athlete's RUNNING fatigue test: about 105% of threshold speed for 3 min (sec 180), frozen for the season, on a treadmill or a flat loop, then a minute of walking — get_fatigue_tests sport:"running" proposes it. null = stop tracking.
controlNowhat they TRAIN BY per sport (Profile "You train by"): the signal you judge and speak in — not the watch's default (running hr also sets runByHr); null = back to what their files show. Only when they say so.
cssPaceNoSWIM threshold — critical swim speed, seconds per 100 m. Confirm it with the athlete before writing: without it swims carry no load, and with a wrong one every swim in their history is mis-scored. From a 400 m + 200 m time trial: (400-200)/(t400-t200) m/s.
runByHrNotrue = runs default to HR targets on the watch (= control.running "hr")
thrPaceNorunning threshold pace, seconds per km
heightCmNo
longDaysNolong-session days, 0=Mon
weightKgNokg — enables W/kg and body-mass fuelling
autoMaxHrNotrue = go back to the age-based HRmax estimate. Writing a sport's maxHr flips this to manual on its own.
birthdateNoYYYY-MM-DD (age is derived); setting it refreshes the age-based HRmax estimate unless maxHr was set manually (maxHrAuto:false — read it back in get_athlete_profile)
trainTimeNo
experienceNotraining age → ramp aggressiveness
powerMeterNofalse = no power meter: ride targets show as HR + RPE; prescribe by HR and feel
structuredNofollowed a structured plan before
weeklyHoursNotypical training hours/week
availableDaysNoweekdays free to train, 0=Mon..6=Sun
trainingYearsNoyears in the sport

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / health / properties / cycle / enum
      Previous value: -[
      -  "regular",
      -  "irregular",
      -  "absent3m",
      -  "hormonal",
      -  "na",
      -  "declined"
      -]New value: +[
      +  "regular",
      +  "irregular",
      +  "absent3m",
      +  "hormonal",
      +  "pregnant",
      +  "na",
      +  "declined"
      +]
  2. Changed4 schema fields changed
    • addedInput schema / properties / bike / properties / vt1Ve
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maximum": 400,
      +      "minimum": 5,
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "VE at VT1, own breathing sensor's units (not L/min); null clears"
      +}
    • addedInput schema / properties / bike / properties / vt2Ve
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maximum": 400,
      +      "minimum": 5,
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "VE at VT2, same units, > vt1Ve"
      +}
    • addedInput schema / properties / run / properties / vt1Ve
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maximum": 400,
      +      "minimum": 5,
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "VE at VT1, own breathing sensor's units (not L/min); null clears"
      +}
    • addedInput schema / properties / run / properties / vt2Ve
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maximum": 400,
      +      "minimum": 5,
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "VE at VT2, same units, > vt1Ve"
      +}
  3. Changed6 schema fields changed
    • changedInput schema / properties / health / description
      Previous value: -"health screen: only what they told you; needs their intake consent"New value: +"only what they told you; needs their consent"
    • removedInput schema / properties / kit / description
      Removed value: -"merged into stored kit"
    • changedInput schema / properties / longDays / description
      Previous value: -"weekdays for long sessions, 0=Mon"New value: +"long-session days, 0=Mon"
    • addedInput schema / properties / prefs / properties / doubles
      Added value: +{
      +  "enum": [
      +    "like",
      +    "can",
      +    "no"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / prefs / properties / repShape
      Added value: +{
      +  "enum": [
      +    "long",
      +    "short",
      +    "either"
      +  ],
      +  "type": "string"
      +}
    • changedInput schema / properties / trainingYears / description
      Previous value: -"years in the sport (sets experience with structured)"New value: +"years in the sport"
  4. Changed7 schema fields changed
    • addedInput schema / properties / health
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "health screen: only what they told you; needs their intake consent",
      +  "properties": {
      +    "cardiac": {
      +      "enum": [
      +        "yes",
      +        "no",
      +        "declined"
      +      ],
      +      "type": "string"
      +    },
      +    "cleared": {
      +      "description": "a doctor cleared them",
      +      "type": "boolean"
      +    },
      +    "cycle": {
      +      "enum": [
      +        "regular",
      +        "irregular",
      +        "absent3m",
      +        "hormonal",
      +        "na",
      +        "declined"
      +      ],
      +      "type": "string"
      +    },
      +    "hrMeds": {
      +      "enum": [
      +        "yes",
      +        "no",
      +        "declined"
      +      ],
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedInput schema / properties / kit
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "merged into stored kit",
      +  "properties": {
      +    "gym": {
      +      "type": "boolean"
      +    },
      +    "hrStrap": {
      +      "type": "boolean"
      +    },
      +    "pool": {
      +      "type": "boolean"
      +    },
      +    "trainer": {
      +      "type": "boolean"
      +    },
      +    "treadmill": {
      +      "type": "boolean"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedInput schema / properties / longDays
      Added value: +{
      +  "description": "weekdays for long sessions, 0=Mon",
      +  "items": {
      +    "maximum": 6,
      +    "minimum": 0,
      +    "type": "integer"
      +  },
      +  "maxItems": 7,
      +  "type": "array"
      +}
    • addedInput schema / properties / prefs
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "company": {
      +      "enum": [
      +        "solo",
      +        "group",
      +        "both"
      +      ],
      +      "type": "string"
      +    },
      +    "disliked": {
      +      "items": {
      +        "enum": [
      +          "intervals",
      +          "tempo",
      +          "long",
      +          "hills",
      +          "easy",
      +          "strength",
      +          "group"
      +        ],
      +        "type": "string"
      +      },
      +      "maxItems": 7,
      +      "type": "array"
      +    },
      +    "liked": {
      +      "items": {
      +        "enum": [
      +          "intervals",
      +          "tempo",
      +          "long",
      +          "hills",
      +          "easy",
      +          "strength",
      +          "group"
      +        ],
      +        "type": "string"
      +      },
      +      "maxItems": 7,
      +      "type": "array"
      +    },
      +    "setting": {
      +      "enum": [
      +        "outdoor",
      +        "indoor",
      +        "both"
      +      ],
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedInput schema / properties / structured
      Added value: +{
      +  "description": "followed a structured plan before",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / trainTime
      Added value: +{
      +  "enum": [
      +    "morning",
      +    "midday",
      +    "evening",
      +    "varies"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / trainingYears
      Added value: +{
      +  "description": "years in the sport (sets experience with structured)",
      +  "maximum": 60,
      +  "minimum": 0,
      +  "type": "number"
      +}
  5. Changed2 schema fields changed
    • removedInput schema / properties / dayCheck
      Removed value: -{
      -  "description": "a subscriber's \"Day check\" (Profile → Assistant): the assistant's own short look at today or tomorrow when the gym log or check-in gives a reason — false turns it off. Only when they ask.",
      -  "type": "boolean"
      -}
    • removedInput schema / properties / suggestReviews
      Removed value: -{
      -  "description": "post-session reviews (Profile → Assistant). For a Blocks Unlimited subscriber this is \"Automatic reviews\": Blocks reviews a finished training session on its own (20 min+, up to 2 a day, none at night) — false turns that off. For everyone else it is the offer of a review after a key session. Only when they ask.",
      -  "type": "boolean"
      -}
  6. Changed1 schema field changed
    • addedInput schema / properties / dayCheck
      Added value: +{
      +  "description": "a subscriber's \"Day check\" (Profile → Assistant): the assistant's own short look at today or tomorrow when the gym log or check-in gives a reason — false turns it off. Only when they ask.",
      +  "type": "boolean"
      +}
  7. Changed1 schema field changed
    • addedInput schema / properties / suggestReviews
      Added value: +{
      +  "description": "post-session reviews (Profile → Assistant). For a Blocks Unlimited subscriber this is \"Automatic reviews\": Blocks reviews a finished training session on its own (20 min+, up to 2 a day, none at night) — false turns that off. For everyone else it is the offer of a review after a key session. Only when they ask.",
      +  "type": "boolean"
      +}
  8. Changed2 schema fields changed
    • addedInput schema / properties / control
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "what they TRAIN BY per sport (Profile \"You train by\"): the signal you judge and speak in — not the watch's default (running hr also sets runByHr); null = back to what their files show. Only when they say so.",
      +  "properties": {
      +    "cycling": {
      +      "anyOf": [
      +        {
      +          "enum": [
      +            "power",
      +            "hr",
      +            "rpe",
      +            "breath",
      +            "lactate"
      +          ],
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "running": {
      +      "anyOf": [
      +        {
      +          "enum": [
      +            "pace",
      +            "hr",
      +            "rpe",
      +            "breath",
      +            "lactate"
      +          ],
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "swim": {
      +      "anyOf": [
      +        {
      +          "enum": [
      +            "pace",
      +            "rpe"
      +          ],
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    }
      +  },
      +  "type": "object"
      +}
    • changedInput schema / properties / runByHr / description
      Previous value: -"true = runs default to HR targets"New value: +"true = runs default to HR targets on the watch (= control.running \"hr\")"
  9. Changed1 schema field changed
    • changedInput schema / properties / runByHr / description
      Previous value: -"true = run targets go out as HR, not pace"New value: +"true = runs default to HR targets"
  10. Changed2 schema fields changed
    • changedInput schema / properties / powerMeter / description
      Previous value: -"false = the athlete rides WITHOUT a power meter — cycling targets display as HR + RPE; prescribe rides by heart rate and feel, not watts"New value: +"false = no power meter: ride targets show as HR + RPE; prescribe by HR and feel"
    • addedInput schema / properties / runByHr
      Added value: +{
      +  "description": "true = run targets go out as HR, not pace",
      +  "type": "boolean"
      +}
  11. Changed2 schema fields changed
    • changedInput schema / properties / sft / anyOf
      Previous value: -[
      -  {
      -    "properties": {
      -      "sec": {
      -        "description": "hold duration in seconds, e.g. 180",
      -        "maximum": 900,
      -        "minimum": 120,
      -        "type": "integer"
      -      },
      -      "watts": {
      -        "description": "absolute watts, frozen for the season — never a % of FTP",
      -        "maximum": 700,
      -        "minimum": 60,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "watts",
      -      "sec"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "properties": {
      +      "sec": {
      +        "description": "hold duration in seconds, e.g. 180",
      +        "maximum": 900,
      +        "minimum": 120,
      +        "type": "integer"
      +      },
      +      "watts": {
      +        "description": "their bike SFT (fatigue test): ~110% FTP × 3 min by protocol, frozen for the season; get_fatigue_tests proposes it. null = off",
      +        "maximum": 700,
      +        "minimum": 60,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "watts",
      +      "sec"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / sftRun / anyOf
      Previous value: -[
      -  {
      -    "properties": {
      -      "pace": {
      -        "description": "seconds per km, frozen for the season",
      -        "maximum": 600,
      -        "minimum": 150,
      -        "type": "integer"
      -      },
      -      "sec": {
      -        "description": "hold duration in seconds",
      -        "maximum": 900,
      -        "minimum": 120,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "pace",
      -      "sec"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "properties": {
      +      "pace": {
      +        "description": "their running SFT: ~105% of threshold speed × 3 min, treadmill or flat loop. null = off",
      +        "maximum": 600,
      +        "minimum": 150,
      +        "type": "integer"
      +      },
      +      "sec": {
      +        "description": "hold duration in seconds",
      +        "maximum": 900,
      +        "minimum": 120,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "pace",
      +      "sec"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
  12. Changed1 schema field changed
    • changedInput schema / properties / sftRun / description
      Previous value: -"the athlete's RUNNING fatigue test: the same pace for the same minutes in the warm-up, on a treadmill or a flat loop, then a minute of walking — get_fatigue_tests sport:\"running\" works the pace out from their running. null = stop tracking."New value: +"the athlete's RUNNING fatigue test: about 105% of threshold speed for 3 min (sec 180), frozen for the season, on a treadmill or a flat loop, then a minute of walking — get_fatigue_tests sport:\"running\" proposes it. null = stop tracking."
  13. Changed1 schema field changed
    • changedInput schema / properties / sft / description
      Previous value: -"the athlete's CYCLING submaximal fatigue test (SFT): the fixed load they hold in the warm-up, which get_fatigue_tests then finds in every ride. null = stop tracking. Pick watts that END near 85-90% of their max HR — over 3 min heart rate has not plateaued, so that is usually around FTP, not below it (get_fatigue_tests works it out from their riding) — agree it with them, and do not change it mid-season — a new value starts a new baseline."New value: +"the athlete's CYCLING submaximal fatigue test (SFT): the fixed load they hold in the warm-up, which get_fatigue_tests then finds in every ride. null = stop tracking. The standard protocol (Science to Sport, what intervals.icu detects) is about 110% of FTP for 3 min (sec 180) — get_fatigue_tests proposes it — agree it with them, and do not change it mid-season — a new value starts a new baseline."
  14. Changed2 schema fields changed
    • changedInput schema / properties / sft / description
      Previous value: -"the athlete's submaximal fatigue test (SFT): the fixed load they hold in the warm-up, which get_fatigue_tests then finds in every ride. null = stop tracking. Pick watts that END near 85-90% of their max HR — over 3 min heart rate has not plateaued, so that is usually around FTP, not below it (get_fatigue_tests works it out from their riding) — agree it with them, and do not change it mid-season — a new value starts a new baseline."New value: +"the athlete's CYCLING submaximal fatigue test (SFT): the fixed load they hold in the warm-up, which get_fatigue_tests then finds in every ride. null = stop tracking. Pick watts that END near 85-90% of their max HR — over 3 min heart rate has not plateaued, so that is usually around FTP, not below it (get_fatigue_tests works it out from their riding) — agree it with them, and do not change it mid-season — a new value starts a new baseline."
    • addedInput schema / properties / sftRun
      Added value: +{
      +  "anyOf": [
      +    {
      +      "properties": {
      +        "pace": {
      +          "description": "seconds per km, frozen for the season",
      +          "maximum": 600,
      +          "minimum": 150,
      +          "type": "integer"
      +        },
      +        "sec": {
      +          "description": "hold duration in seconds",
      +          "maximum": 900,
      +          "minimum": 120,
      +          "type": "integer"
      +        }
      +      },
      +      "required": [
      +        "pace",
      +        "sec"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "the athlete's RUNNING fatigue test: the same pace for the same minutes in the warm-up, on a treadmill or a flat loop, then a minute of walking — get_fatigue_tests sport:\"running\" works the pace out from their running. null = stop tracking."
      +}
  15. Changed1 schema field changed
    • changedInput schema / properties / sft / description
      Previous value: -"the athlete's submaximal fatigue test (SFT): the fixed load they hold in the warm-up, which get_fatigue_tests then finds in every ride. null = stop tracking. Pick watts that end near 85-90% of their max HR (roughly threshold or a little under for 3 min), agree it with them, and do not change it mid-season — a new value starts a new baseline."New value: +"the athlete's submaximal fatigue test (SFT): the fixed load they hold in the warm-up, which get_fatigue_tests then finds in every ride. null = stop tracking. Pick watts that END near 85-90% of their max HR — over 3 min heart rate has not plateaued, so that is usually around FTP, not below it (get_fatigue_tests works it out from their riding) — agree it with them, and do not change it mid-season — a new value starts a new baseline."
  16. Changed1 schema field changed
    • addedInput schema / properties / sft
      Added value: +{
      +  "anyOf": [
      +    {
      +      "properties": {
      +        "sec": {
      +          "description": "hold duration in seconds, e.g. 180",
      +          "maximum": 900,
      +          "minimum": 120,
      +          "type": "integer"
      +        },
      +        "watts": {
      +          "description": "absolute watts, frozen for the season — never a % of FTP",
      +          "maximum": 700,
      +          "minimum": 60,
      +          "type": "integer"
      +        }
      +      },
      +      "required": [
      +        "watts",
      +        "sec"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "the athlete's submaximal fatigue test (SFT): the fixed load they hold in the warm-up, which get_fatigue_tests then finds in every ride. null = stop tracking. Pick watts that end near 85-90% of their max HR (roughly threshold or a little under for 3 min), agree it with them, and do not change it mid-season — a new value starts a new baseline."
      +}
  17. First observed

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: safe partial-update semantics, server-side validation, the side effect that changing FTP/weight moves every target, zone manual/auto flipping, and the birthdate ↔ HRmax ↔ maxHr manual-state interactions. This is exactly the behavioral context an agent needs for a destructive-hinted mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and the optional-field contract, and every sentence carries real information. It is dense and parenthetical, which makes it slightly harder to scan than ideal for a 25-parameter tool, but there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, nested, 25-parameter mutation tool with no output schema, the description covers the critical cross-field rules, the safety/confirmation requirement, the read-first workflow, and scope boundaries. Remaining per-field detail is well handled by the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 80%, so the baseline is 3; the description adds valuable cross-field semantics (zoneBounds flips to Manual, autoZones reverts, hrZoneBounds mirrors this, birthdate refreshes the age-based HRmax estimate, writing maxHr marks it manual). It doesn't mention every top-level parameter (prefs, health, kit, control), but the schema documents those well.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Edit) and resource (athlete's profile) and enumerates the field families it covers (FTP, thresholds, zones, about-you). It is unmistakably distinct from read siblings like get_athlete_profile and from update_athlete_file.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says every field is optional, that only changed fields should be passed, and that new numbers must be confirmed with the athlete first. It also routes the agent to read with get_athlete_profile before writing and states the tool never touches the calendar or library.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources