Skip to main content
Glama

What you can ask

Ask your assistant anything about your Garmin data, in your own words and in any language. The assistant chooses the tools and can combine their data. Some examples:

  • Activities: "List my last 5 activities, with pace and heart rate."

  • Activities: "How much time did I spend in each HR zone on my runs this month?"

  • Activities: "How did my sessions named Tempo 5k and Long run change over the last 2 months?"

  • Laps: "Show the laps of my last run."

  • Bike: "Compare the grit and flow of my last mountain-bike rides."

  • Bike: "How many metres per hour did I climb on my last 5 rides?"

  • Bike: "How much of my riding time was in Z1-2 and how much in Z4-5 over my last 5 rides?"

  • Strength: "Compare my sets of this week with the week before."

  • Strength: "Which muscles did I train most this week?"

  • Strength: "What was my heaviest squat set this month, and what 1RM does it suggest?"

  • Strength: "Which of my lifts have stalled over the last 6 weeks?"

  • Strength: "How long did I rest between sets in my last strength session?"

  • Strength: "How much weight did I lift in total in each strength session this month?"

  • Workouts: "Did I do the reps and rests my workout planned?"

  • Recovery: "How did I sleep this week, and how was my HRV?"

  • Recovery: "Should I train hard today?"

  • Recovery: "Show my steps, stress and Body Battery for the last 7 days."

  • Recovery: "Did my Body Battery recover overnight this week, and which days drained it most?"

  • Body: "How has my weight changed over the last 3 months?"

  • All together: "My run on Saturday felt hard. Compare it with my sleep and HRV of the nights before."

Related MCP server: Garmin Workouts MCP Server

Features

  • Official and read-only: uses the Garmin Connect Personal API, writes nothing back, and runs with npx.

  • All of your data: laps and strength sets from the original .FIT files, with the muscles of each set; HRV, sleep, heart rate, stress and Body Battery; garminGet for the other endpoints.

  • All stdio clients: Claude Desktop, Claude Code, Codex and the other MCP clients that use stdio. Tested with Claude Desktop and Claude Code.

  • A dashboard in less than a minute: your training load next to recovery, for you or for your coach, with your own widgets and languages. See Dashboard.

  • The dashboard in the chat: in Claude Desktop, ask "show my training dashboard" and the page opens in the reply, with new data. See Dashboard in the chat.

  • Coach prompts: a review of one run or one strength session against its planned workout, a readiness check before a race, and a check of today. See Coach prompts.

Quick start

You need Node.js 22 or later (node --version shows the version) and a Garmin Connect account with access to the Personal API.

You do not use a terminal? Follow the step-by-step setup in Claude Desktop.

1. Create a personal API key

  1. Open Garmin Connect web at https://connect.garmin.com/app/settings/personalApiToken.

  2. Select Create Key, accept the terms, select the expiry (1 year at most) and select Create.

  3. Garmin shows the key only one time. Save it with the setup command. Paste the key at the prompt: it stays hidden. setup tests the key with Garmin and saves it in a file that only you can read (default ~/.config/garmin-mcp/api-key, in your user folder on Windows):

npx -y @indaco/garmin-personal-mcp@latest setup

setup runs on macOS, Linux and Windows, and CI tests it on each one.

You can also give the key in GARMIN_PERSONAL_API_KEY, in the env block of the client configuration (example). Claude Desktop does not read your shell profile. The automatic dashboard refresh reads only the key file.

2. Connect your client

Claude Desktop: select Settings → Developer → Edit Config. Add a top-level mcpServers key next to the keys that the file has, not in preferences (example):

{
  "mcpServers": {
    "garmin-personal": {
      "command": "npx",
      "args": ["-y", "@indaco/garmin-personal-mcp@latest"]
    }
  }
}

Then quit Claude Desktop fully, including the tray icon, and start it again. Settings → Developer shows garmin-personal.

Claude Code: this command adds the server to all your projects:

claude mcp add garmin-personal --scope user -- npx -y @indaco/garmin-personal-mcp@latest
claude mcp list          # garmin-personal: ... ✔ Connected

Use --scope project to write a .mcp.json file that you can share in the current repository.

Codex: add this table to ~/.codex/config.toml. The first npx download can take longer than the default start time, so the table sets a longer one:

[mcp_servers.garmin-personal]
command = "npx"
args = ["-y", "@indaco/garmin-personal-mcp@latest"]
startup_timeout_sec = 60

Codex does not send your shell environment to the server. Use the key file, or add env = { GARMIN_PERSONAL_API_KEY = "..." } to the table. The automatic dashboard refresh needs the key file.

Other clients (Gemini CLI, VS Code, Cursor and others): in the MCP configuration of the client, set the command npx and the arguments -y @indaco/garmin-personal-mcp@latest. Some clients do not show MCP prompts. In these clients, ask for the dashboard in your own words. The tools are the same.

3. Ask your assistant

Start a new chat (Claude Desktop) or a new session (Claude Code). Ask "list my last 5 activities". The first time that a garmin-personal tool asks for permission, answer Allow always in Claude Desktop. In Claude Code, use /permissions and add mcp__garmin-personal.

Tools

Tool

What it gives

listActivities

each activity with pace, HR, load and effect, by date, type or name

getActivity

the details of one activity

getActivityLaps

the laps of an activity, from its .FIT file; for a run also the half split, the HR drift and the fade of each workout step

getActivitySets

the strength sets of an activity, with the muscles, the top set and the e1RM, from its .FIT file

getActivityWorkouts

the planned workout of an activity: steps, targets and notes

downloadActivityFit

saves the .FIT file of an activity in the data folder

getHrvRange

HRV during the night

getDailyHeartRate

the heart rate of a day, with the resting HR

getSleep

the sleep of a night, or of up to 14 nights: hours, phases, score and need

getWeight

weight and body composition for a range of dates

getBodyBattery

how Body Battery charged and drained, for up to 14 days

getHeartRateZones

your HR zones

getFitnessAge

fitness age against actual age

getDailySummary

steps, stress and Body Battery, for a day or a range

getDashboardData

all the dashboard data in one call, with the server's totals and a local cache

writeDashboard

writes the dashboard page

editDashboard

changes the layout, the custom widgets and the languages of the page

showDashboard

shows the dashboard inside the chat, in Claude Desktop

scheduleDashboardRefresh

updates a dashboard page automatically, at the times you say in your own words

garminGet

all other GET endpoints of the Personal API

Tools gives the endpoints, the details of each tool and the data that the Personal API does not have.

Dashboard

The server makes a training dashboard with these prompts. In Claude Desktop, the prompts are in the + menu of the message box, under garmin-personal. In Claude Code, they are slash commands: use the full name, /mcp__garmin-personal__<prompt>. The short form /garmin-personal:<prompt> can reach the assistant as the command name only, without the prompt.

Prompt

What it does

Claude Code example

training-dashboard

makes the page

/mcp__garmin-personal__training-dashboard 8

training-dashboard-update

adds the new data, your layout stays

/mcp__garmin-personal__training-dashboard-update

dashboard-setup

makes a page for you or for your coach, with only the sports and the data that you select

/mcp__garmin-personal__dashboard-setup

dashboard-widget

makes a new widget from your idea

/mcp__garmin-personal__dashboard-widget my longest ride

dashboard-language

adds a language to the page

/mcp__garmin-personal__dashboard-language Dutch

The prompts remove all spaces around an argument, also the no-break space from a phone keyboard.

training-dashboard

The server writes the dashboard page from its template, and the assistant writes the coach notes. The page is one HTML file, garmin-dashboard.html in the data folder. It works offline.

Argument

Values

Default

weeks

1 to 52 (a larger value gives 52)

12

layout

preset, blank or freeform

preset

  • preset gives the built-in widgets on each board.

  • blank gives empty boards: you add the widgets that you want.

  • freeform lets the assistant design the whole page. This takes much longer, and each page looks different.

In Claude Code, the arguments are in order and separated by spaces: first weeks, then layout. You can also give only the layout: /mcp__garmin-personal__training-dashboard freeform.

The assistant gives you the path of the page and the command to open it. The page has a board for all your training, a Recovery board and a board for each sport. A missing value shows as "n/a".

When your runs repeat a name, for example the "Tempo Run" of a training plan, the assistant asks whether to compare those workouts across weeks. The default is no. A yes adds the Workout trend widget. The server downloads the laps of the last 8 runs of each workout once and keeps them, so the comparison grows with each update. See Page settings.

The dashboard guide tells about the title and the headline, the boards, the themes and languages, the units and the activity-name filter, and how to change the layout. The widget catalogue lists every widget.

training-dashboard-update

This prompt replaces the data and the coach notes of the page. Your layout, your custom widgets and your languages stay. Only a new preset widget of a release can join a board that you edited, one time. Reload the page to see the new data.

Argument

Values

Default

weeks

the weeks to cover

the weeks of the page

path

the dashboard file, for example garmin-dashboard-coach.html (.html)

garmin-dashboard.html

In Claude Code: /mcp__garmin-personal__training-dashboard-update coach.html updates coach.html. A value that ends in .html is the file, also in the first place.

After a release, this prompt also writes the new page code. Restart the client first. See Update the page code after a release.

To update the page automatically, tell your assistant when, in your own words, for example "update my dashboard every Monday at 7". See Update the dashboard on a schedule.

dashboard-setup

The assistant asks you some questions, then writes a page with your answers. First, it asks who the page is for:

  • Personal: a page for you, with all your data.

  • Shared: a page for your coach or personal trainer. You select each type of data to include, for example HR zones yes, fitness age and sleep no.

Then the assistant asks for the file (any name or path), the title, the headline, the sports, the languages and the themes, and whether to compare the workouts that your runs repeat. The server writes only the data that you select into the file. Other data is not in the file, so you can send the file safely. A personal page and a shared page can be two files side by side. Each page keeps its settings on each update. The argument weeks is optional (default 12).

Page settings tells more.

dashboard-widget

This prompt makes a new widget from your idea, for example "my longest ride of each month". The assistant writes a small widget, and editDashboard stores it in the page and in your widget library (widgets.json in the data folder). The widget stays after each update, and each new page gets it too. The argument idea is required. The argument path is optional: it is the file of the page, for example coach.html. In Claude Code: /mcp__garmin-personal__dashboard-widget my longest ride each month coach.html. Reload the page to see the widget. Custom widgets tells more.

dashboard-language

This prompt adds a language to the dashboard. The assistant translates the texts of the page, and editDashboard stores them in the page. The argument language is optional: the default is the language of the conversation. The argument path is optional: it is the file of the page, for example coach.html. In Claude Code: /mcp__garmin-personal__dashboard-language Dutch coach.html. A text without a translation shows in English. To remove an added language, ask your assistant to remove it: editDashboard with removeLanguages. Languages tells more.

Presets or freeform

In many setup guides for Claude and Garmin, Claude reads the data and writes the whole dashboard page. With a preset, the server writes the page from a tested template, and Claude writes only the coach notes. My measurements for a first build, with Claude Code and Opus (other clients and models give other times and costs):

First build

Time

Cost

Preset

34 s

$0.16

Claude writes the page

24 to 35 min

$6.6 to $9.2

For a design of your own, use layout = freeform: Claude writes the page, as in those guides.

Presets or freeform gives the measurements and the limits of the presets.

Dashboard in the chat

In Claude Desktop, the dashboard can open inside the chat, with its boards, charts and themes. You do not open a file or a browser. There is no prompt to run: ask in your own words, for example:

  • "Show my training dashboard in the chat."

  • "Show my dashboard in the chat for the last 26 weeks."

  • "Show garmin-dashboard-coach.html in the chat."

The assistant calls showDashboard. The tool reads new data from Garmin and shows your saved page, with its layout, custom widgets, languages and settings. It writes no file, and the page has no coach notes.

Client

What you get

Claude Desktop

the page in the chat (tested)

Claude Code, the Codex CLI and other terminal clients

a short text reply. Run training-dashboard to write the page as a file

Codex in the ChatGPT desktop app

not tested yet

The ChatGPT chat, Claude on the web

not available: they connect only to servers on the internet

The page in the chat is an MCP App. Other clients that show MCP Apps can also work, but they are not tested. Show the dashboard in the chat gives the limits.

Coach prompts

These prompts answer in the chat. They do not change a dashboard.

Prompt

What it does

Claude Code example

run-review

reviews one run as a coach

/mcp__garmin-personal__run-review

race-readiness

tells if you are ready for a race, with a plan for its pace

/mcp__garmin-personal__race-readiness 2026-11-15 half 1:45:00

strength-review

reviews one strength session as a coach

/mcp__garmin-personal__strength-review

train-today

tells if you should train hard today, with fitness and form

/mcp__garmin-personal__train-today

A missing value shows as "n/a": the assistant does not estimate it.

run-review

The assistant compares the steps of the planned workout with the laps of the run: the target, what the lap did, and hit or miss. For intervals, it gives the fade from the first rep to the last. For a steady run, it gives the HR drift: the drop in distance per heartbeat from the first half to the second half. It ends with the sleep and HRV of the night after the run, and a short coach note.

Argument

Values

Default

activity

an activity id, or words of the activity name (Long Run)

the last run

race-readiness

The assistant reads the server's summary of 12 weeks (a writeDashboard preview, which writes nothing). It has the weekly run distance and load, the long runs with their pace split and HR drift, and the race predictions, as the dashboard computes them. The assistant gives the days to the race and these numbers, and tells whether your load drops in the last 2 weeks (the taper). The race prediction uses your best efforts of 5 km or more (Riegel, an estimate: the fastest prediction counts). The assistant compares it with your goal and checks the HRV and sleep of the last 7 nights. It ends with a target pace for each quarter of the race.

Argument

Values

Default

date

the race date, yyyy-MM-dd

none: the assistant asks

distance

5k, 10k, half, marathon, or a distance

none: the assistant asks

goal

your goal time, for example 1:45:00

no goal: prediction only

In Claude Code, give the values in any order: a value in the form yyyy-MM-dd is the date, a value in the form 1:45:00 is the goal, and the other words are the distance. For example /mcp__garmin-personal__race-readiness half marathon 2026-11-15.

strength-review

The assistant compares the planned workout with the sets you did: the planned sets and reps of each exercise, what you did, and hit or miss. Garmin plans no weights, so the plan shows none. For each exercise it gives the top set and its estimated 1RM against the previous session of the same name, and the rep drop from the first set to the last at the same weight. It compares your rest with the planned rest, and ends with the sleep and HRV of the night after the session, and a short coach note.

Argument

Values

Default

activity

an activity id, or words of the activity name (Upper Body)

the last strength session

train-today

The assistant reads the server's summary of the dashboard data (a writeDashboard preview, which writes nothing). It uses the weeks of your dashboard page, so the numbers are the same as on the page. It gives the verdict of the dashboard's Readiness widget: go easy, normal or ready to push. This verdict is the dashboard's own rule, not Garmin's Training Readiness. A table shows each input and the rule it meets: the HRV status, the sleep score, the resting HR against the average of the 7 days before, and the load ratio of 7 to 28 days. When a value is from an older night, the assistant gives its date. Then it gives your fitness, fatigue and form, and a short coach note.

Without HRV and sleep data, for example when the page leaves out the recovery data, the summary has no readiness: the verdict and its inputs show as "n/a". The prompt has no arguments.

Configuration

All the settings are environment variables, and all of them are optional.

Variable

Default

Meaning

GARMIN_PERSONAL_API_KEY

not set

the personal API key. It has priority over the key file. The automatic refresh needs the key file.

GARMIN_API_KEY_FILE

~/.config/garmin-mcp/api-key

the file with the API key

GARMIN_DATA_DIR

~/workspace/garmin-data

the data folder

GARMIN_BASE_URL

https://personal.connectapi.garmin.com

the Personal API host

To set a variable in Claude Desktop, add an env object next to args:

"env": { "GARMIN_DATA_DIR": "/absolute/path/to/garmin-data" }

In Claude Code, add --env GARMIN_DATA_DIR=/path/to/garmin-data to claude mcp add.

The data folder lists the files that the server keeps and its log.

Commands

The server is also a command for a terminal. A command does one task and stops: it does not start the MCP server.

Command

What it does

info

shows the version, the settings and where the files are. It never shows the key.

doctor

tests the API key, the folders and the schedule. It never shows the key.

setup [--force]

tests the API key and saves it in a file that only you can read

refresh [page.html]

updates a dashboard page one time

schedule [daily|weekdays|weekly ...]

shows, sets or stops the automatic update of a page

--version, -v

shows the version

--help, -h

lists the commands. After a command, it shows the help of that command.

npx -y @indaco/garmin-personal-mcp@latest info

A command reads the environment variables of your terminal, not of your MCP client configuration. Commands has each command, its output and its exit codes.

Security

The server is read-only. It sends the API key only to the Garmin token endpoint, and it never logs or returns the key or the access token. It refuses a key that has spaces or line breaks in it, and it removes the key and the token from network error messages. If you saw your API key in a chat, revoke the key on the API key page and create a new one. No tool result has your Garmin user id, name or profile image, or the ids of your devices and daily records, also with raw and garminGet. Your .FIT files can have your GPS track, so keep the data folder private.

SECURITY.md tells how the server protects your data and how to report a vulnerability. Do not open a public issue for a vulnerability.

The Personal API is for personal use that is not commercial, under the terms of Garmin. Garmin does not endorse this project, and the project has no affiliation with Garmin.

Problems and solutions

Problem

Solution

The server does not start

Make sure that Node.js is version 22 or later: node --version.

Claude Desktop does not find npx

GUI apps do not read your shell profile. Use the absolute path of npx (which npx) as the command.

Changes have no effect

The client keeps the old server process. Restart the client: a new Claude Code session, or quit and start Claude Desktop again.

Which version runs

npx -y @indaco/garmin-personal-mcp@latest --version (or -v) prints the version and stops. --help (or -h) lists the commands.

Where the files are

npx -y @indaco/garmin-personal-mcp@latest info shows the key file, the data folder and the logs. See Commands.

Problems and solutions has more problems, the log files, and commands that test the key and the server.

Contributing

Read CONTRIBUTING.md. It tells how to run the server from source, and it has the commands, the test rules and the code map.

To build the website with its demo dashboard (a year of sample data), run pnpm build:all. The site is in dist-site/, and the demo in dist-site/demo/index.html.

Credits

The idea comes from apratico/garmin-mcp by Alessandro Praticò: a Java MCP server for the Garmin Personal API, where Claude writes the dashboard. I tested it in a fork, indaco/garmin-mcp, and then made this server as a different solution. It runs with npx, without Java, and it writes the dashboard page from a tested template.

This server uses the same key file as indaco/garmin-mcp and can share its data folder.

How this was built

AI agents in Claude Code wrote the code, tests and docs of this project. I chose the design, reviewed each change and tested the server with my own Garmin data. The rules that the agents follow are in AGENTS.md.

License

This project uses the MIT License. dist/index.js and the dashboard page include other libraries with their own licenses: THIRD-PARTY-NOTICES.md lists them.

Available Tools

20 tools
downloadActivityFitA

Download the ORIGINAL .FIT file of an activity and save it on the user's computer. Returns the absolute path of the saved .fit file (second-by-second HR, cadence, speed, laps).

Inputs: activityId (required).

editDashboardA

Changes the layout, the custom widgets or the languages of the dashboard page (a page from the template; call writeDashboard first). Without arguments it only reads: the reply has the layout, the custom widgets, the missing texts of each language, the catalogue of built-in widgets and widgetApi, the guide to writing a custom widget. layout replaces the whole layout (the text of the page's 'Copy layout'); place adds widgets at the end of a board; widgets adds or replaces custom widgets by id and saves them in the widget library (/widgets.json), which every page from the template gets; removeWidgets removes them from this page and its boards, forgetWidgets also from the library. widgetTexts adds texts to custom widgets by id, language and key, e.g. {"longest-ride": {"de": {"title": "Längste Fahrt"}}}. languages adds page texts by key, e.g. {"de": {"title": "Training + Erholung"}}: keys and {placeholders} as in englishTexts: true; a text with "|" has a singular and a plural form. Missing texts show in English. removeLanguages removes languages that languages added.

Inputs: path, place, layout, widgets, +6 more.

garminGetA

Generic read-only GET on the Garmin Connect Personal API, for endpoints not covered by the other tools or when a query parameter name has to be adjusted. 'path' is relative and starts with '/', e.g. /fitnessage-service/fitnessage/v2/2026-10-25 . 'query' is an optional URL query string without '?', e.g. date=2026-10-25&foo=bar .

Inputs: path (required), query.

getActivityA

Get the full detail of one activity (summary, metadata, splits/laps) as JSON.

Inputs: activityId (required).

getActivityLapsA

Laps of an activity as recorded by the watch (manual laps, auto-lap every km, or workout steps), read from the original .FIT file. One row per lap: distance (km), timer time, pace (min/km, foot sports) or speed (km/h), average/max HR, cadence (spm for running), ascent/descent, average power, running form (gctMs, vertRatioPct, vertOscCm, strideCm), intensity (active, interval, rest, recovery, warmup, cooldown; the auto laps of a free run can be interval), lap trigger, and the step of the planned workout (step: the reps of one drill share it). Use it for intervals and per-km splits; getActivity does not have them. For a run: split (pace of the first and second half, kind, hrDriftPct) and, for a structured workout, work (reps, pace, avgHR, and the fade of each step with more than one rep, pct). null is n/a.

Inputs: activityId (required).

getActivitySetsA

Strength training sets of an activity, read from the original .FIT file. One entry per exercise, in the order first done, with its movement category, its primary and secondary muscles (from Garmin's exercise catalogue) and its active sets: reps, weight (kg, absent when none was recorded), set time in seconds and the rest after the set (restSec). Each exercise with weight also has top (the heaviest set of 1 to 12 reps, then the most reps; without one, the heaviest set) and e1rmKg (the best estimated 1RM, Epley, of its sets of 1 to 12 reps; null when it has none). Exercise names are stable across sessions, so they can be used for per-exercise trends. Edits made later in Garmin Connect (renamed exercises, corrected reps or weights) are not in the .FIT file.

Inputs: activityId (required).

getActivityWorkoutsA

The planned workout that an activity followed, as created in Garmin Connect: its steps in order, each with its intensity (warmup/active/rest/recovery/cooldown), its duration (time in seconds, reps, or open), its target (cadence, heart rate, pace, or open, with low and high values), the exercise for strength steps, and the coach's notes. A step with durationType REPEAT_UNTIL_STEPS_CMPLT repeats the steps from stepIndex durationValue up to it, targetValue times in all. Compare it with getActivitySets or getActivityLaps for plan against done. An empty list means the activity followed no planned workout. Null fields are left out.

Inputs: activityId (required).

getBodyBatteryA

Body Battery for up to 14 days, yyyy-MM-dd: for each day how much it charged and drained, its readings through the day, and the events that changed it (sleep, activities, stress, naps) with their impact.

Inputs: toDate (required), fromDate (required).

getDailyHeartRateB

Daily heart rate for one date (includes resting heart rate), yyyy-MM-dd.

Inputs: date (required).

getDailySummaryA

Daily user summary (steps, calories, stress, body battery, resting HR) for one date, or for up to 14 days (fromDate and toDate; the range answer has Garmin's v2 field names), yyyy-MM-dd.

Inputs: date, toDate, fromDate.

getDashboardDataA

All the data of the training dashboard in one call: HR zones, fitness age, the activities of the last weeks weeks (compact summaries, with strength sets and laps where they apply), the activities of the weeks before for the period comparison, daily HRV, and the last 14 days of sleep and daily summaries, and units: the measurement system of the Garmin profile (metric, statute_us or statute_uk) that the page shows; the data itself is always metric; locale: the language of the Garmin profile, e.g. it or pt-BR. Keeps a local cache and fetches from Garmin only what is new since the last call, so a rebuild or an update needs few calls. sync in the result says what was fetched: Garmin calls, .FIT files downloaded (fitDownloads) and new activities. digest, first in the result: the server's totals for the whole period and for each Monday-Sunday week (sessions, km, hours, load), the training load of the last 7 and 28 days, best efforts, races and strength top sets, the long runs with their half split and HR drift, the longest run and the race predictions (Riegel), the page's readiness verdict for today with its inputs (readiness), and today's fitness, fatigue and form (fitnessFatigue); quote them instead of your own sums. For another date range, use the activities: each one is on its own line. A load is null (n/a) when the sessions have none; estimatedLoads counts the loads that are estimates from heart rate. A week with partial: true starts before the period. Without HRV and sleep data the digest has no readiness: give the verdict as n/a.

Inputs: weeks, workouts.

getFitnessAgeB

Garmin fitness age for a date, yyyy-MM-dd: fitness age vs chronological age, the achievable fitness age, and its components (body fat, vigorous days and minutes per week, resting HR) with the targets Garmin suggests.

Inputs: date (required).

getHeartRateZonesB

Heart rate zones currently configured in Garmin Connect.

Inputs: no named parameters.

getHrvRangeC

Daily HRV (overnight) summaries for a date range, yyyy-MM-dd.

Inputs: toDate (required), fromDate (required).

getSleepA

Sleep for one night (date: the morning you woke up), or for up to 14 nights (fromDate and toDate), yyyy-MM-dd, as one compact row per night: bedtime and wake (local HH:mm), hours of sleep, deep, light, REM and awake, the sleep score and its quality, the sleep need (hours), average heart rate, average and lowest SpO2, average respiration, awake count, average sleep stress and Garmin's feedback. Missing values are left out, and a night without sleep data has only its date. Set raw=true for Garmin's JSON.

Inputs: raw, date, toDate, fromDate.

getWeightA

Weight for a date range, yyyy-MM-dd: the latest weight of each day (with body fat, muscle and bone mass, BMI and body water when a scale records them), the average of the range, and the last weight before and the first after the range. Set includeAll=true for every entry of each day. Weight, muscle mass and bone mass are in grams.

Inputs: toDate (required), fromDate (required), includeAll.

listActivitiesA

List the user's Garmin activities (most recent first) as a compact summary: id, name, type, local start time, distance (km), moving duration, average pace, average/max heart rate, cadence, ascent; when Garmin has them: elapsed time (if longer than moving time), race flag, Garmin training load, aerobic/anaerobic training effect and label, seconds in HR zones 1-5, calories, moderate/vigorous intensity minutes, body battery change, steps, swim SWOLF, pool length, lengths and strokes, power, mountain-bike grit and flow, running form (stride, ground contact, vertical oscillation and ratio), grade-adjusted pace, best efforts (1k, mile, 5k, 10k, half, marathon) and run/walk segments. Dates are yyyy-MM-dd. Set raw=true for Garmin's full JSON.

Inputs: raw, limit, names, endDate, +2 more.

scheduleDashboardRefreshA

Turns on, changes or stops the automatic refresh of a dashboard page. Use it only when the user asks for it or says yes to the question of a dashboard prompt. A job in the scheduler of the computer (launchd, cron or Task Scheduler) replaces the data of the page at the given times, also with no assistant open. The refresh removes the coach notes, because old notes do not agree with new data. The computer must be on at that time. The page must exist (writeDashboard first). last is the last automatic run: its time and the pages that it could not update, with the error. A page shows a note when its update is more than 1 hour late: last tells why. cron: convert what the user says, in any language, into a 5-field cron expression in local time: minute hour day-of-month month weekday, numbers only (0 = Sunday), e.g. "0 7 * * 1-5" for weekdays at 7. Two runs must be at least 1 hour apart. The cron is for all scheduled pages; path adds that page (default the main page); off stops the refresh of path, or of every page when no path is given. Without arguments it only reads. The reply has next, the next runs in local time: tell them to the user in their language, so they can check the schedule.

Inputs: off, cron, path.

showDashboardA

Shows the training dashboard in the chat, in assistants that show MCP Apps: the page of path (default /garmin-dashboard.html) with its layout, custom widgets, languages and settings, or the preset page when there is none, with new data of the last weeks weeks. Writes nothing and has no coach notes. Returns the page path, the digest of the data and the page settings. Other assistants show only this reply: there, writeDashboard writes the page as a file.

Inputs: path, weeks.

writeDashboardA

Writes the training dashboard page (default /garmin-dashboard.html) with the data of the last weeks weeks, and returns its path and a short digest of the data (totals, weekly sums, load, best efforts, races, long runs, race predictions, strength top sets, readiness, fitness and form, HRV, recovery, fitness age, sync) for the coach notes. Without HRV and sleep data the digest has no readiness: give the verdict as n/a. An existing page keeps all its code, layout and widgets: its data is replaced. A page with different page code gets the page code of the server and keeps its layout and widgets; the result then has page: "upgraded", previousServer (the server version that wrote the page, n/a when unknown) and server. Every page from the template also gets the custom widgets of the widget library (/widgets.json), not placed on a board. On a page from the template, an edited board also gets the widgets that a release adds to its preset, one time; the result lists the ones that the page shows in addedWidgets (board -> widget ids). layout writes a new page from the template: preset (the default widgets) or blank (empty boards). It keeps the languages added with editDashboard languages. page writes your own page code instead; it must contain /* garmin-data:start /null/ garmin-data:end */. A replaced page is kept as .bak. The .bak keeps the page from before the build: a write that follows within 15 minutes (the notes, a new title) does not replace it. notes: at most 5 plain-text coach notes; the server escapes them. settings replace the page's settings (title, headline, sports, data to leave out, languages, themes); without them the page keeps its own. The page holds only the data, languages and themes they keep. pageLanguages in the result lists the languages of the page's Language menu, and settings the settings that the page keeps. missingProfileLanguage is the language of the Garmin profile when the page has no texts in it (it shows English); editDashboard languages adds it. missingWidgetTexts lists the custom widgets that miss texts in a language of the page, with those languages; editDashboard widgetTexts adds them. preview: true writes nothing: it returns the digest, the activities of each board and the settings of the page.

Inputs: page, path, notes, weeks, +3 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 20 tools

    Disambiguation4/5

    Most tools have clearly distinct targets, and the activity sub-tools (getActivity, getActivityLaps, getActivitySets, getActivityWorkouts) are explicitly differentiated with cross-references ("getActivity does not have them"). There is mild overlap between getDailySummary and the individual getters (getDailyHeartRate, getBodyBattery), and between getDashboardData and the per-domain readers, but descriptions largely resolve it. The garminGet escape hatch is clearly framed as a fallback.

    Naming Consistency4/5

    Names are uniformly camelCase with a predictable verb_noun pattern: get*, list*, download*, write*, edit*, show*, schedule*. The main deviation is garminGet, which uses a noun-prefix style inconsistent with everything else, but overall the convention is readable and predictable.

    Tool Count4/5

    Twenty tools is on the heavier side, but the Garmin domain is genuinely broad (activities, sleep, HRV, HR, weight, body battery, zones, fitness age) and each reader covers a distinct endpoint. The five dashboard tools form a coherent subsystem (read, write, edit, show, schedule) rather than redundant surface.

    Completeness4/5

    Read coverage is extensive across health, activity, and training domains, and the dashboard lifecycle plus a generic garminGet fallback make most workflows achievable. The main gap is the absence of writes back to Garmin (logging weight, uploading activities), though this appears to be a read-focused personal server by design.

    Maintenance

    ActivityMaintained
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      C
      maintenance
      Enables AI assistants to access and query Garmin Connect health and fitness data, including sleep, HRV, training load, and activities, with an optional coaching plugin for personalized training plans.
      9 npm
      4
      -
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables reading and analyzing Garmin Connect data—activities, health metrics, FIT files, and challenges—through natural language, for AI assistants like Claude and ChatGPT.
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI assistants to retrieve and discuss personal fitness activities, training splits, heart-rate zones, and daily health metrics from a Garmin Connect account.
      MIT