Skip to main content
Glama

Catence

Local MCP server for primary Garmin data, with added Intervals.icu metrics and Strava enrichment.

Catence

... what?

As a context, I'm both an endurance athlete and a data junkie. I already got a coach for all the serious stuff, but I wanted to hook up some—any—LLM to the insane amount of data collected from Garmin, derived on Intervals.icu (I don't pay for TrainingPeaks) and comparable efforts on Strava segments. Naturally, the first answer was a local MCP server for my current tooling.

Related MCP server: fitMCP

What is included

  • Garmin, Intervals.icu, and Strava ingestion with source-aware normalization.

  • Read-only MCP tools, plus explicitly named, lock-guarded write tools for Strava hydration and detached syncs.

  • One shared Catence agent can serve several isolated athlete stores. Every personal-data MCP call names an athleteId; Catence never silently combines athletes.

  • A password-protected Chainlit Console with an authenticated dashboard, a data-sync button with live progress, and in-app model management.

  • A generated demo catalog for safe evaluation in Glama, desktop MCP clients, or local development.

Catence helps explore recovery, training load, trends, activity detail, swimming/cycling/running progress, segments, gear, and data quality. It reports the evidence and coverage it can see; it does not diagnose or prescribe training.

Requirements

  • Node.js 22+

  • Python 3.12+ and uv for Garmin and Strava provider workers

  • Provider credentials for the athletes you choose to sync

Quick start

Install Catence and create the first athlete. The default catalog home is ~/.catence; set CATENCE_HOME or pass --home to use a different location.

Every catence-data command requires --athlete <id>; there is no default athlete. Pair it with --home <dir> to select the catalog when not using the default home.

npm install --global catence@latest          # or catence@beta
catence-data setup --athlete alex --label "Alex"

Store each provider value through stdin so it does not enter shell history. Values are written to the selected athlete's owner-only local secret file.

printf %s 'alex@example.com' | catence-data --athlete alex secret set --provider garmin --field email --value-stdin
printf %s 'your-garmin-password' | catence-data --athlete alex secret set --provider garmin --field password --value-stdin
printf %s 'intervals-api-key' | catence-data --athlete alex secret set --provider intervals --field apiKey --value-stdin
printf %s '12345' | catence-data --athlete alex secret set --provider intervals --field athleteId --value-stdin

Sync and create retrieval context:

catence-data --athlete alex sync --provider all
catence-data --athlete alex build-retrieval-index

Start the stdio MCP server:

catence

An agent first calls list_athletes, then includes athleteId with every data tool. This is intentional: a shared agent may access the stores you configured, but no tool implicitly aggregates or crosses between athletes.

Add another athlete

catence-data athlete add --id sam --label "Sam"
printf %s 'sam@example.com' | catence-data --athlete sam secret set --provider garmin --field email --value-stdin
printf %s 'sam-password' | catence-data --athlete sam secret set --provider garmin --field password --value-stdin
catence-data --athlete sam sync --provider garmin
catence-data athlete list

Garmin, Intervals, and Strava client credentials are isolated per athlete. Strava OAuth tokens remain in that athlete's own store. The old 0.1 single-store directory cannot be migrated safely: create a fresh home and re-sync each athlete.

Common operations

catence-data --athlete alex status
catence-data --athlete alex sync --provider intervals
catence-data --athlete alex sync --provider garmin --from 2025-07-29
catence-data --athlete alex backfill --provider garmin --from 2020-01-01 --refresh
catence-data --athlete alex retry --run <run-id>
catence-data --athlete alex progress --watch
catence-data --athlete alex auth strava --callback
catence-data --athlete alex disconnect strava
catence-data update --check
catence-data update

Documentation

Document

Covers

Deployment: local MCP

Install, catalog, secrets, sync, background progress, stdio/HTTP MCP, demo, common operations

Deployment: local Console

Local web chat setup, model config, doctor, updates, troubleshooting

Deployment: Docker

One-container stack: deploy script, .env, sync.sh, MCP exposure (SSH/Tailscale), Cloudflare Tunnel

Configuration

Complete config.json schema: rate limits, Strava budget, Console profiles, environment variables

LLM providers

Model providers (OpenAI, Anthropic, OpenAI-compatible/Azure, Opencode Go/Zen), reasoning effort

Architecture

Design rationale, layers, data flow, serving

MCP activity retrieval

Implementation contract for answering questions, current tools, planned endpoints

Distribution

Release artifacts: npm, PyPI, APM, MCPB

MCP clients and HTTP

For a packaged installation, point a client at catence:

codex mcp add catence -- catence
claude mcp add --transport stdio catence -- catence

For a source checkout:

codex mcp add catence -- npm --prefix /absolute/path/to/catence run mcp

Optional local Streamable HTTP MCP and dashboard APIs:

catence serve --host 127.0.0.1 --port 8787

GET /api/v1/athletes returns IDs and labels only. GET /api/v1/dashboard requires athleteId, for example http://127.0.0.1:8787/api/v1/dashboard?athleteId=alex&days=28. Browser origins must be listed with --allow-origin; the packaged Console instead proxies the dashboard through its authenticated same-origin route. The MCP server has no authentication of its own.

Configuration

config.example.json documents rate limits, Strava budgets, and Console model profiles. Keep per-athlete provider values in catence-data secret set, not in .env or config.json. The full config.json schema —including per-model reasoning effort— is documented in docs/configuration.md and docs/llm-providers.md.

For source development:

npm ci
npm run check
npm test
UV_CACHE_DIR=$PWD/.cache/uv uv run --project console --group dev python -m pytest console/tests -q

Data and caveats

The current available sources respond to my own used platforms. I used some wrappers:

Strava is only used for segments and gear.

Caveats

There are two caveats to the data fetching, both coming from the fact that this was created to be used by a single person. Accessing the full Garmin API requires applying via a company—which I don't have—and getting Strava data for multiple users is another headache I don't want to get into.

  • I don't use the official Garmin Connect API. The library uses email/pwd.

  • Connecting Strava requires the user to be a Strava Premium subscriber and create an API application. The rotating token is stored locally in <data-dir>/secrets/strava.json.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • MCP server for Withings health data — sleep, activity, heart, and body metrics.

  • Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.

  • MCP server for interacting with the Supabase platform

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rifusaki/catence'

If you have feedback or need assistance with the MCP directory API, please join our Discord server