Skip to main content
Glama

suunto-mcp

An MCP server for authoring and managing structured workouts (SuuntoPlus™ Guides) on Suunto, designed so the transport can be swapped without touching the workout model.

Not affiliated with or endorsed by Suunto Oy.

Why it's built this way

There are three possible ways to get a structured workout onto a Suunto watch, and they differ enough that the transport has to be a replaceable part:

Path

Status

Notes

Cloud API (cloudapi.suunto.com/v2/guides)

Documented, needs a subscription key

The sanctioned path. Contract fully captured in docs/cloud-api.md.

Private mobile API (suuntoplus/guides/*)

Fully mapped and live-verified, reads and writes, unsanctioned

Confirmed by static analysis of the Suunto Android app, then exercised for real: create → duplicate-externalId 409 → update → delete, all against a live account. Full write-up in docs/private-guides-api.md. Genuinely undocumented; needs no new credential — reuses a suuntool session.

Local zip

Works today

Emit a validated guide.zip; no auth involved.

suuntool deliberately isn't one of these paths: it has no guide-creation capability at all. What it does have is a good, read-only MCP server of its own — suuntool mcp — for completed activity and wellness data, comments, reactions, and profile info. This server doesn't wrap or re-expose any of that: run the two side by side as separate MCP configs (claude mcp add suunto-mcp -- ... and claude mcp add suuntool -- suuntool mcp) rather than have this one duplicate a surface suuntool already covers better. The private backend's use of suuntool's session file (below) is credential reuse, not functionality overlap — it's the reason suuntool is a prerequisite for the private backend either way, so adding its own MCP server alongside this one costs nothing extra.

Its exit codes double as this server's own error taxonomy: codes 2–7 (USAGE/NETWORK/AUTH_EXPIRED/SERVER/NOT_FOUND/FORBIDDEN) are numerically identical on both, so a session that has expired in suuntool's own session.json surfaces through the same code as an expired Cloud API token.

Related MCP server: fitMCP

The interesting part

The guide format is a display format, not a training format. It has no step roles, no percentages, no nesting, and a 13-character title budget. So the domain model is what a coach would write, and src/compile lowers it:

  • roles (warmup/work/rest/…) → titles, notifications and lap marks

  • durations → a per-step trigger plus a matching countdown field

  • every duration/distance trigger grants lap-skip by default — a compound {type:"or", triggers:[base, {type:"manualLap"}]} plus createManualLap:true, confirmed live against a real Runna guide after a user reported this compiler's own workouts couldn't be skipped early. Opt a step out with allowSkip: false to lock it instead.

  • pace ranges → m/s, with the bounds inverted (4:15–4:25 /km is 3.77–3.92 m/s)

  • cadence → Hertz (180 spm is 3.0)

  • %HRmax / %FTP → absolutes, resolved from the athlete profile

  • nested repeats → flattened, keeping the outer block so the step budget survives

  • every string truncated and charset-sanitised for the watch display

Correctness is anchored on Suunto's own published sample guide, which is stored verbatim in test/fixtures/ and used two ways: to prove the format model accepts real Suunto output, and as the compiler's target.

Layout

src/domain/     workout model, guide wire format, validator, limits, activity IDs
src/compile/    the lowering compiler, unit conversions, externalId hashing
src/package/    zip packing (manifest.json + guide.json + icon.png)
src/backends/   the GuideBackend port and its implementations
src/mcp/        MCP server
scripts/        APK acquisition and static analysis for the RE track
docs/           captured API contracts and RE findings

Running it

Tool tiers follow suuntool's: read-only by default, --allow-write to create and update, --allow-destructive on top of that to delete. Gating happens at registration, so a tool you have not permitted is absent from the listing entirely rather than present and always refusing.

claude mcp add --scope user suunto-mcp -e SUUNTO_MCP_BACKEND=private -- node /path/to/suunto-mcp/dist/mcp/main.js --allow-write

Tier

Tools

read

preview_workout, list_workouts, describe_backend

--allow-write

create_workout, update_workout

--allow-destructive

delete_workout

preview_workout compiles and validates without uploading, and returns the warnings — start there.

For completed-activity and recovery data, add suuntool's own MCP server as a separate config rather than expecting this one to cover it:

claude mcp add --scope user suuntool -- suuntool mcp

Configuration

Variable

Purpose

SUUNTO_MCP_BACKEND

file (default), cloud, or private (reuses a suuntool session; see the warning above)

SUUNTO_MCP_OUTPUT_DIR

Where the file backend writes; defaults under ~/.local/share

SUUNTO_OWNER

Creator name. Must match the OAuth app name for the Cloud API

SUUNTO_SUBSCRIPTION_KEY

Ocp-Apim-Subscription-Key, required for cloud

SUUNTO_ACCESS_TOKEN

Static bearer token, for trying the API by hand

SUUNTO_CLIENT_ID / SUUNTO_CLIENT_SECRET

Enables refresh of the 24h token

SUUNTO_MAX_HR, SUUNTO_THRESHOLD_HR, SUUNTO_FTP, SUUNTO_REST_HR

Athlete profile, needed only for %HRmax / %FTP targets

Configuration is validated at startup and a bad config is a hard exit — an MCP server that starts and then fails every call is much harder to diagnose.

Development

pnpm install
pnpm test
pnpm typecheck

Reverse-engineering track

scripts/pull-apk.sh        # pull the APK off a connected Android device
scripts/analyze-apk.sh     # stage 1: fast dex string scan
scripts/analyze-apk.sh 2   # stage 2: full jadx decompile, only if needed

apk/ and capture/ are git-ignored and must stay that way — captures contain session keys and account identifiers.

Available Tools

3 tools
describe_backendDescribe the active backendA
Read-only

Report which backend is active and which operations it supports. Check this before planning a sequence of changes — backends differ in what they can do.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior3/5

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

Annotations include readOnlyHint=true, and the description does not contradict this. The description adds the context that backends differ in capability, but does not disclose additional behavioral traits such as output format or performance characteristics. With read-only status already declared, the added value is modest, so a 3 is appropriate.

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

Conciseness5/5

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

Two sentences, front-loaded with the core function, and the second sentence provides actionable usage advice. No redundancy or fluff.

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

Completeness5/5

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

For a zero-parameter, read-only introspection tool, the description fully covers what the tool does and when to use it. It explains the output at a high level (active backend and supported operations) and does not need an output schema.

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

Parameters4/5

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

The tool has zero parameters, so the description carries no parameter burden. Per the rubric, the baseline is 4, and the description meets that baseline by not omitting anything required.

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

Purpose5/5

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

The description uses the specific verb 'report' with the resource 'active backend' and 'which operations it supports', clearly distinguishing it from the workout-related sibling tools. The title reinforces the same.

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

Usage Guidelines5/5

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

Explicitly instructs to 'Check this before planning a sequence of changes', providing clear timing guidance. It also mentions that 'backends differ' which explains why checking is necessary. No alternatives are named, but none are needed given the tool's unique introspection role.

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

list_workoutsList guidesB
Read-only

List structured workouts stored on the configured backend.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
sinceNoEpoch ms; only guides modified at or after
offsetNo

TDQS

B3.3/5.0
Behavior3/5

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

The readOnlyHint annotation already signals a safe read operation, so the bar for additional transparency is lower. The description adds 'stored on the configured backend' but does not disclose pagination behavior, default limits, ordering, or whether the list is comprehensive.

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

Conciseness5/5

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

The description is a single, well-structured sentence that directly states the tool's purpose. No wasted words or redundancy.

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

Completeness2/5

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

With no output schema and a paginated list operation (limit/offset/since), the description is too sparse. It does not mention return format, whether results are ordered, or how pagination works, leaving the agent guessing about the actual invocation behavior.

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

Parameters2/5

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

Schema description coverage is only 33% (only 'since' is described). The tool description adds no explanation for limit, offset, or since. It fails to compensate for the low schema coverage, leaving agents uncertain about how parameters affect results.

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

Purpose5/5

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

The description clearly states a specific action ('List') and resource ('structured workouts') plus context ('configured backend'). It distinguishes from siblings: preview_workout implies a focused view of a single workout, and describe_backend is about backend metadata, whereas this tool returns a list.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus its alternatives. There is no mention of exclusions, prerequisites, or situations where preview_workout or describe_backend would be more appropriate.

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

preview_workoutPreview a workoutA
Read-only

Compile a structured workout into the SuuntoPlus guide format and return it WITHOUT uploading. Use this first: it surfaces unit conversions, truncated titles and validation errors, so mistakes are caught before anything reaches the watch.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateNoyyyy-MM-dd. Pins the guide to a date in the Suunto calendar
stepsYesThe session, in order
titleYesGuide name, max 60 chars
profileNoRequired only when the workout uses pctMax, pctLthr or pctFtp targets
activitiesNoSports this guide offers itself for. The first drives pace-vs-speed display
externalIdNoStable id for idempotent re-pushes. Derived from the session when omitted
descriptionYesShown in the Suunto app listing, max 256 chars
finalMessageNoClosing screen shown when the session ends, max 13 chars
shortDescriptionNoShown on the watch itself, max 23 chars. Defaults to title

TDQS

A4.2/5.0
Behavior4/5

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

Annotations declare readOnlyHint=true, and the description complements this by stating 'WITHOUT uploading' and detailing the types of errors it surfaces. This adds behavioral context beyond the annotation, such as the tool's side-effect-free nature and its focus on validation, without contradicting any annotations.

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

Conciseness5/5

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

Two sentences, front-loaded with the core function, then a direct usage recommendation. No wasted words; ideal for a complex tool where the schema carries parameter details.

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

Completeness4/5

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

Given the high schema complexity (nested steps, many optional fields) and no output schema, the description provides useful context about behavior (compilation, no upload, error surfacing). It doesn't describe the return value format, but the purpose and usage guidance are sufficient for an agent to invoke correctly, especially with the schema covering parameter semantics.

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

Parameters3/5

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

Schema description coverage is 100%, meeting the high-coverage threshold, so a baseline of 3 applies. The description text does not need to add parameter-level meaning; it only mentions outputs like 'unit conversions' and 'truncated titles', which are consequences of parameter processing rather than direct parameter semantics.

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

Purpose5/5

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

The description uses a specific verb-resource pair ('Compile a structured workout into the SuuntoPlus guide format') and explicitly states it returns without uploading, distinguishing it from sibling tools like list_workouts and describe_backend. The phrase 'Use this first' reinforces its unique role.

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

Usage Guidelines4/5

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

Clear guidance is provided: 'Use this first' followed by what it surfaces (unit conversions, truncated titles, validation errors) and why (catch mistakes before they reach the watch). This implies it's a pre-upload validation step, though it doesn't explicitly name alternative upload tools or when not to use it.

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.

  1. 3 tool updatesv0.0.1
    • First observeddescribe_backend
    • First observedlist_workouts
    • First observedpreview_workout

TDQS

A3.8/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: preview_workout compiles and validates without uploading, list_workouts retrieves stored workouts, and describe_backend reports backend capabilities. There is no ambiguity or overlap between them.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case: preview_workout, list_workouts, describe_backend. This is predictable and easy to navigate.

Tool Count4/5

With only 3 tools, the server is at the lower end of the ideal range, but each tool earns its place. The count feels slightly thin for a full workout management workflow, yet is appropriate for a focused validation and overview server.

Completeness2/5

The server lacks core operations such as create, update, delete, or upload for workouts. It only supports previewing and listing, with describe_backend to check capabilities, leaving significant gaps for any actual modification or synchronization workflow.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    B
    maintenance
    A multi-platform fitness MCP server that syncs data from Garmin, Strava, Google Fit, and Suunto into a local DuckDB database and provides analytics tools via MCP.
    1
    -
  • A
    license
    A
    quality
    B
    maintenance
    An MCP server that converts structured cycling workout specs into MyWhoosh .zwo and Garmin Connect workout files, with tools for validation, description, and rendering. It also includes skills for uploading workouts to both platforms.
    6
    MIT