rouvy-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@rouvy-mcpHow did my last ride go? Compare the first and second half of the climb."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
rouvy-mcp
Unofficial Rouvy MCP server.
It reads your own Rouvy Activities and serves them to any MCP client (Claude Desktop, Claude Code, Cursor…): list your Activities, read Rouvy's summary of one, and analyse its per-second data (splits, any stretch you pick, downsampled streams). It also reads your own Workouts and, when you ask, creates, changes or deletes them in your Rouvy library. It never writes anything else. It runs locally over stdio, or self-hosted on Cloudflare for web clients such as claude.ai. Please read the disclaimer before you use it.
Install
You need Node.js 22 or later.
1. Log in once, in a terminal:
npx -y rouvy-mcp loginIt asks for your Rouvy email and password (a Rouvy password: Google, Apple or Facebook sign-in alone won't do, but you can set a password on your Rouvy account). The password is never stored. Only a refresh token is kept, in $XDG_CONFIG_HOME/rouvy-mcp/credentials.json (by default ~/.config/rouvy-mcp/credentials.json; %APPDATA%\rouvy-mcp\credentials.json on Windows), readable by you alone.
2. Add the server to your MCP client. For most clients, that's this entry in the MCP config:
{
"mcpServers": {
"rouvy": {
"command": "npx",
"args": ["-y", "rouvy-mcp@latest"]
}
}
}@latest keeps npx from serving an old cached version, so you get the fixes when Rouvy changes something. With Claude Code: claude mcp add rouvy -- npx -y rouvy-mcp@latest.
If you log in after the client has started, there's no need to restart it: the server reads the credentials file on every call.
Optional: exporting files
Set ROUVY_MCP_EXPORT_DIR to an absolute folder path to turn on the export_activity_file tool, which saves an Activity's FIT file, or its per-second records as CSV, into that folder:
{
"mcpServers": {
"rouvy": {
"command": "npx",
"args": ["-y", "rouvy-mcp@latest"],
"env": { "ROUVY_MCP_EXPORT_DIR": "/Users/you/Rouvy exports" }
}
}
}Without it, the tool doesn't exist and rouvy-mcp writes nothing to disk besides the credentials file.
Related MCP server: garmin-raw-mcp
Tools
Tool | What it gives |
| Your Activities, newest first: id, title, type, start, moving time, distance, elevation, TSS, IF. |
| One Activity's summary with Rouvy's own numbers (NP, IF, TSS, power peaks, HR, zones, laps…) and its Activity snapshot (the Rider settings Rouvy stored with it). |
| Fixed-size splits (every 5 min by default) from the per-second Activity file. |
| Stats for one stretch (e.g. a climb from 20:00 to 35:00): best efforts, first half vs second half, HR:power decoupling. |
| Downsampled per-second data (power, heart rate, cadence, speed, altitude, distance), at most 500 points per field. |
| Only with |
| Your own Workouts (the plans in your Rouvy library), newest first: id, name, duration, TSS, difficulty, tags, number of Steps. |
| One of your Workouts: its Steps in % FTP (with cadence ranges), Cues, tags, visibility, route, and your current FTP. |
| Creates a Workout in your library from steady, ramp, free-ride and repeated Steps, with Cues and tags. Private unless you ask. |
| Changes one of your Workouts: only the fields given; new Steps replace them all. A Workout synced from another app may be overwritten by that app's next sync. |
| Deletes one of your Workouts and checks it's gone from your library. Rouvy may keep it readable by its id. |
Try asking: "How did my last ride go? Compare the first and second half of the climb."
Commands
npx -y rouvy-mcp login # log in (or switch accounts)
npx -y rouvy-mcp status # who is logged in, and whether a Session can still be opened
npx -y rouvy-mcp logout # delete the credentials filelogout deletes the credentials file from your machine, but it can't revoke the refresh token on Rouvy's side. To make sure a copied credentials file stops working, change your Rouvy password.
How it behaves
It only calls the routes Rouvy's own web app calls, one request at a time, with an honest user agent (
rouvy-mcp/<version>). It never polls and makes no requests while idle.The only writes it can send are to your own Workouts, and only when a tool you called asks for one. Any other write is refused before it leaves your machine. A write is never retried: if Rouvy fails mid-write, the tool tells you to check
list_workoutsfirst.If Rouvy's bot protection or rate limits push back, it stops and tells you when to try again, rather than retrying. A server error or a network failure gets one retry, 2 s later, and an expired Session is renewed once.
No telemetry and no update check: the only requests it makes go to Rouvy.
Nothing is cached on disk.
If a tool says Rouvy changed its API, update (restart your MCP client: @latest picks up the new version) or open an issue.
Self-host on Cloudflare
The hosted server lets riders connect from a web client such as claude.ai, signing in with their Rouvy email and password on its own page instead of running anything locally. You can run your own, with the same code as the Public instance. This is best effort, with no support promise: if you only need it for yourself, the stdio server above costs nothing.
You are the operator. Riders hand your instance their Rouvy login, and it keeps their refresh tokens (encrypted) on your Cloudflare account. The duties that come with that (a privacy notice, answering access and erasure requests, shutting down if Rouvy objects) are yours, not the project's. Read spec-m2 §10 before you invite anyone.
You need a Cloudflare account on Workers Paid ($5/month: tool calls take 57–305 ms of CPU, over the Free plan's 10 ms) and Node.js 22 or later.
Fork the repo and clone your fork, then
npm ciandnpx wrangler login.Pick the instance's URL,
PUBLIC_URLunder[vars]inwrangler.toml: the bare origin, with no path or trailing slash. Its/mcpis the OAuth audience and sits in every rider's connector, so never change it once riders have connected: every Grant would stop working. Keep "rouvy" out of the hostname.On workers.dev (what the Public instance does): set
nameto your Worker's name, andPUBLIC_URLtohttps://<name>.<your-subdomain>.workers.dev. Then never rename the Worker or your account's workers.dev subdomain.On a custom domain on your Cloudflare account (
mcp.example.orgstands for yours): add these two lines at the top level, above[vars], and setPUBLIC_URLto"https://mcp.example.org":workers_dev = false routes = [{ pattern = "mcp.example.org", custom_domain = true }]
Name yourself as the operator,
OPERATOR_NAMEandOPERATOR_CONTACTunder[vars]: your name and the address riders write to about their data. The privacy notice at<PUBLIC_URL>/privacyand the sign-in page show them. Read the notice before inviting anyone, since it's written for the Public instance: you own its accuracy for yours.Create the KV namespace that holds clients, Grants and tokens, and paste the
idit prints intowrangler.toml's[[kv_namespaces]]:npx wrangler kv namespace create OAUTH_KVThere's nothing to create for the Durable Object: the code puts it in the EU jurisdiction (
RIDERS.jurisdiction("eu")), and the first deploy creates it.Keep both compatibility flags,
nodejs_compatandglobal_fetch_strictly_public. Without the second one, the OAuth provider refuses to fetch a client's metadata document, and claude.ai can't connect.Set the allow-list, the Rouvy emails allowed to sign in, separated by commas or whitespace. Anyone else is told the instance is invite-only.
npx wrangler secret put ALLOW_LISTDeploy with
npm run deploy, which stamps the version, then runswrangler deploy. Check<PUBLIC_URL>/.well-known/oauth-protected-resource/mcp: itsresourceis<PUBLIC_URL>/mcp.Connect: in claude.ai, add a custom connector with the URL
<PUBLIC_URL>/mcp, sign in with an allow-listed Rouvy account, and ask for your last Activities.
Running it: docs/operations.md has how long Grants and tokens live, and how to kill one rider, which is also how you handle an erasure request. To shut your instance down for good, take the same steps as the Public instance's Hard stop runbook, on your own account: close the sign-in page, tell your riders, delete the KV namespace, then the Worker. The repo's daily drift canary only checks the Public instance: watch your own /health (it runs the same account-free checks from your Worker's egress, and reports the block signals the runbook acts on).
Disclaimer
Unofficial project. rouvy-mcp is not affiliated with, endorsed by, or supported by ROUVY or VirtualTraining s.r.o. "ROUVY" is a trademark of its owner.
Rouvy has no public API. This tool talks to Rouvy's private web API with your own account, from your own machine, and only reads data. Rouvy's Terms of Use (§29.h) prohibit reverse engineering and "using any automated means for accessing and using ROUVY". Using this tool may breach those terms, and Rouvy may suspend or terminate your account without a refund (§15, §29.d). The API may change or stop working at any time.
Use at your own risk. The software is provided "as is", without warranty of any kind (see LICENSE). The authors aren't responsible for any consequences to your Rouvy account or data. Nothing here is legal advice.
If you'd rather stay within Rouvy's terms, use Rouvy's official integrations (e.g. Intervals.icu, Strava, Garmin Connect) or request a copy of your data from Rouvy under the GDPR (gdpr@rouvy.com).
License
Available Tools
11 toolscreate_workoutA
Create a Workout in the rider's Rouvy library, only when they ask for one. Steps are steady, ramp or free ride, in % FTP (use get_workout's rider_ftp_w to convert watts), each with an optional cadence range; repeat a block with a repeat Step. Private unless the rider asks for public. Returns the saved Workout as Rouvy has it. If it says the outcome is unknown, call list_workouts before trying again.
| Name | Required | Description | Default |
|---|---|---|---|
| cues | No | Text Cues shown during the Workout. | |
| name | Yes | 1–200 characters. | |
| tags | No | Training effects, at most 3. | |
| steps | Yes | The Steps in order, at least 30 s in all. A repeat is flattened: Rouvy stores and returns flat Steps. | |
| route_id | No | The route to ride it on, as get_workout returns it. Default: Rouvy's suggested route. | |
| visibility | No | private (the default), or public only when the rider asks. | |
| description | No | Free text. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare a non-read-only, non-idempotent, non-destructive write. The description adds real value beyond that: private-by-default visibility, the fact that Rouvy flattens repeat blocks in storage, that the saved Workout is returned, and a specific recovery path for unknown outcomes that directly explains the non-idempotent semantics. Auth/permission behavior is the main omission.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the create action leads, followed by step-model guidance, privacy default, return behavior, and retry rule. No sentence is wasted, though the parenthetical about FTP conversion and the retry clause pack a lot into a small space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter write tool with full schema coverage and no output schema, the description covers invocation gating, step semantics, visibility defaults, return shape, and non-idempotent recovery. Remaining gaps such as permissions or detailed cue/tag semantics are adequately handled by the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description still adds meaning beyond the schema by framing step types (steady, ramp, free ride), the % FTP convention, optional cadence, and repeat blocks, plus the pointer to get_workout for watt conversion.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create a Workout in the rider's Rouvy library') and scopes it with 'only when they ask for one', which clearly separates it from read/update/delete siblings. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the conditions and the alternatives explicitly: use get_workout's rider_ftp_w to convert watts, default to private unless the rider asks for public, and call list_workouts before retrying when the outcome is unknown. These are concrete routing and gating rules rather than implied behavior.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_workoutADestructive
Delete one of the rider's own Workouts from their Rouvy library, only when they ask, and check it's gone. Warning: a Workout synced from another app (TrainingPeaks, Intervals.icu…) may come back with that app's next sync. Returns the deleted Workout's id and name.
| Name | Required | Description | Default |
|---|---|---|---|
| workout_id | Yes | A Workout id as returned by list_workouts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds genuinely new behavior beyond the destructiveHint/readOnlyHint annotations: it verifies the deletion afterward ("check it's gone") and warns that workouts synced from TrainingPeaks/Intervals.icu may reappear on the source app's next sync — a non-obvious side effect critical for an agent deciding whether to delete. It also discloses the return payload (deleted Workout's id and name), filling the gap left by the absent output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences, front-loaded with the core operation and guardrail, followed by the sync warning and return value. Every sentence earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and a single fully-documented parameter, the description covers what is needed: scope, guardrail, side-effect warning, verification behavior, and return values. Nothing an agent needs in order to call this safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the workout_id parameter already documents its format and provenance ("as returned by list_workouts"). The description adds nothing about the parameter beyond that, which is appropriate given the schema does the work — baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Delete ... Workouts from their Rouvy library") and scopes it to the rider's own library, clearly distinguishing it from sibling read/list/create/update workout tools. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Only when they ask" gives an explicit guardrail for this destructive operation, which is exactly the context an agent needs for a delete. It does not explicitly name the alternative flow (e.g., use list_workouts to find the id, get_workout to confirm) — though the schema description points to list_workouts for the id — so it stops just short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_activity_fileA
Save one Activity to the rider's export folder: its Activity file as downloaded from Rouvy (fit), or its per-second records as CSV (csv). Overwrites an earlier export of the same Activity and returns the file's absolute path.
| Name | Required | Description | Default |
|---|---|---|---|
| format | No | fit: the Activity file; csv: per-second records. | csv |
| activity_id | Yes | An Activity id as returned by list_activities. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations, so the description must carry the behavioral burden. It usefully discloses the key side effect that an earlier export of the same Activity is overwritten and that the tool returns the file's absolute path, though it does not mention permissions, error conditions, or the exact export folder location.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that covers purpose, format options, overwrite behavior, and return value. It is dense but efficient, with no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with full schema coverage and no output schema, the description is complete enough: it explains what is saved, the format choices, the overwrite behavior, and the returned absolute path. Missing details such as permissions or exact folder location are minor for this low-complexity operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents activity_id and the fit/csv format enum. The description reinforces that fit is the downloaded Rouvy Activity file and csv is per-second records, but adds little beyond the schema's own parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: saving one Activity to the rider's export folder. It also identifies the two supported formats and their meanings, so an agent can distinguish this export operation from sibling read/list tools without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when this tool applies by saying it saves one Activity to the export folder, but it does not explicitly compare it with alternatives such as get_activity or get_activity_streams. It also does not state when not to use it or any prerequisite workflow for obtaining activity_id.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_activityA
One Activity's summary, with Rouvy's own numbers (they match the Rouvy app): times, distance, elevation, kcal, NP, IF, TSS, power peaks, min/max/avg power, heart rate, cadence and speed, %FTP, time in power and HR zones, laps and route segment results. Also the Rider settings used (FTP, weight, max HR, zones) from the Activity snapshot, which data exist, and a note for each value left out.
| Name | Required | Description | Default |
|---|---|---|---|
| activity_id | Yes | An Activity id as returned by list_activities. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does meaningful work: it discloses that values come from a stored Activity snapshot (so Rider settings may reflect the time of recording), that it reports which data exist, and that every omitted value gets an explanatory note. It does not state read-only nature, error behavior for a malformed id, or cost/latency, but the omission handling is real, non-obvious context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then a dense but informative metric inventory, then the less obvious Rider-settings and omitted-value notes. The single long sentence is heavily comma-listed but nearly every item carries selection value; only mild tightening is possible.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema and no annotations, so the description must convey return content, and it does so thoroughly, including snapshot semantics and missing-data notes. It falls short only on sibling differentiation and on any statement about safety, failure modes, or size of the response for an activity with many laps and segments.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single activity_id parameter is documented with a pattern and a pointer to list_activities, so the schema does the heavy lifting. The description adds only the notion that the id identifies 'one Activity' whose snapshot is read, which is marginal beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource ('One Activity's summary') and enumerates exactly what is returned: times, distance, elevation, power/HR/cadence metrics, zone times, laps, segment results, plus the Rider settings snapshot. This is far more concrete than the bare name, though it never explicitly distinguishes itself from siblings like get_activity_intervals, get_window_stats, or get_activity_streams.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The word 'summary' plus the enumeration of aggregate metrics implies this is the whole-activity overview rather than the interval or stream views, but the agent is left to infer that. There is no explicit when-to-use or when-not-to-use guidance naming the alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_activity_intervalsA
Fixed-size splits of one Activity (every 5 min by default), from its per-second Activity file. For each split: start/end second, avg, NP and max power, avg power as %FTP, avg/max heart rate, avg cadence, avg speed, distance and climbing. %FTP uses the FTP from the Activity snapshot. A note says why any stat is left out.
| Name | Required | Description | Default |
|---|---|---|---|
| every_sec | No | Split length in seconds (at least 10). | |
| activity_id | Yes | An Activity id as returned by list_activities. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the data source (per-second Activity file), that %FTP derives from the Activity snapshot FTP rather than current FTP, and that missing stats come with an explanatory note. It stops short of stating failure modes (missing streams, permission needs), so it is not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core definition is front-loaded in the first sentence, followed by a compact field enumeration and two short clarifications. Every sentence carries information, though the field list is dense enough to be slightly list-like rather than prose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema and no annotations, so the description must explain the return payload, which it does thoroughly by naming every returned statistic plus the explanation field. Combined with the source-of-truth note for %FTP, an agent has enough to call and interpret results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented, and the description's 'every 5 min by default' merely restates the schema default of 300. It adds only light framing ('fixed-size splits') without new format or constraint detail, matching the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (splits of one Activity) and a concrete operation, and it enumerates the returned statistics so the agent knows exactly what a call yields. It doesn't explicitly contrast itself with the closest sibling, get_window_stats, but the 'fixed-size splits' framing makes the distinction reasonably inferable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the fixed-size split framing and the default 5-minute interval, so an agent can infer this is for binned whole-activity analysis. However, there is no explicit statement of when to prefer this over get_window_stats or get_activity_streams, and no exclusions or prerequisites (e.g. activity must have a per-second file) are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_activity_streamsB
Downsampled per-second data of one Activity, from its Activity file, to chart or reason about: one array per field, each value the mean of one bucket of resolution_sec_used seconds from start_sec (the last bucket may be shorter). Units: power W, heart_rate bpm, cadence rpm, speed m/s, altitude m, distance m from the start. At most 500 points per field: a finer request is served at the smallest resolution that fits. A field the Activity doesn't have is listed in missing_fields; a bucket with no data is null.
| Name | Required | Description | Default |
|---|---|---|---|
| fields | No | Which columns to return. | |
| end_sec | No | End, in seconds from the start (after start_sec; default the end of the Activity). | |
| start_sec | No | Start, in seconds from the start (default 0). | |
| activity_id | Yes | An Activity id as returned by list_activities. | |
| resolution_sec | No | Bucket length in seconds (at least 1). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No behavioral disclosure beyond the mechanics of the data: there is no statement of whether the tool is read-only, what permissions it requires, what errors occur for an invalid activity_id, or whether calls are rate-limited. The description does explain what the return value contains (one array per field, means, unit strings, nulls for empty buckets, missing_fields), which is valuable, but for a tool with no annotations at all, it leaves the operational characteristics largely undisclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is front-loaded with the essential statement ('Downsampled per-second data of one Activity') and sustains a tight chain of semicolon-separated clauses without repetition. It is dense and slightly run-on with nested parentheses, but every sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
It covers the return shape well enough without an output schema: how arrays are nested, how missing fields are reported, and how empty buckets are nulled. It still omits the shape of the missing_fields container itself and any failure modes or limits, which matters for a five-parameter read tool with no annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema supplies the baseline. The description adds real meaning: it defines buckets as resolution_sec_used-second means starting from start_sec, notes that the last bucket may be shorter, and fixes units per field (W, bpm, rpm, m/s, m, m). It also explains the 500-point cap and the behavior when a finer resolution is requested. That goes beyond the schema's field-level text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific operation and resource: downsampled per-second data for one Activity, taken from its Activity file. It also describes the value of the result: chart it or reason about it. It does not name sibling tools such as get_window_stats or get_activity_intervals, so an agent must still infer why it should choose streams over aggregates.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase "to chart or reason about" only implies the intended use (time-series visualization) without stating when to use this tool versus get_window_stats or get_activity_intervals. No exclusions or prerequisites are given, so selection guidance is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_window_statsA
Stats for one stretch of an Activity (e.g. a climb from 20:00 to 35:00), from its per-second Activity file: the same stats as one split of get_activity_intervals, plus the best efforts (peak powers for the durations that fit), the first half vs the second half, and HR:power decoupling between them. %FTP uses the FTP from the Activity snapshot. A note says why any stat is left out.
| Name | Required | Description | Default |
|---|---|---|---|
| end_sec | Yes | Window end, in seconds from the start (after start_sec). | |
| start_sec | Yes | Window start, in seconds from the start of the Activity. | |
| activity_id | Yes | An Activity id as returned by list_activities. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and discloses substantive behavior: it computes from the per-second file, adds best efforts, first-half vs second-half comparisons, HR:power decoupling, uses FTP from the Activity snapshot, and includes notes for omitted stats. It does not mention read-only safety, required data availability, or performance characteristics, but the output behavior is well covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three tight sentences with no filler. It front-loads what the tool returns and then adds the substantive extras and caveats; every clause carries useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must explain return values, and it does so at a useful level: core stats, best efforts, half comparisons, decoupling, FTP source, and omission notes. It could go further on exact stat definitions, but referencing get_activity_intervals helps anchor the missing detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description's example 'climb from 20:00 to 35:00' reinforces the start/end window semantics, but it adds no parameter-specific format, bounds, or edge-case detail beyond what the schema already documents.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (stats for one time window of an Activity) and scope (from the per-second Activity file). It also explicitly relates the output to a split of get_activity_intervals and lists the extra metrics, so an agent can distinguish it from sibling tools without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It implies when to use this tool by saying it returns 'the same stats as one split of get_activity_intervals, plus...' for a custom window. That gives clear context against the sibling, but it lacks an explicit exclusion or statement of when to prefer get_activity_intervals instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_workoutBRead-only
One of the rider's own Workouts: name, description, tags, visibility, duration, TSS, IF, difficulty, route, its Steps (steady, ramp or free ride, in % FTP, with an optional cadence range) and Cues (text at a time from the start). Also rider_ftp_w, the rider's current FTP in watts, to turn watts into % FTP.
| Name | Required | Description | Default |
|---|---|---|---|
| workout_id | Yes | A Workout id as returned by list_workouts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety is covered. The description adds substantial value beyond annotations by documenting the returned workout structure, including Steps types and Cues, plus rider_ftp_w for interpreting watts as % FTP. It omits error behavior for invalid ids, but the return-content disclosure is strong for a no-output-schema tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single dense sentence, front-loaded with the resource scope before listing return fields. The long field list is justified because there is no output schema, though the lack of an explicit action verb makes the opening slightly less crisp than it could be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter read tool with a fully documented schema and readOnly annotation, the main missing structured information is the return shape, and the description covers that extensively. It does not fully explain when to choose this over list_workouts, but overall it is complete enough to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is only one parameter and schema coverage is 100%, so the schema already explains workout_id fully, including that it comes from list_workouts. The description adds only the implication that the returned workout belongs to the rider; baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource as one of the rider's own workouts and enumerates its fields, so retrieval is strongly implied. However, it never states a retrieval verb such as 'get' or 'retrieve', and it does not explicitly distinguish itself from list_workouts or the mutation siblings. The purpose is understandable but requires inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit guidance on when to use this tool versus list_workouts or get_activity. The schema says workout_id comes from list_workouts, but the description itself gives no usage conditions, prerequisites, or alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_activitiesA
List the rider's Rouvy Activities, newest first, as compact rows (id, title, type, start, moving time, distance, elevation, TSS, IF). Use the ids with the other tools.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many Activities to return (1–50). | |
| offset | No | How many of the newest Activities to skip. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the behavioral load. It discloses ordering (newest first), that rows are compact rather than full detail, and the exact field set — good transparency — but says nothing about read-only nature, result-count limits, or what happens past 50 items.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the verb and resource, then the return shape and the follow-up hint. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so listing the returned columns is valuable and largely fills that gap; all parameters are schema-documented. Only minor gaps remain around read-only assurance and ceiling behavior, which are small for a simple paginated list tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both limit and offset are already documented, giving a baseline of 3. The description adds a little beyond the schema by stating results are newest first, which clarifies what offset skips in practice.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (the rider's Rouvy Activities) plus ordering (newest first) and the exact columns returned. That shape makes it immediately distinguishable from get_activity (single item) and get_window_stats (aggregates) without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use the ids with the other tools' implies this is an entry point for ID discovery, which is useful chaining context. However, there is no explicit when-to-use guidance versus get_activity or the list_workouts siblings, and no stated condition for choosing it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_workoutsARead-only
List the rider's own Workouts in their Rouvy library (the plans, not the rides), newest first, as compact rows (id, name, duration, TSS, difficulty, tags, number of Steps). Use get_workout for the Steps.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many Workouts to return (1–50). | |
| offset | No | How many of the newest Workouts to skip. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, but the description adds real behavior: ordering ('newest first'), the compact-row payload (id, name, duration, TSS, difficulty, tags, step count), and the deliberate exclusion of Steps. What it omits is pagination behavior beyond the offset hint, which is a minor gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence plus a short routing clause, both front-loaded and waste-free. Every phrase (scope, ordering, return shape, sibling pointer) carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There's no output schema, yet the description enumerates the row fields an agent will receive and flags that Steps are excluded, which is exactly the missing context. With only two optional params of documented semantics, nothing needed to call it correctly is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description earns credit by clarifying that 'newest first' ordering is what offset counts against ('How many of the newest Workouts to skip' is reinforced in prose). That ordering semantics is the one piece of meaning the schema alone doesn't convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the rider's own Workouts in their Rouvy library') and immediately disambiguates with '(the plans, not the rides)', which cleanly separates it from list_activities. An agent can pick this tool over its siblings without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to get_workout for the Steps, which is the one obvious follow-up action. It doesn't spell out when to prefer list_activities over this tool beyond the 'plans, not rides' aside, so it stops just short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_workoutADestructiveIdempotent
Change one of the rider's own Workouts, only when they ask. Give only what changes: steps, when given, replace all Steps; every field left out (cues included) keeps its current value; the route is kept. A get_workout result can be edited and passed back as is. Warning: a Workout synced from another app (TrainingPeaks, Intervals.icu…) may be overwritten by that app's next sync. Returns the saved Workout.
| Name | Required | Description | Default |
|---|---|---|---|
| cues | No | Text Cues shown during the Workout. | |
| name | No | 1–200 characters. | |
| tags | No | Training effects, at most 3. | |
| steps | No | The Steps in order, at least 30 s in all. A repeat is flattened: Rouvy stores and returns flat Steps. | |
| visibility | No | private (the default), or public only when the rider asks. | |
| workout_id | Yes | A Workout id as returned by list_workouts. | |
| description | No | Free text. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=true; the description then explains exactly what that destruction means: supplying steps replaces all Steps, omitted fields (cues included) are preserved, and the route is kept. It also warns that externally synced workouts may be overwritten by the next sync and states the return value, which are real behavioral disclosures not in the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five tight sentences in a deliberate order: purpose, patch semantics, workflow hint, destructive warning, return value. No filler, and the scoping constraint is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-param mutation with no output schema, the description covers scope, partial-update behavior, the sync overwrite hazard, and the returned object. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds genuinely schema-absent semantics: patch-style omission behavior per field, all-or-nothing replacement of steps, route preservation, and that visibility should be public only on request. That is meaningful meaning beyond the schema's per-field type descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb (Change) and resource (one of the rider's own Workouts), and the ownership qualifier plus 'only when they ask' distinguishes it from create_workout and delete_workout in the sibling list. An agent can route here without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Only when they ask' sets a clear activation condition, and 'a get_workout result can be edited and passed back as is' implies the read-then-update workflow against the get_workout sibling. It stops short of explicitly excluding create_workout when no workout exists yet, but the context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
11 tool updates
v0.3.0- First observed
create_workout - First observed
delete_workout - First observed
export_activity_file - First observed
get_activity - First observed
get_activity_intervals - First observed
get_activity_streams - First observed
get_window_stats - First observed
get_workout - First observed
list_activities - First observed
list_workouts - First observed
update_workout
TDQS
Scored across 11 tools
Each tool has a clearly distinct role, and the descriptions explicitly differentiate them (summary vs. fixed splits vs. arbitrary window vs. raw stream). The closest pair is get_activity_intervals and get_window_stats, which return the same stat family and can overlap if a window matches a split, but the fixed-vs-arbitrary distinction is spelled out well enough to choose correctly.
Almost everything follows a consistent snake_case verb_noun pattern grouped by resource (activities, workouts), with get/create/update/delete_workout forming a clean CRUD set. The only wobble is get_window_stats, whose noun omits the 'activity' resource seen in every other activity tool.
Eleven tools is well within the sweet spot and each one earns its place: four read tools for activity analysis, five for the workout lifecycle, one for export. No redundant or filler tools are present.
Workouts have full CRUD and activities have a rich read/analysis/export surface, so the main workflows are covered. Minor gaps remain: no standalone rider-profile/settings tool (FTP only surfaces via get_workout), no route listing to attach to a created workout, and no activity delete or route browsing.
Maintenance
Related MCP Connectors
Strava MCP tools for AI: athletes, activities, segments, clubs, routes. Powered by HAPI MCP server.
- FlaMapOAuthapp.flamap
Your own cycling data for your AI assistant: rides, power, climbs and routes. Read-only.
Read your workouts, history, and stats; create and schedule new workouts. Writes are additive only.
Your swim, bike and run training: readiness, HRV, sleep, workouts and race predictions. Read-only.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceMCP server to fetch Strava activities using OAuth authentication with automatic token refresh. Allows retrieving recent activities, activities by date range, activity details, and athlete stats.-
- AlicenseNot gradedqualityBmaintenanceProvides raw Garmin Connect data access for training analysis, enabling retrieval of activity summaries, lap data, time-series streams, comments with lactate, wellness metrics, and personal records through an MCP interface.MIT
- AlicenseBqualityAmaintenancePrivacy-first MCP server for Strava activities, streams, routes and training data.2969 npm3MIT
- AlicenseBqualityAmaintenanceMCP server for local fitness-data extraction and analysis from Garmin Connect, Intervals.icu, and Strava. Provides read-only analytical tools over DuckDB and targeted Strava enrichment.351,792 npm1AGPL 3.0