Running Companion MCP Server
Personal project, not offered for public use.
Through Claude's MCP connector, you can inspect, analyze, and sync a personal Garmin running/health database.
View daily readiness, recovery, HRV, sleep, training load, Body Battery, activity, weight, and fitness age.
Review weekly summaries/reports, trends by week or month, and activity lists/details with laps, zones, planned vs actual, and best efforts.
Explore insights and personal patterns, body/nutrition guidance, sleep and stress deep dives, and run weather/heat forecasts.
Track lifetime progress, milestones, records, PBs, and year-in-review/form analysis.
Read the database schema and run read-only SQL SELECT queries (max 200 rows).
Trigger a Garmin sync to fetch new activities, sleep, HRV, wellness, and weigh-ins and recompute metrics.
Integrates with Garmin's official read-only Personal API to sync and query running and health data, including activities, sleep, HRV, stress, Body Battery, weigh-ins, and derived training metrics.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Running Companion MCP Server What does my long-term training load look like?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Running Companion
My personal running and health dashboard, built on Garmin's read-only Personal API. It runs on my Windows laptop: the Garmin key and the database stay there. Claude can read the data through the app's MCP connector. Races, predictions and training plans stay in Garmin Connect.
This is a personal project. It isn't set up or supported for anyone else.
Install and run
Download
Running-Companion-Setup-<version>.exefrom the latest release and run it. It brings its own Node and needs no administrator rights. Windows warns about an unsigned installer the first time: More info → Run anyway.Start Running Companion from the Start Menu. A window opens along with the browser. Closing the window turns the app off.
The first start shows the setup page: choose a password and paste a Garmin Personal API key.
Data:
%LOCALAPPDATA%\Running Companion\data. Installing a new version or uninstalling never touches it.Forgot the password: Start Menu → "Running Companion (new password)".
Phone and Claude on the web: with Tailscale connected, the window asks once whether to open a public HTTPS address through Tailscale Funnel (only while the window is open). The answer is kept in
desktop.jsonnext to the data folder; delete that file to be asked again.Claude connector: Settings → Claude shows the address (
https://<machine>.ts.net/mcp). Add it in Claude as a custom connector and approve it with the password.Food log: ask Claude to log a meal ("log this", with a photo or a description). It only logs when asked. Meals show on Today (removable there) and the last two weeks with feedback on Body.
Backups: one a day in
data\backups, automatic. To restore: close the app, then from a clone runnpm run restore -- <file>withCOMPANION_DATA_DIRpointing at the data folder.
Related MCP server: garmin-mcp
Development
Node 26 (it runs the TypeScript directly).
Command | What it does |
| The app on generated data at http://localhost:8788: no key, no login |
| The server on http://localhost:8787 with data in |
| The dashboard with instant reload, proxying |
| Builds the dashboard |
| Sync from Garmin; recompute metrics ( |
| Back up or restore the data folder |
| New login password |
| Tests (synthetic data only) and types |
Releasing: put the notes under a new version in CHANGELOG.md, set that version in every package.json, push,
then publish a release with tag v<version> on GitHub. CI builds the installer, installs, starts and uninstalls it
on Windows, and attaches it to the release.
Notes
Metrics: formulas and their assumptions are in
packages/metrics/srcand in the MCP tooldescribe_data. Thresholds (LTHR, max and resting HR) come from the latest Garmin profile.Weather: Open-Meteo, no key. It receives coordinates rounded to about 100 m and dates.
Maps: OpenStreetMap tiles.
Privacy: when Claude reads the data, the tool results it uses are sent to Anthropic as part of that chat.
License
Copyright (C) 2026 Dimitris Tsiakas. AGPL-3.0-or-later, see LICENSE.
Not affiliated with Garmin. Not medical advice.
Available Tools
15 toolsdescribe_dataDescribe dataARead-only
Schema of every table, units, how each derived metric is calculated, the HR thresholds in use and known caveats. Read before writing SQL.
Inputs: no named parameters.
get_activityActivity detailsARead-only
Everything about one activity: summary, running dynamics, zones, the planned workout steps, planned vs actual per step (executed_steps: auto-laps merged back into steps, pace judged against the target as on/fast/slow), every lap and best efforts. Defaults to the latest activity.
Inputs: activity_id.
get_best_effortsBest effortsBRead-only
Fastest time for 400 m, 1 km, 1 mile, 3 km, 5 km, 10 km, half and marathon found inside any run. Optionally only since a date.
Inputs: since.
get_body_reportBody and nutritionBRead-only
Weight trend against the user's goal with a safe-rate assessment and projected date, body composition (two-week averages of fat and muscle, a muscle-loss flag), Garmin's fitness age, calories burned on rest, training and big days, the user's own sweat rates (ml/h, overall and warm vs cool), and daily protein and carbohydrate ranges for their weight from the ACSM/ISSN position stands. Pass run_minutes (and hard) for a fuel and fluid plan for one run. This is general sports-nutrition guidance, not a diet: never suggest aggressive deficits, and point to a sports dietitian for personal plans.
Inputs: date, hard, run_minutes.
get_insightsInsightsARead-only
Signals for a day (warnings such as possible illness, overreaching, load spikes; watch items such as easy-run drift, sleep debt, irregular bedtimes, stress streaks; positives) and the user's personal patterns: comparisons from two years of their own data (late bedtimes, short nights, hard sessions, stressful days, evening runs, running after short nights or in heat), each with sample sizes, p-values (p raw, q adjusted for the number of comparisons: q decides what counts as an effect), effect size d and a caveat. Patterns are associations, not proof of cause; say so. Pass a date (defaults to the latest day with data).
Inputs: date, include_patterns.
get_progressProgress, milestones and year in reviewARead-only
Lifetime totals, milestones passed with their dates (total km, run counts, first times under round times per distance), the next milestones with an estimated date at the recent pace, records (longest run, biggest week and month, weekly streaks) and personal bests per distance. Pass year for that year in review (volume, consistency, PBs set, fitness and resting values from start to end of year, time of day, hottest and coldest run, against the previous year). Pass form: true for running form by month on easy runs, adjusted to the same pace.
Inputs: form, year.
get_run_forecastWhen to runARead-only
Hourly forecast for today's remaining hours and tomorrow (06:00 to 22:00) where the user usually runs, from Open-Meteo: air temperature, dew point, humidity, wind, chance of rain, and the heat cost of each hour (Hadley's temperature plus dew point rule: estimated % slower at the same effort). Each day has the coolest dry window and the hour to avoid. Clock hours are local. A run's own weather and heat-adjusted pace are in get_activity.
Inputs: no named parameters.
get_sleep_stress_reportSleep and stress in depthBRead-only
Sleep: the last 4 weeks of nights (bedtime, wake time, hours, Garmin's sleep need, score), tonight's suggested bedtime (Garmin's need counted back from the usual wake time for tomorrow's kind of day, plus a realistic 30-minute step when the target is far from the usual bedtime), 7-night sleep debt, timing consistency (spread of bed and wake times, weekday vs weekend shift) and the stage mix against Garmin's ideal ranges. Stress: Body Battery charged vs drained (2-week balance and morning levels), what charges and drains it per day (sleep, naps, workouts, stress, everyday), awake minutes at each stress level, workdays vs weekends. Clock times are local. For what affects sleep for this user, also see get_insights (bedtime, short nights, evening runs).
Inputs: date.
get_todayTodayBRead-only
Recovery status (green/amber/red with reasons), HRV, resting HR, sleep, training load (fitness/fatigue/form), last night in detail (score, stages, bedtime, breathing rate, SpO2), energy (Body Battery this morning, yesterday's stress), everyday activity (steps, calories, weekly intensity minutes), weight trend, fitness age with its biggest lever and the weight goal, the latest run, and how fresh the data is. Pass a date for a past day.
Inputs: date.
get_trendTrendBRead-only
A metric aggregated per week or month. Metrics: fitness (Fitness (CTL) at period end); form (Average form (TSB)); load (Total training load (TRIMP)); run_km (Running distance (km)); runs (Number of runs); hrv (Average nightly HRV (ms)); resting_hr (Average resting HR (bpm)); sleep_h (Average sleep (hours)); sleep_need_h (Average Garmin sleep need (hours)); weight_kg (Weight trend (kg) at period end); body_fat_pct (Body fat trend (%) at period end); easy_efficiency (Metres per heartbeat on easy outdoor runs); pace_at_ref_hr (Pace at the reference HR on outdoor runs); decoupling (Average decoupling (%) on steady runs of 30+ min); low_intensity_pct (Share of running time below LT1 (%)); sleep_score (Garmin's sleep score (0–100), average per night); deep_sleep_h (Deep sleep per night (hours)); rem_sleep_h (REM sleep per night (hours)); breathing_rate (Overnight breathing rate (breaths per minute)); spo2 (Overnight blood oxygen, SpO2 (%)); sleep_stress (Stress during sleep (0–100)); stress (All-day stress (0–100), average per day); body_battery_morning (Body Battery peak of the day, usually right after waking (0–100)); steps (Steps per day); calories (Calories burned per day (resting + active)); active_calories (Active calories per day); intensity_minutes (Intensity minutes, total for the period (vigorous count double, as Garmin and the WHO count them)).
Inputs: metric (required), to, from, period.
get_weekly_reportWeekly reportARead-only
The computed report for one Monday-to-Sunday week: a headline, training (volume against the previous four weeks, intensity balance, form), key sessions with planned vs actual, recovery (HRV, resting heart rate, status days, sleep against need, sleep score, bedtime regularity), life (stress, Body Battery), body (weight trend), new personal bests and the signals raised during the week. Lines carry a tone (good, neutral, concern). Start every weekly review from this. Defaults to the last complete week.
Inputs: week_start.
get_weekly_summaryWeekly summaryBRead-only
One row per Monday-based week: runs, km, hours, load, intensity split, efficiency, fitness/form, weight, sleep, HRV, resting HR.
Inputs: weeks.
list_activitiesList activitiesBRead-only
Activities newest first, with pace, HR, load, intensity split, efficiency and RPE. Filter by date range, run category or activity type.
Inputs: to, from, type, limit, +1 more.
querySQL queryARead-only
Run one read-only SQLite SELECT against the database (max 200 rows). Call describe_data first for tables, units and conventions.
Inputs: sql (required).
sync_garminSync from GarminAIdempotent
Fetch new data from Garmin (activities, sleep, HRV, wellness, weigh-ins) and recompute metrics. Usually takes 10–30 seconds.
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 15 tools
Most tools target a clearly distinct slice of the data: get_today (daily snapshot), list_activities/get_activity (activity drill-down), get_trend (aggregates), get_run_forecast (weather), get_progress (lifetime/PBs), describe_data/query (raw SQL). The report family (get_weekly_report, get_sleep_stress_report, get_body_report, get_insights) overlaps domain-wise with get_today and get_weekly_summary, but descriptions give explicit guidance ('Start every weekly review from this', 'one row per Monday-based week') that keeps selection tractable.
Eleven tools use a clean get_<subject> pattern (get_today, get_trend, get_weekly_report, get_run_forecast...), plus list_activities, a coherent verb_noun shape elsewhere. Minor deviations: bare `query` and the loose `_report` ordering vary between subject-first and domain-first (get_weekly_report vs get_sleep_stress_report), but the convention is recognizable throughout.
Fifteen tools is at the upper end of a healthy set and each one maps to a distinct question an agent would actually ask (today, activity, trend, week, sleep, body, forecast, progression, insights, raw SQL). No tool looks like padding or a synonym for another.
Read coverage is excellent across training, recovery, sleep, stress, body composition, weather and lifetime progress, with query as an escape hatch for anything unmodeled. The gap is write-side: RPE is surfaced in list_activities but there is no tool to set RPE, notes, tags or goals, so the agent can never annotate or correct the data it reads.
Maintenance
Related MCP Connectors
Garmin watch data for AI assistants: activities, sleep, HRV, recovery. Never writes to Garmin.
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
tri-train is a training platform for triathletes that syncs activities from Strava and Garmin and exposes them to Claude through a remote MCP server. Ask Claude how your last block went, why your run pace dropped, or whether you are fresh enough for Sunday's race, and it answers from your real data: activities with laps and grade-adjusted pace, weekly load and the performance management chart (CTL/ATL/TSB), sleep, HRV and resting heart rate, and your race calendar with predictions. Claude can also act: create and adjust planned workouts with structured intervals, push them to your Garmin watch, add races and write notes. Every change is journaled and can be undone. Read and write access are separate OAuth scopes, and the server enforces them on every call. Built and hosted in Switzerland by a triathlete; data stays on our own servers (Swiss revDSG / GDPR).
Garmin data in Claude: 135 tools — activities, sleep, HRV, training, workouts. Free, open source.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceConnects Claude Desktop to your Garmin Connect running data stored locally in SQLite, enabling querying, syncing, and AI analysis of fitness activities.1-
- FlicenseAqualityDmaintenanceExposes your Garmin Connect data (activities, sleep, recovery, training status) to Claude in read-only mode.7-
- AlicenseNot gradedqualityBmaintenanceEnables reading and analyzing Garmin Connect data—activities, health metrics, FIT files, and challenges—through natural language, for AI assistants like Claude and ChatGPT.MIT
- AlicenseAqualityBmaintenanceProvides Claude Code and Claude Desktop with safe, read-only access to your local Garmin training data, readiness decisions, run details, and trends so you can get coaching advice in natural language.15164 PyPI9MIT