Suunto watch data (workouts, sleep, recovery, 24/7 activity) for Claude and other AI assistants.
Ask Claude anything about your training. Suunto MCP connects your Suunto watch data to Claude so you can just talk to your data instead of clicking through dashboards.
Built by a Suunto user who wanted to ask "how was my last long run?" and get a real answer with numbers β and to feed live training data into a personal AI coach.
π For regular Suunto users: Suunto's API docs say access is for commercial partners only β that's not the full picture. Private users get access too. It just takes 3β4 weeks for approval after you apply. Submit, wait, enjoy. Don't let that disclaimer stop you. β
Once it's set up, just ask:
Claude figures out what data to pull. You just ask.
It's not just read-only either β Claude can push things to your watch too:
See What you can push to your watch below.
If you already have Claude Code, you don't need to run a single terminal command. Just open it and say:
"Please install and set up suunto-mcp from https://github.com/googlarz/suunto-mcp"
Claude Code will clone the repo, run all the install commands, and add everything to your Claude Desktop config β on its own. That's exactly how this project's author set it up: no manual terminal work.
Three things stay yours no matter what, by design, not because of missing tooling:
Claude will tell you exactly what to do and when for each of these.
If you want to do it manually, keep reading.
Before starting, make sure you have:
Once it's done, you never redo it.
Prefer one guided walkthrough with a pacing choice up front (fast path vs. explained-step-by-step) and a proper explanation of how syncing works? See GETTING_STARTED.md. What follows here is the same steps in reference form.
The setup has three parts:
Suunto has a free developer portal called apizone where you register apps that can access your data. You'll create an account, subscribe to the data plan, and register a small "app" β don't worry, there's nothing to build, it's just a name and a password you make up.
Go to apizone.suunto.com and sign up or sign in.
Use the same email you use for the Suunto app. If you have a Sports Tracker account, that works too β it's the same login system.
After signing in, follow the How to start guide β it walks you through subscribing to the Developer API. This is free and gives you access to your workout history.
Heads up: Suunto's website states that API access is only for commercial partners β ignore that. Private users do get access, it just takes 3β4 weeks for the subscription to be approved. Submit it and wait. It will come through.
You may see other products like "Sleep API", "Recovery API", "Daily Activity API". Skip those for now β the Developer API is enough to get started. You can add the others later if you want sleep and recovery data in Claude.
β³ Stop here and wait. Once you've subscribed, Suunto needs to approve your request. This takes 3β4 weeks. You'll get an email when it's done. Come back to Steps 3β4 only after your subscription shows as Active in your apizone profile.
You're going to tell Suunto: "I have a small program, here's its name and a secret password β please let it read my data."
Go to your apizone profile page
Scroll down to OAuth application settings
Fill in the form:
| Field | What to enter |
|---|---|
| App name | suunto-mcp (or anything you like) |
| Client secret | Make up a unique password β something only you'd know, e.g. alice-suunto-2026 with your own name. Write it down. Don't use this exact example. |
| Redirect URI | http://localhost:8421/callback β copy this exactly |
Click Save
After saving, the form shows a Client ID β a long code that Suunto generated for you. Copy it.
What are these three things? β Client ID: your app's username, generated by Suunto β Client Secret: your app's password, chosen by you β Redirect URI: where Suunto sends you back after you approve access β must match exactly, typos break it
The Client Secret is never shown again after you save. If you forget it, just set a new one in the same form.
The subscription key is a second passcode that goes on every data request. Here's how to find it:
Save all three values before continuing β you'll need them in Part 2:
Used the "Let Claude Code install it" option above? Claude already ran every command below β skip to Part 3. These steps are for anyone doing it by hand.
Open Terminal on Mac (press βSpace and type "Terminal") or Command Prompt on Windows. Then run these commands one at a time:
git clone https://github.com/googlarz/suunto-mcp
cd suunto-mcp
npm install
npm run build
This downloads the code, installs what it needs, and builds it. Takes 1β2 minutes. If you see any errors, check the Troubleshooting section.
You'll create a file called .env in the suunto-mcp folder and put your three values in it. Even if Claude is doing the rest of this for you, type these three values in yourself rather than pasting them into the chat β keeps them out of your conversation history.
On Mac:
cp .env.example .env
open -e .env
This copies the template and opens it in TextEdit. Replace each placeholder with your actual values, then save and close.
On Windows:
copy .env.example .env
notepad .env
The file looks like this β replace the parts after the = signs:
SUUNTO_CLIENT_ID=your-client-id-here
SUUNTO_CLIENT_SECRET=your-client-secret-here
SUUNTO_SUBSCRIPTION_KEY=your-subscription-key-here
Save and close the file.
Only if you want to push guided workouts to your watch (see What you can push), add one more line:
SUUNTO_APP_NAME=your-app-name-hereβ it must exactly match the app name you registered on apizone.suunto.com in Step 3, or the watch will reject the upload. Not needed for anything else.
npm run auth
Here's exactly what happens:
β Terminal β you see a long URL printed and the message "Opening Suunto authorization in your browserβ¦"
β‘ Browser opens β Suunto's login page appears. It looks identical to the Suunto app login: email + password fields at the top, then "Sign in with Apple" and "Sign in with Facebook" below. Sign in with whichever you use.
β’ Permissions screen β after logging in, a screen appears asking you to approve access for "suunto-mcp". It lists what the app will be able to read (your workouts). Click Authorize.
β£ Browser confirmation β the page shows: "Suunto MCP connected. You can close this tab."
β€ Terminal confirmation β prints: "Paired successfully. Tokens saved."
Done β you won't need to do this again. The connection stays active and renews itself automatically.
Browser didn't open automatically? Copy the long URL from the terminal and paste it into your browser manually.
npm run doctor
This runs a health check. You should see output like:
Suunto MCP β health check
β Node version 20.18.0 (require β₯ 20)
β Credentials client_id, client_secret, subscription_key set
β Network reachability reachable
β Pairing paired (user: your-username), token expires in 47 min
β API probe (workouts) received 1 workout
If any line shows β, the message tells you exactly what to fix. Resolve any issues before moving on.
Used the "Let Claude Code install it" option? This part is done too β Claude edited your config directly. Restart Claude Desktop and jump to Step 11.
Now you'll tell Claude Desktop where to find Suunto MCP.
Open this file in a text editor (create it if it doesn't exist yet):
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.jsonQuick way on Mac β run this in Terminal:
mkdir -p ~/Library/Application\ Support/Claude && open -e ~/Library/Application\ Support/Claude/claude_desktop_config.json
Quick way on Windows β run this in Command Prompt:
notepad "%APPDATA%\Claude\claude_desktop_config.json"
(If it asks "file not found β create it?", click Yes.)
First, find the actual path to the suunto-mcp folder. In Terminal, while inside the folder, run:
pwd
It'll print something like /Users/yourname/suunto-mcp. Copy that.
Now paste the following into the config file. Replace /Users/yourname/suunto-mcp with the path you got from pwd, and replace the credential placeholders with your actual values.
If the file already has other servers configured, don't replace the whole file β just add the
"suunto"section alongside them. The structure must be valid JSON, so keep all the curly braces balanced. When in doubt, compare your file to the example below.If the file is empty, paste the whole block as-is.
{
"mcpServers": {
"suunto": {
"command": "node",
"args": ["/Users/yourname/suunto-mcp/dist/index.js"],
"env": {
"SUUNTO_CLIENT_ID": "your-client-id",
"SUUNTO_CLIENT_SECRET": "your-client-secret",
"SUUNTO_SUBSCRIPTION_KEY": "your-subscription-key"
}
}
}
}
To also push guided workouts to your watch, add one more line inside "env": put a comma at the end of the SUUNTO_SUBSCRIPTION_KEY line, then add "SUUNTO_APP_NAME": "your-app-name" (exactly the app name registered on apizone) on a new line after it. If you only ask Claude about your data, you don't need it.
Anything the server needs must be in this "env" block β a .env file is only read by the terminal commands (npm run auth, npm run doctor, the CLI) when you run them from this folder.
Save the file.
Three things, in order β this is the only part of setup nothing can do for you:
"What was my most recent workout?"
If Claude answers with your actual sport, date, and distance β you're done. If it doesn't, don't guess β go to Troubleshooting.
You: Compare my last three long runs. Has my heart-rate drift improved?
Claude: Looking up your workoutsβ¦
Found 3 runs over 90 minutes in the last 6 weeks:
β’ Apr 12 β 22.4 km, 2h09, avg HR 148, last-30min drift +6 bpm
β’ Apr 19 β 24.0 km, 2h21, avg HR 144, last-30min drift +4 bpm
β’ Apr 26 β 25.1 km, 2h28, avg HR 142, last-30min drift +2 bpm
Drift is trending down despite slightly longer runs β your aerobic
base is improving. Pace at the same HR is also ~3 s/km faster.
| Category | What you can ask about | Requires |
|---|---|---|
| Workouts | Any recorded activity β runs, hikes, rides, swims, ski tours. Distance, time, heart rate, pace, elevation, power, and lap-by-lap data for guided sessions. | Developer API (already subscribed) |
| Sleep | Sleep duration, stages (light/deep/REM), sleep score. | Sleep API subscription on apizone |
| Recovery | Recovery balance and stress state through the day (HRV comes with the sleep data). | Recovery API subscription on apizone |
| Daily activity | Steps, calories, 24/7 heart rate. | Daily Activity API subscription on apizone |
To add sleep, recovery, or daily activity: go back to apizone.suunto.com, find each product, and subscribe. Then run npm run doctor to confirm they're active.
Suunto MCP isn't read-only. Claude can also send things back to your account:
| You want to | Ask Claude | Requires |
|---|---|---|
| Get a gym plan on your wrist | "Plan today's workout and send it to my watch" | SUUNTO_APP_NAME set (see Step 6) |
| Upload a workout from another device | "Upload this FIT file as a Suunto workout" | β |
| Grab a saved route as GPX | "Export my Sunday route as GPX" | β |
Guided workouts show up as a SuuntoPlus Guide: exercise name and weight/reps on screen, lap button advances to the next one, a stopwatch (not a countdown) between exercises with a preview of what's next, a vibrate when a new exercise starts, and a "session complete" screen at the end. There's no live push to the watch itself β it appears after your phone's next normal Suunto app sync, same as any other watch data.
This pairs naturally with a coaching workflow: describe your goals, equipment, and current lifts to Claude, and it can write a real progressive program and push each session directly β see Pairs well with health-skill below for recovery-aware programming.
Ask Claude "generate my daily digest for yesterday" and it writes a color-coded markdown summary β steps, sleep, recovery balance, HRV, and a training-load model (Fitness/Fatigue/Form) β appended to SUUNTO_HISTORY.md in the folder the server runs from (set SUUNTO_DIGEST_HISTORY_PATH to choose another file).
Fitness (CTL), Fatigue (ATL), and Form (TSB) aren't Suunto API fields β there's no endpoint for them. They're computed here from each workout's real tss.trainingStressScore using standard 42-day/7-day exponential decay, the same math training-load tools like TrainingPeaks use. The running values persist in ~/.suunto-mcp/averages.json (override with SUUNTO_DIGEST_AVERAGES_PATH) since there's nowhere else to keep them.
A few things worth knowing before you rely on it:
--seed-ctl 42 --seed-atl 38 on the CLI. Only works on the first-ever digest; ignored after that.CLI: suunto-mcp daily-digest 2026-04-20 [--seed-ctl 42 --seed-atl 38]. MCP tool: generate_daily_digest.
Always run npm run doctor first β it pinpoints most problems automatically.
| What you see | What it means | How to fix it |
|---|---|---|
| Claude returns an error or nothing | Something isn't connected yet | Run npm run doctor and fix any lines with β |
| Empty workout list | Watch hasn't synced recently | Open the Suunto app on your phone and wait for the sync to complete |
| "Not authenticated" | The pairing step didn't finish | Run npm run auth again |
| You logged in but nothing happened | The browser tab closed or timed out before Suunto confirmed | Close all Suunto tabs and run npm run auth again β click Authorize promptly |
| "Token request failed" or "400 error" | Client Secret or Redirect URI don't match apizone | Go to apizone β profile β OAuth application settings and confirm both values match exactly |
| "401" error on every request | Subscription key is wrong or incomplete | Go to apizone β profile β Subscriptions, reveal and re-copy the Primary Key |
| "403 Forbidden" on workouts | Developer API subscription isn't active | Sign in to apizone and confirm it's listed as Active |
| Sleep / recovery / activity returns "not found" | Those need separate subscriptions | Go to apizone and subscribe to the Sleep, Recovery, or Daily Activity API |
| Got an SSL error after Apple sign-in | Known Suunto quirk with Apple login | Close the error tab, go back to the auth URL the terminal printed, and continue |
| "State mismatch" error | A second auth flow started before the first finished | Close all auth-related tabs and run npm run auth fresh |
npm run build failed with an error | Node.js version too old or not installed | Run node --version β it must be 20 or higher. Reinstall from nodejs.org |
| Terminal says "EADDRINUSE" or port in use | Something else is using port 8421 | Restart your computer, or run lsof -i :8421 to see what's using it |
| Guide upload fails with an "owner" error | SUUNTO_APP_NAME doesn't exactly match your registered app name | Check apizone β your app β confirm the exact name, fix the env var, restart Claude |
| Pushed a guide but it's not on the watch | Watch hasn't synced with your phone yet | Open the Suunto app and let it sync; it should appear without any extra steps |
Is this safe? Will Suunto lock my account? Suunto built this API specifically for people to connect their own tools β it's explicitly allowed. You're using it exactly as intended.
Is my data leaving my computer? Your data travels directly between your computer and Suunto's servers. Suunto MCP is just the bridge. When Claude asks about your workouts, it goes: Claude β Suunto MCP (on your machine) β Suunto's servers β back. No third-party services see your data.
Which Suunto watches work? Any watch that syncs to the Suunto app: Race, Vertical, 9 Peak Pro, 9 Peak, 5 Peak, Wing, Ocean, and older models. If it appears in your Suunto app, it works here.
Do I need to do anything when I record a new workout? No. Just ask Claude β it always pulls live data from Suunto.
What if I want to disconnect and stop using this? See Disconnecting below. You can fully revoke access in under a minute.
Can I use this with AI apps other than Claude? Yes β anything that supports MCP: Claude Code, Cursor, Windsurf, and others.
My Suunto app username is different from my email β which do I use? Use your email address to sign in to apizone. Your username will appear once you're authenticated.
~/.suunto-mcp/tokens.json β not uploaded anywhere.To fully remove access:
rm -f ~/.suunto-mcp/tokens.json
"suunto" block from your Claude config and restart Claude.If you use googlarz/health-skill β a Claude skill for symptom triage and health Q&A β you can connect both to Claude: health-skill handles the health side while Claude reads your training, sleep, and recovery data from Suunto MCP in the same conversation. Together they can answer questions like "given my recovery scores this week, should I keep tomorrow's interval session?" with real numbers.
The same combination works for planning, not just Q&A: Claude can check your actual HRV and sleep before writing a session, scale it back on a bad recovery day instead of a generic one, and push the result straight to your watch with push_strength_guide (gym) or push_interval_guide (cardio). Ask for it directly β "check my recovery and plan today's gym session" β no extra setup beyond having both connected.
To also store your daily step counts in health-skill's own records, run suunto-mcp sync-to-health-skill --health-root <your health folder> (add --person-id for a household member). It copies steps only, and only for days that are finished β today's total is picked up tomorrow.
For the full version β real progressive-overload programming that persists week to week instead of a one-off ask β install googlarz/gym-skill: /gym setup once, then /gym plan//gym today//gym log//gym review going forward.
The package is published on npm as suunto-mcp, so you can skip Step 5 (no git clone, no build). You still need Node.js 20 or newer and the credentials from Part 1.
Pair your account (replaces Step 7). Run these in a terminal, with your own values:
export SUUNTO_CLIENT_ID=your-client-id SUUNTO_CLIENT_SECRET=your-client-secret SUUNTO_SUBSCRIPTION_KEY=your-subscription-key
npx -p suunto-mcp suunto-mcp-auth
npx -p suunto-mcp suunto-mcp-doctor
The first command opens the browser pairing page and saves your tokens to ~/.suunto-mcp/tokens.json; the second checks that everything is connected.
Connect to Claude Desktop (replaces Step 10). Use npx instead of a path to the code:
{
"mcpServers": {
"suunto": {
"command": "npx",
"args": ["-y", "suunto-mcp"],
"env": {
"SUUNTO_CLIENT_ID": "your-client-id",
"SUUNTO_CLIENT_SECRET": "your-client-secret",
"SUUNTO_SUBSCRIPTION_KEY": "your-subscription-key"
}
}
}
}
The first start downloads the package, so it can take a few seconds. To stay on one version, write "suunto-mcp@0.15.1" in args. In Claude Code: claude mcp add suunto -e SUUNTO_CLIENT_ID=... -e SUUNTO_CLIENT_SECRET=... -e SUUNTO_SUBSCRIPTION_KEY=... -- npx -y suunto-mcp.
Run this in a terminal (use your own values and the real path to this folder), then claude mcp list to verify it's loaded:
claude mcp add suunto -e SUUNTO_CLIENT_ID=your-client-id -e SUUNTO_CLIENT_SECRET=your-client-secret -e SUUNTO_SUBSCRIPTION_KEY=your-subscription-key -- node /full/path/to/suunto-mcp/dist/index.js
Add -e SUUNTO_APP_NAME=your-app-name if you want to push guided workouts.
After building, you can query Suunto data directly without Claude:
suunto-mcp list-workouts --limit 10
suunto-mcp get-workout <workoutKey>
suunto-mcp get-sleep 2026-04-20
suunto-mcp list-recovery --from 2026-04-01 --to 2026-04-30
All output is JSON β pipe into jq for filtering.
npm run webhook
Starts an HTTP receiver on port 8422 that logs workout events as they arrive. Expose it to the internet (cloudflared, ngrok, your own server) and register the URL in apizone β webhooks.
Set SUUNTO_WEBHOOK_SECRET to the notification secret you configure in apizone's OAuth application settings. Without it, the receiver accepts any POST to its URL as genuine β since this endpoint is exposed to the internet, anyone who finds it could inject forged events. With it set, every request is verified against Suunto's X-HMAC-SHA256-Signature header and rejected with 401 if it doesn't match.
Most users can skip this whole section β asking Claude on demand is simpler.
To store your Suunto login tokens in your OS keychain (macOS Keychain, Windows Credential Manager) instead of a file:
SUUNTO_TOKEN_STORAGE=keychain npm install @napi-rs/keyring
SUUNTO_TOKEN_STORAGE=keychain npm run auth
Claude picks the right tool automatically β you don't need to know these. For the curious:
Workouts
| Tool | What it does |
|---|---|
list_workouts | Recent workouts, filtered by date |
get_workout | Summary numbers for one workout (no laps β use get_workout_laps) |
get_workout_laps | Lap-by-lap table for one workout: time, heart rate, calories and the guide step of each lap β the way to read back a guided gym session set by set |
get_workout_fit | Raw FIT file decoded to structured data (large β full: true is about 550 KB for a strength session) |
get_workout_samples | Currently unavailable β Suunto's servers reject this call (checked on one account, September 2026); use get_workout_fit |
export_workout_gpx | Currently unavailable β Suunto's servers reject this call (checked on one account, September 2026) |
24/7 health (requires individual product subscriptions on apizone)
| Tool | What it does |
|---|---|
get_daily_activity / list_daily_activity | Steps, calories, daily heart rate |
get_sleep / list_sleep | Sleep stages, duration, score |
get_recovery / list_recovery | Recovery balance and stress state through the day |
get_daily_activity_statistics | Aggregated daily stats over a date range |
Routes
| Tool | What it does |
|---|---|
list_routes | Saved routes on your account |
export_route | Export a route as GPX |
Uploads & guided workouts (write β send data back to your account)
| Tool | What it does |
|---|---|
upload_workout | Upload a FIT file as a new workout β Suunto's own docs say only FIT is currently supported for this endpoint, despite what you might read elsewhere |
get_upload_status | Check whether an upload finished processing |
push_workout_guide | Push a structured workout (exercises, weights, rest, notifications) as a SuuntoPlus Guide β requires SUUNTO_APP_NAME |
push_interval_guide | Push an auto-advancing interval/cardio guide (timed or distance-based segments, target HR ranges) β requires SUUNTO_APP_NAME |
push_strength_guide | Push a per-set strength session (prep stopwatch, set/rest lap tracking, configurable rest mode) β requires SUUNTO_APP_NAME |
list_guides | List all SuuntoPlus Guides on your account |
delete_guide | Permanently delete a guide by id |
Other
| Tool | What it does |
|---|---|
list_subscriptions | Currently unavailable β Suunto's servers reject this call (checked on one account, September 2026) |
generate_daily_digest | Writes the daily health digest to SUUNTO_HISTORY.md (see Daily health digest) β a write tool |
fit-file-parser β FIT binary decodingMIT β use it, fork it, improve it.
Source-derived launch command. Check the maintainerβs required arguments and credentials before running:
npx -y suunto-mcpMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-googlarz-suunto-mcp": {
"command": "npx",
"args": [
"-y",
"suunto-mcp"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the clientβs tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceSuunto MCP works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.