exr-mcp-aws
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., "@exr-mcp-awsPut today's planned row into EXR"
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.
exr-mcp-aws
An MCP (Model Context Protocol) server that lets Claude create custom rowing workouts in EXR, the indoor rowing app. It runs on AWS Lambda as a claude.ai custom connector, so it works in claude.ai on the web, on mobile and in Claude Desktop. Several people can share one deployment, and each signs in with their own EXR account.
It's meant for a training coach in Claude that plans workouts in intervals.icu: Claude reads the planned rowing workout there and creates it in EXR, with the date in the title. That avoids EXR's in-app Training Editor.
"Put today's row into EXR."
"Create the EXR workouts for this week's planned rows."
"Which custom workouts do I have in EXR? Remove the rows from before today."
Tools
Tool | Description |
| Creates a workout from steps in intervals.icu's |
| The custom workouts in the EXR account, newest first: ID, title, description and total length. |
| One workout, block by block: length, power target in % of FTP (or free row) and stroke rate. |
| Removes workouts from EXR, reversibly: it first saves a complete copy of each to the server's archive, and removes nothing if that fails. Only removes workouts created through this server, so ones made in EXR are safe. |
| The archived workouts that can still be restored, and until when. |
| Puts an archived workout back into EXR. |
New workouts show up in the EXR app after a restart, under Training Mode → My Workouts.
Archived workouts can be restored for 5 days (the ArchiveDays parameter in template.yaml). After that, an S3 lifecycle rule purges them. No tool can purge the archive, and the server itself has no permission to delete from it.
From intervals.icu to EXR
EXR workouts are simpler than intervals.icu's, so create_workout converts:
intervals.icu | EXR |
Power in % FTP | The same %, of the FTP set in EXR |
Power in watts | % of |
Range, e.g. 55–65% | Its midpoint, 60% |
Ramp, e.g. 5 min from 45% to 60% | Steps of about a minute (or 250 m), each at the ramp's power halfway through it |
Cadence | Stroke rate (spm) |
Repeats | Written out in full |
Free ride, or a heart rate or pace target | A free-row block (no power target) |
A workout is all timed or all distance-based. EXR can't mix the two, so create_workout refuses workouts that do. Other power units (such as zones) have to be converted to % FTP first.
Related MCP server: Garmin Training MCP
Setup
You need an AWS account and an EXR account.
Install Node.js 20+, the AWS CLI and the SAM CLI, then sign in to AWS with a default region:
winget install OpenJS.NodeJS.LTS
winget install Amazon.AWSCLI
winget install Amazon.SAM-CLI
aws configure # or: aws login
npm install1. Deploy
npm run deployConfirm the changeset when asked. The output ends with McpServerUrl, which people add to claude.ai. sam list stack-outputs shows it again later.
2. Allow your EXR account
npm run admin -- allow you@example.comUse the email address you sign in to EXR with.
3. Connect Claude
In claude.ai, go to Settings → Connectors → Add custom connector and paste the McpServerUrl (it ends in /mcp). Click Connect and sign in with your EXR email and password.
The connector then works on web and mobile, and in Claude Desktop. To use it in a training-coach project, enable it in that project's chat, next to the intervals.icu connector.
Adding someone
Run
npm run admin -- allow their@email.comwith the email of their EXR account.Send them the
McpServerUrl. They add the connector in their own claude.ai account and sign in with their EXR account. On the Free plan, claude.ai allows one custom connector.
Each person sees only their own EXR workouts.
Day to day
Task | Command |
Deploy code changes |
|
Show who can connect |
|
Let someone connect |
|
Stop someone connecting (signs them out) |
|
Sign everyone out |
|
Show the URL |
|
Remove everything |
|
Lambda reads its settings once per cold start, so every admin change also replaces the function's running instances. That way changes take effect immediately.
How it works
EXR: EXR has no API, so the server uses the same pages and forms as a browser on the EXR website's Custom workouts page: it uploads, downloads and deletes workout files there.
Sign-in: claude.ai custom connectors only support OAuth, so the server is a small OAuth server with its own sign-in page. It checks the email against the allowlist, then signs in to EXR with the email and password. The password goes to EXR only; the server keeps nothing but EXR's "remember me" cookie.
Tokens: Claude's access and refresh tokens carry that cookie, encrypted (AES-256-GCM) with a key only the server has. Every hour Claude refreshes its token, and the server checks that EXR still accepts the cookie. If it doesn't, Claude asks you to connect again.
Archive: removed workouts are kept as JSON files in a private S3 bucket, one folder per EXR account, until the lifecycle rule purges them.
Only its own workouts: the server marks the workouts it creates in a hidden ID inside the workout file, and only removes workouts that carry that mark.
No database: apart from the archive, nothing is stored per person. The signing secret and the allowlist are SecureString parameters in SSM Parameter Store, so they never appear in the function's configuration or in the repo.
Cost: normally $0, within Lambda's always-free allowance (1M requests and 400,000 GB-seconds a month). Set up an AWS budget alert anyway.
Running locally
For testing, or for MCP clients on your own machine, the same server runs locally with settings from .env:
Copy
.env.exampleto.envand fill it in. The archive needs an S3 bucket, such as the deployed stack'sArchiveBucketoutput, and AWS credentials that can write to it.Run:
npm run build npm start
The server listens on http://localhost:3000/mcp. For example: claude mcp add --transport http exr http://localhost:3000/mcp.
Known limitations
Logging out of the EXR website signs out every connection to the same EXR account, because EXR then invalidates all of its "remember me" cookies. Claude asks you to connect again.
Relies on EXR's website: a redesign of the Custom workouts page can break the server until it's updated.
Checksum: EXR's workout files carry a checksum whose algorithm isn't public. The server writes its own, which the EXR website and app accept today. A future EXR version could start checking it.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Connect Claude to your Intervals.icu watch data for fitness, workout review, and plan writing.
WHOOP recovery, strain, sleep and workouts in Claude via official WHOOP OAuth. Free, open source.
Garmin data in Claude: 135 tools — activities, sleep, HRV, training, workouts. Free, open source.
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables Claude AI to access and manage intervals.icu training data, including workouts, wellness, and fitness trends, through natural language conversation.MIT
- FlicenseNot gradedqualityBmaintenanceConnects Claude to Garmin Connect to view fitness data and create adaptive training plans for running, swimming, cycling, and strength. Supports both local and VPS deployment with optional Supabase storage.-
- AlicenseNot gradedqualityBmaintenanceConnects to Intervals.icu to let users query training data, create workouts, manage calendar events, and coach athletes through natural language in Claude Desktop.43 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables Claude to read Garmin activities and wellness data, then creates structured workouts that sync to your Garmin watch via Intervals.icu.MIT