Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

Suunto MCP

NPM · SUUNTO-MCP

Suunto watch data (workouts, sleep, recovery, 24/7 activity) for Claude and other AI assistants.

Available components

+55 this week 89 Trust /100

Last scanned (17 hours ago)

Scores higher than 91% of npm servers

Category Health and Science

Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →

Supply Chain Security98
  • No malware found by supply-chain analysis.Pass
  • No known CVEs affecting this package version or its production dependencies.Pass
  • No install/post-install scripts declared.Pass
  • 34 of 110 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency100
  • Source repository is publicly reachable at the declared URL. View diagnostics → Pass
  • Cryptographically verified build provenance (signed, bound to googlarz/suunto-mcp). View diagnostics → Pass
  • Clear OSI-approved license (MIT).Pass
  • Actively maintained (last published 0 days ago).Pass
  • Publishes a security disclosure policy (SECURITY.md).Pass
Schema Quality & AI Usability78
  • 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 7029 tokens (~226/item across 31 items; 26 tools + 5 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management57
  • Stability observed for 17 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage99
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 96% of tool parameters carry a description.Partial
Tool Safety100
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • All 1 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
  • An AI judge read all 27 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 16 Oct 26 +16
    • Known CVEs: unverified → pass ▲ security
    • Source repository: unverified → pass ▲ security
    • Dependency health: unverified → 0.87 ▲ functional
  • 15 Oct 26 −15
    • Provenance: pass → unverified ▼ security
    • Stability: 0.50 → unverified ▼ security
    • Known CVEs: pass → unverified ▼ security
    • Tool safety: pass → unverified ▼ security
    • Capabilities: pass → unverified ▼ functional
    • Dependency health: 0.87 → unverified ▼ functional
    • Tool coverage: 100 → unverified ▼ functional
    • Schema quality: 100 → unverified ▼ functional
    • Package version: 0.19.0 → 0.19.2 functional
    • Package version: 0.19.0 → 0.19.1 functional
  • 14 Oct 26 +39
    • Injection markers: unverified → pass ▲ security
    • Schema quality: 201 → 223 ▼ functional
    • Tool coverage: unverified → 100 ▲ functional
    • Stability: unverified → 0.50 ▲ functional
    • Schema quality: unverified → 100 ▲ functional
    • MCP protocol: unverified → pass ▲ functional
    • Package version: 0.15.2 → 0.19.0 functional
  • 12 Oct 26 +15
    • Malware scan: unverified → pass ▲ security
  • 9 Oct 26 0
    • Security disclosure: fail → pass ▲ functional
    • Package version: 0.18.0 → 0.19.0 functional
  • 6 Oct 26 −49
    • Malware scan: pass → unverified ▼ security
    • Tool safety: pass → unverified ▼ security
    • Stability: 0.17 → unverified ▼ security
    • Capabilities: pass → unverified ▼ functional
    • Tool coverage: 100 → unverified ▼ functional
    • Schema quality: 100 → unverified ▼ functional
    • Package version: 0.15.2 → 0.18.0 functional
  • 3 Oct 26 +16
    • Malware scan: unverified → pass ▲ security
  • 2 Oct 26 −14
    • Malware scan: pass → unverified ▼ security
    • Stability: unverified → 0.10 ▲ functional
    • Package version: 0.15.1 → 0.15.2 functional
Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 16 Oct 2026 · Analysed npm/suunto-mcp@0.19.2

Provenance Verified

A signed build attestation was found and verified, binding this exact artifact to the source repository it claims to come from.

Result Verified
Ecosystem npm
Reason Verified
Discovered via Registry attestation endpoint
Source repo googlarz/suunto-mcp
Certificate issuer https://token.actions.githubusercontent.com
Certificate SAN https://github.com/googlarz/suunto-mcp/.github/workflows/publish.yml@refs/tags/v0.19.2
Rekor log index 3264921579
Predicate type SLSA build provenance https://slsa.dev/provenance/v1
Subject digest sha512:a8da8acc1664b86d909a7995a6178037f3d2b75de31c59c6163d4bdf5a0956ff4af208943e5778e92a7abfe247323bfb8d4c306c1aa40ba754340dc0e

Background: How many MCP packages publish verified provenance →

Dependencies 110 packages
Packages resolved 110
Stale 34
Tree resolution Complete

Background: SBOMs and build attestations, explained →

MCP tools · 26 exposed · ~6,939 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
delete_guide ~93

Permanently deletes one SuuntoPlus Guide from the user's account by id. Use list_guides to find the id. This removes it from the Suunto app / apizone catalogue; it does not reach into the watch to un-pin a copy already synced there. Write operation (irreversible).

NameTypeReqDescription
guideIdstringyesGuide id, from list_guides or from a previous push_*_guide response.

No output schema declared.

No examples provided.

export_route ~70

Exports a saved Suunto route as a GPX 1.1 XML string. Suitable for import into navigation apps (Komoot, Strava, Garmin Connect, etc.). Use list_routes to discover valid route IDs. Read-only.

NameTypeReqDescription
routeIdstringyesRoute ID returned by list_routes.

No output schema declared.

No examples provided.

export_workout_gpx ~151

UNAVAILABLE — Suunto's API gateway currently rejects this endpoint (/v2/workout/exportGpx) with 401 OperationNotFound on the account it was tested with (September 2026), so the call fails with an 'endpoint unavailable' error; it is not an authentication problem. Would return the workout's GPS route as a GPX 1.1 XML string. Kept so the tool starts working again if Suunto restores the endpoint. Read-only.

NameTypeReqDescription
workoutKeystringyesOpaque server-assigned string returned by list_workouts. Not guessable or constructable — always discover via list_workouts first. Passing an invalid key throws SuuntoNotFoundError.

No output schema declared.

No examples provided.

generate_daily_digest ~358

Builds a color-coded daily health digest (steps, sleep, recovery balance, HRV, and a training-load model) for one date and appends it as markdown to a history file. Suunto's API has no fitness/fatigue endpoints, so this computes CTL (42-day fitness), ATL (7-day fatigue), and TSB (form) from each workout's tss.trainingStressScore using standard exponential time constants, persisting the running values in a local sidecar file (SUUNTO_DIGEST_AVERAGES_PATH env var, default ~/.suunto-mcp/averages.json) since there's nowhere else to store them. Running-average baselines (all days so far) per metric are also tracked there, with a separate baseline bucket for 'party nights' (>20,000 steps) so those don't skew the normal-day average. Requires Sleep and Recovery API subscriptions on apizone for the sleep/recovery sections to populate — falls back to 'no data' text for sections without a subscription rather than erroring. Write operation (updates the sidecar file and appends to the history file).

NameTypeReqDescription
datestringyesCalendar date YYYY-MM-DD to summarize. Use yesterday or earlier — today's data is usually partial until the watch has synced.
seedAtlnumber–Same as seedCtl but for Fatigue (ATL). Only used on the very first digest ever run.
seedCtlnumber–Only used on the very first digest ever run (no prior sidecar file). Anchors the starting Fitness (CTL) value to the number shown on the user's watch instead of cold-starting at 0. Ask the user for t…

No output schema declared.

No examples provided.

get_daily_activity ~222

Returns the 24/7 activity samples for one local calendar day (00:00–23:59 in the local time the watch stamped on each sample) from the /247samples API, as a plain array of { timestamp (ISO 8601 with UTC offset), entryData: { HR (bpm), StepCount, EnergyConsumption (joules, as in get_daily_activity_statistics) } } — 144 rows for a full day, one per 10 minutes (138 or 150 on the days the clocks change). A day without synced data returns []. Use list_daily_activity for a date range. Requires 24/7 Activity API subscription on apizone. Read-only.

NameTypeReqDescription
datestringyesCalendar date YYYY-MM-DD (a local day, in the local time the watch stamped on each sample). Data arrives when the watch syncs, so today's is usually partial — the API answers 200 with an empty or par…

No output schema declared.

No examples provided.

get_daily_activity_statistics ~341

Returns aggregated daily step count and energy consumption (joules) from the /247 API for the given datetime range. Response is an array of AggregatedActivityData objects, each with a Name ('stepcount' or 'energyconsumption'), Aggregation ('sum'), and Sources array containing per-device Samples with TimeISO8601 and Value. The window must be less than 28 days (exactly 28 is rejected). Samples with null Value indicate no data synced for that day. Each daily Sample is stamped local noon (TimeISO8601 like 2026-09-27T12:00:00+02:00); a one-day window (startdate = enddate = D) was observed returning the samples for D and the day after, so select samples by the date in TimeISO8601 rather than summing the response. Prefer this tool over list_daily_activity when you need totals rather than intraday time-series. Read-only.

NameTypeReqDescription
enddatestringyesEnd datetime in ISO-8601 format, same forms as startdate (e.g. 2026-04-27T23:59:59). Must be less than 28 days after startdate.
startdatestringyesStart datetime in ISO-8601 format, with or without a UTC offset (e.g. 2026-04-01T00:00:00 or 2026-04-01T00:00:00+02:00). An offset written +0200, as `date +%z` prints it, is rewritten to +02:00 becau…

No output schema declared.

No examples provided.

get_daily_snapshot ~710

One call for "how was this day, and the night before it": the aggregation the other tools leave to the caller. Output: { date, sleepNightOf, sleep, recovery, activity, workouts, errors }. sleep describes the NIGHT THAT LED INTO the date (sleepNightOf = the previous date, i.e. sleeps that began between noon on the previous day and noon on the date): { main (the longest non-nap sleep: sleepId, bedtimeStart, bedtimeEnd, durationS, deepS, lightS, remS, score, avgHrv, hrAvg, hrMin, spo2Max, latencyS, wasoS, wakeBeforeOffBedS — all durations in seconds: time to fall asleep, awake after falling asleep, awake in bed before getting up), otherNights (further non-nap sleeps, when the watch split a night), nightSleepS (total of main + otherNights, null when there is none), naps }. Suunto marks any sleep shorter than about 3 hours as a nap, so a short night appears under naps with main null. recovery covers the local calendar day: { samples, low: { balance, at }, high, first, last, morning: { balance, at } (the sample nearest the main sleep's bedtimeEnd — the waking value), atBedtime: { balance, at } (nearest its bedtimeStart, which falls on the previous local day), both null when there is no main sleep or no sample within an hour, stressStateSamples (samples per StressState) } or null without data. low is the day's lowest balance — not necessarily overnight (after an evening workout it can fall in the evening). activity: { steps, energyKcal } for the local day — energyKcal is the daily-statistics energy converted from joules; real days come out around 700-1,500 kcal, well below a resting rate, so it looks like ACTIVE energy rather than a total (not verified against the watch). A value is null, never 0, when Suunto has no sample for the date. workouts: the day's workouts (by their own local date) with { workoutKey, activityId, startLocal, totalTimeS, kcal, hrAvg, hrMax, tss (HR method), guide, hasLaps } — pass a workoutKey with hasLaps to get_workout_laps. Each section is fetch…

NameTypeReqDescription
datestringyesThe local calendar day YYYY-MM-DD (the first day when `to` is given). Use yesterday or earlier for a complete day; today's data is partial until the watch has synced, and the night that led into toda…
tostring–Optional last day of a range (inclusive, at most 14 days from `date`). The result is then { from, to, days: [one entry per day, in the shape above without errors], errors } — one request per section…

No output schema declared.

No examples provided.

get_recovery ~237

Returns recovery-balance samples from the /247samples API for one local calendar day (00:00–23:59 in the local time the watch stamped on each sample), as a plain array of { timestamp (ISO 8601 with UTC offset), entryData: { Balance (0.0–1.0 recovery balance), StressState (0=Invalid, 1=Relaxing, 2=Active, 3=Passive, 4=Stressful) } } — 48 half-hourly rows for a full day (46 or 50 on the days the clocks change). A day without recovery data returns []. Use list_recovery for a date range. Requires Recovery API subscription on apizone; returns 404 without it. Read-only.

NameTypeReqDescription
datestringyesCalendar date YYYY-MM-DD (a local day, in the local time the watch stamped on each sample). Data arrives when the watch syncs, so today's is usually partial — the API answers 200 with an empty or par…

No output schema declared.

No examples provided.

get_sleep ~431

Returns the sleeps of one night from the /247samples API. A date means the NIGHT of that date: every sleep that began between 12:00 (noon) on it and 12:00 the next day, in the local time the watch stamped on the sleep — so 23:00, 00:30 and 03:00 bedtimes all belong to the same date, and an afternoon nap is filed with the night after it. Last night is therefore filed under yesterday's date. Plain array with one row per sleep — Suunto re-sends a sleep every time it revises it, and only the longest revision is kept — of { timestamp (= BedtimeStart, ISO 8601 with UTC offset), entryData: { SleepId, IsNap, BedtimeStart, BedtimeEnd, Duration (s), DeepSleepDuration, LightSleepDuration, REMSleepDuration (s), SleepQualityScore, AvgHRV (ms), HRAvg, HRMin (bpm), … } }. IsNap is true for any sleep shorter than about 3 hours, at any time of day, and can flip while a sleep is still being recorded — so it also marks a short fragment of a split night; do not drop rows by IsNap alone. A night can hold several rows (a split night, or a nap beside it): rows are not merged, so decide from BedtimeStart and Duration which belong together. Returns [] when no sleep began in that window, e.g. today's date before tonight. Use list_sleep for a range. Requires Sleep API subscription on apizone; returns 404 without it. Read-only.

NameTypeReqDescription
datestringyesDate YYYY-MM-DD of the night, NOT the wake-up date: sleeps that began between noon on this date and noon the next day (in the local time the watch stamped on each sample), so a bedtime shortly after…

No output schema declared.

No examples provided.

get_upload_status ~78

Polls the processing status of a workout upload initiated by upload_workout. Returns status (e.g. 'Queued', 'Processing', 'Processed', 'Error') and the workoutKey once processing completes. Use the returned workoutKey with get_workout for full detail.

NameTypeReqDescription
uploadIdstringyesUpload ID returned by upload_workout.

No output schema declared.

No examples provided.

get_workout ~185

Returns the base summary for one workout (about 1.6 KB): the same scalar fields as a list_workouts item (times, distance, energy, hrdata, tss/tssList, recoveryTime) plus extensionTypes, the list of data streams Suunto holds for it. It does NOT include laps, HR zones or other extension data — use get_workout_laps for laps and zone times, get_workout_fit for record-level data. Throws SuuntoNotFoundError if the workoutKey is malformed (not 24 hex characters) or does not exist. Use list_workouts to discover valid workoutKey values. Read-only.

NameTypeReqDescription
workoutKeystringyesOpaque server-assigned string returned by list_workouts. Not guessable or constructable — always discover via list_workouts first. Passing an invalid key throws SuuntoNotFoundError.

No output schema declared.

No examples provided.

get_workout_fit ~226

Downloads the workout's binary FIT file from Suunto and returns it parsed to JSON. Default (full=false): compact summary { sport, total_distance_km, avg_heart_rate, training_effect, laps (a COUNT only, not the laps), records_sample: { first, middle, last (one record each), count } }. Set full=true to receive every parsed FIT record and lap — pretty-printed, about 550 KB for a 35-lap strength session, so the result usually spills to a file. For per-lap data use get_workout_laps instead (about 2.5 KB); use full=true only when record-level data is required. An unknown workoutKey fails with a 403 Forbidden error here (not-found on the other workout tools). Read-only.

NameTypeReqDescription
fullboolean–false (default): return compact summary. true: return all parsed FIT records.
workoutKeystringyesOpaque server-assigned string returned by list_workouts. Not guessable or constructable — always discover via list_workouts first.

No output schema declared.

No examples provided.

get_workout_laps ~719

Returns the manual laps of one workout as a compact table, plus its training-load fields — the way to read back a guided gym session set by set (push_strength_guide records one lap per set and per rest; push_workout_guide one lap per exercise and one per rest between exercises). A session from push_interval_guide auto-advances and is expected to record no manual laps (unverified), so it should return an empty table. About 2.5 KB for a 35-lap strength session, versus ~550 KB for get_workout_fit full=true. Output: { workoutKey, activityId, startTime (epoch ms), totalTimeS, guide: { id, name } | null (the guide that ran, as recorded by Suunto — not looked up in list_guides, because guides are often deleted afterwards), tss: [{ method (seen so far: 'HR', 'MET'), value }], pte, peakEpoc, recoveryTime (from the workout's summary extension; units not verified, and it can differ from the recoveryTime that list_workouts and get_workout carry), hrZoneTimeS: [zone1..zone5 seconds], feeling (the answer to the watch's 'How was it?' question, passed through as Suunto sends it; null when skipped), lapCount, checks: [{ code, detail }], laps: { cols, rows } }. checks lists reasons not to trust positional reading of the table (empty when clean): 'duplicate-rest' (the same rest label twice in a row — a set lap is missing or a rest was split), 'no-session-complete' (a guided table without its final lap — session ended early, buttons locked or watch restarted), 'unlabelled-laps' (some laps have no guide label), 'no-heart-rate' (no lap has heart rate, e.g. battery mode Tour). laps.cols = [i (1-based), startOffsetS (from workout start), durationS, hrAvg, hrMax, hrMin (bpm), kcal, kind, label]; each row is an array in that order. label is the text of the guide step that was active during the lap (lines joined with ' | '), or null when no guide ran. kind is 'rest' when the label contains 'Next:' at its start or after a '·' (a per-set rest lap reads 'Next: set k/S', or '<restSec>s target ·…

NameTypeReqDescription
workoutKeystringyesThe 24-character workoutKey returned by list_workouts. Anything else fails with a not-found error without calling Suunto.

No output schema declared.

No examples provided.

get_workout_samples ~157

UNAVAILABLE — Suunto's API gateway currently rejects this endpoint (/v2/workout/samples) with 401 OperationNotFound on the account it was tested with (September 2026), so the call fails with an 'endpoint unavailable' error; it is not an authentication problem. Use get_workout_fit with full=true for record-level data (heart rate etc.), or get_workout_laps for laps. Kept so the tool starts working again if Suunto restores the endpoint. Read-only.

NameTypeReqDescription
workoutKeystringyesOpaque server-assigned string returned by list_workouts. Not guessable or constructable — always discover via list_workouts first. Passing an invalid key throws SuuntoNotFoundError.

No output schema declared.

No examples provided.

list_daily_activity ~224

Returns 24/7 activity samples from the /247samples API for the local calendar days [from, to] inclusive (in the local time the watch stamped on each sample), ordered chronologically, as a plain array of { timestamp (ISO 8601 with UTC offset), entryData: { HR (bpm), StepCount, EnergyConsumption (joules, as in get_daily_activity_statistics) } }. Days without synced data are simply absent. Use get_daily_activity for a single day or get_daily_activity_statistics for aggregated daily step/energy totals. Requires 24/7 Activity API subscription on apizone. Read-only.

NameTypeReqDescription
fromstringyesStart date YYYY-MM-DD, inclusive. Must be ≤ to. Days without synced data are silently omitted, not 404.
tostringyesEnd date YYYY-MM-DD, inclusive. Future dates are accepted but produce no entries. Prefer about 3–7 days: a day is ~15 KB, so 30 days is ~450 KB (use get_daily_activity_statistics for longer totals).

No output schema declared.

No examples provided.

list_guides ~91

Returns all SuuntoPlus Guides (from push_workout_guide/push_interval_guide/push_strength_guide) on the user's account, newest first. Each item includes id, name, description, owner, localDate, and usage. Use the id with delete_guide, or with push_*_guide's guideId param to update an existing guide instead of creating a new one. Read-only.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_recovery ~216

Returns recovery-balance samples from the /247samples API for the local calendar days [from, to] inclusive (in the local time the watch stamped on each sample), ordered chronologically, as a plain array of { timestamp (ISO 8601 with UTC offset), entryData: { Balance (0.0–1.0 recovery balance), StressState (0=Invalid, 1=Relaxing, 2=Active, 3=Passive, 4=Stressful) } }. Days without recovery data are simply absent. Use get_recovery for a single day. Requires Recovery API subscription on apizone; returns 404 without it. Read-only.

NameTypeReqDescription
fromstringyesStart date YYYY-MM-DD, inclusive. Must be ≤ to. Days without recovery data are silently omitted, not 404.
tostringyesEnd date YYYY-MM-DD, inclusive. Future dates are accepted but produce no entries. Prefer about 14 days or less: a day is ~4 KB of output.

No output schema declared.

No examples provided.

list_routes ~54

Returns all routes saved in the user's Suunto account. Each route: id, description, visibility, distance (m), start/end coordinates, waypoint count. Use export_route to get the GPX track for navigation. Read-only.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_sleep ~341

Returns the sleeps of the nights [from, to] inclusive from the /247samples API, ordered chronologically by bedtime. A date means the NIGHT of that date: every sleep that began between 12:00 (noon) on it and 12:00 the next day, in the local time the watch stamped on the sleep — so 23:00, 00:30 and 03:00 bedtimes all belong to the same date, and an afternoon nap is filed with the night after it. Last night is therefore filed under yesterday's date. Same rows as get_sleep, one per sleep (revisions collapsed): { timestamp (= BedtimeStart, ISO 8601 with UTC offset), entryData: { SleepId, IsNap, BedtimeStart, BedtimeEnd, Duration (s), DeepSleepDuration, LightSleepDuration, REMSleepDuration (s), SleepQualityScore, AvgHRV (ms), HRAvg, HRMin (bpm), … } }. Nights without recorded sleep are simply absent. Use get_sleep for a single night. Requires Sleep API subscription on apizone; returns 404 without it. Read-only.

NameTypeReqDescription
fromstringyesFirst bedtime date YYYY-MM-DD, inclusive (the date the person went to bed, not woke up — see get_sleep). Must be ≤ to. Nights without recorded sleep are silently omitted, not 404.
tostringyesLast bedtime date YYYY-MM-DD, inclusive (the date the person went to bed, not woke up — see get_sleep). Future dates are accepted but produce no entries. Prefer ranges ≤ 30 days for responsiveness.

No output schema declared.

No examples provided.

list_subscriptions ~103

UNAVAILABLE — Suunto's API gateway currently rejects this endpoint (/v2/subscriptions) with 401 OperationNotFound on the account it was tested with (September 2026), so the call fails with an 'endpoint unavailable' error rather than returning a list. Would return the active webhook subscriptions as an array of { id, eventType, callbackUrl, createdAt }. Kept so the tool starts working again if Suunto restores the endpoint. Read-only.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_workouts ~338

Returns the user's recent Suunto workouts ordered newest-first (Workout API v3). Each item: workoutKey (string id), activityId (numeric activity code — there is no separate plain-language 'sport' field; use get_workout_fit for the parsed FIT file's session.sport if a sport name is needed), startTime (epoch ms), totalTime (s), totalDistance (m), totalAscent (m), totalDescent (m), energyConsumption (kilocalories, not 'totalCalories'), hrdata: { avg, max } (workout heart rate — hrdata.max is the account's overall max HR, use hrdata.workoutMaxHR for this specific workout's peak). Auto-paginates with offset-based pagination until limit is reached or no more workouts exist. Each item also embeds SummaryExtension (including apps[]: the SuuntoPlus guide that ran, if any) and IntensityExtension (HR-zone times). Use get_workout_laps for the lap table of a single workout. Read-only.

NameTypeReqDescription
limitinteger–Maximum number of workouts to return (1–1000). Defaults to 25. Pagination is automatic across API pages; set to 1 for the single most-recent workout.
sincestring–ISO 8601 lower bound on startTime (inclusive). Filters on workout start time; omit for all time. Pagination is automatic so since does not affect page size.
untilstring–ISO 8601 upper bound on startTime (inclusive). Omit to include workouts up to the present. Combine with since to target a specific window.

No output schema declared.

No examples provided.

push_interval_guide ~270

Pushes an interval/cardio guide (warmup, timed or distance-based work intervals, recoveries, optional repeats) to the user's Suunto account via the SuuntoPlus Guide Cloud API. Unlike push_workout_guide (manual lap-per-exercise), interval segments auto-advance by elapsed time or distance — hands-off during a run or ride. Each segment can show a target heart-rate range alongside live HR. Requires SUUNTO_APP_NAME env var to exactly match the app name registered on apizone.suunto.com. Same delivery caveat as push_workout_guide: appears after the phone's next normal Suunto app sync, no live push. Write operation.

NameTypeReqDescription
blocksarrayyesOrdered list of blocks. A block with times>1 repeats its segments as a unit (e.g. 4x[interval,recovery]) — put only the segments that repeat inside it; warmup/cooldown go in their own times=1 blocks…
datestringyesSession date YYYY-MM-DD.
guideIdstring–If provided, updates this existing guide instead of creating a new one.
titlestringyesShort session name shown in the Suunto app, e.g. '4x4 VO2max'.

No output schema declared.

No examples provided.

push_strength_guide ~542

Pushes a resistance-training guide to the user's Suunto account via the SuuntoPlus Guide Cloud API — the tool to use for gym sessions. Per exercise: a prep step (self-paced stopwatch showing the plate breakdown if given, otherwise the weight/sets detail, plus the exercise name and live HR; a lap press starts the exercise), then with lapGranularity 'perSet' (default) each set is its own step ended by a lap press, and each rest between sets is its own step showing 'Next: set k/S'. restMode 'countdown' (default) counts down restSec and auto-advances into the next set with a vibration; 'stopwatch' counts up and waits for a lap press. lapGranularity 'perExercise' gives one step per exercise after its prep, with no between-set rests and no per-set laps. Every prep, set and rest is its own lap and the guide ends with one extra 'Session complete' step, so a perSet session records 2 × (total sets) + 1 laps. Read them back after the workout with get_workout_laps — its labels are the step texts. Requires SUUNTO_APP_NAME to exactly match the app name registered on apizone.suunto.com. Without guideId a new guide is created on every call (see list_guides / delete_guide to tidy up); with guideId that guide is overwritten. There is no live push to the watch: it appears after the phone's next normal Suunto app sync. Write operation.

NameTypeReqDescription
datestringyesSession date YYYY-MM-DD.
exercisesarrayyes–
guideIdstring–If provided, updates this existing guide instead of creating a new one.
lapGranularitystring–'perSet' (default, recommended): one step per set plus one per rest, so laps bound every set/rest individually — needed to read per-set HR and duration from the synced workout. 'perExercise': one ste…
restModestring–Rest between sets. 'countdown' (default): counts down from restSec and auto-advances into the next set. 'stopwatch': counts up and waits for a lap press — the user paces it. Has no effect with lapGra…
titlestringyesShort session name shown in the Suunto app, e.g. 'Push A'.

No output schema declared.

No examples provided.

push_workout_guide ~230

Pushes a text-step workout guide to the user's Suunto account via the SuuntoPlus Guide Cloud API. Each exercise becomes one step, advanced by a lap-button press on the watch. Requires SUUNTO_APP_NAME env var to exactly match the app name registered on apizone.suunto.com. There is no live push to the watch itself — delivery depends on the phone's normal Suunto app sync. In testing it showed up on the watch after the next ordinary sync with no manual pinning needed; if it doesn't appear, check the Suunto app under SuuntoPlus Guides and pin it there. For gym sessions prefer push_strength_guide: it records one lap per set and per rest, which get_workout_laps can read back. Write operation.

NameTypeReqDescription
datestringyesSession date YYYY-MM-DD.
exercisesarrayyes–
guideIdstring–If provided, updates this existing guide instead of creating a new one.
titlestringyesShort session name shown in the Suunto app, e.g. 'Push A'.

No output schema declared.

No examples provided.

upload_route ~355

Imports a GPX file as a route in the user's Suunto account (it appears in the Suunto app's route library as PRIVATE and can then be synced to the watch for navigation). Provide the absolute path to a .gpx file. Every <rte> or <trk> element in the file becomes its own route; the route name comes from its <name> (or <desc>), and waypoints are created from <wpt> elements at the same coordinates as route points and from route points that have a name or type. The route's activities come from the `activities` argument, NOT from the GPX content (default [1] = running). Returns { count, routes: [{ id, name, activities, segments }], check: { verified, watchEnabled, distanceM, pointsInFile, pointsInRoute, note? } }. Imports are queued one at a time with a short pause and each route is read back from Suunto (point count against the file), so many calls at once are safe; expect roughly 3 s per route. verified:false with a note means the import went through but the read-back did not match — say so to the user instead of reporting success. A route cannot be deleted through this server — remove it in the Suunto app. Requires the Route API on the Suunto subscription (list_routes shows existing routes). Write operation.

NameTypeReqDescription
activitiesarray–Suunto activity IDs the route is suitable for (1 = running; the other IDs are in Suunto's Activities.pdf on apizone). Shown in the app's route details. Optional.
filePathstringyesAbsolute path to the .gpx file on disk.

No output schema declared.

No examples provided.

upload_workout ~197

Uploads a workout file to the user's Suunto account. Provide the absolute path to the file on disk. The file is pushed to Suunto and appears in the app after processing (usually a few seconds). Returns an uploadId you can poll with get_upload_status. Suunto's own upload API docs state only .fit (binary) is currently supported for this endpoint — a .gpx path is still accepted here (sent as application/gpx+xml) in case that changes, but treat it as unverified; use .fit for a workout that must reliably show up. Write operation.

NameTypeReqDescription
commentstring–Longer notes for the workout. Optional.
descriptionstring–Short workout title shown in the Suunto app. Optional.
filePathstringyesAbsolute path to the .fit or .gpx file on disk.
privacystring–Visibility. DEFAULT uses the account's default setting.

No output schema declared.

No examples provided.

Install

How do I install the Suunto MCP server?

Suunto MCP runs locally as an npm package, launched with npx -y suunto-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

npm · suunto-mcp

# add to Claude Code
claude mcp add googlarz-suunto-mcp -- npx -y suunto-mcp
Common questions

What is the Suunto MCP server?

Suunto MCP is listed in the public MCP registry as io.github.googlarz/suunto-mcp. Suunto watch data (workouts, sleep, recovery, 24/7 activity) for Claude and other AI assistants. This page covers its npm package (suunto-mcp).

Is the Suunto MCP server safe to use?

Suunto MCP scores 89 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 16 October 2026. It declares no install or post-install scripts. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the Suunto MCP server expose?

Suunto MCP exposes 26 tools: list_workouts, get_workout, get_workout_samples, get_workout_fit, get_daily_snapshot, and 21 more. Their descriptions and schemas cost roughly 6,939 tokens of context every time the server is loaded.

Is the Suunto MCP server still maintained?

Suunto MCP is still listed as active in the MCP registry. We last reached this channel on 16 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

What licence is the Suunto MCP server under?

Suunto MCP declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.