FitCoach MCP
Click on "Install 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., "@FitCoach MCPLog my workout: squat 5x5 at 225 and bench 3x8 at 185, then plan my week."
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.
FitCoach MCP
A remote MCP server that turns Claude or ChatGPT into a fitness coach with memory: persistent goals, conversational workout logging, per-user parameter fitting, and a weekly "plan my sessions" ritual that produces a versioned, explained training plan.
The division of labor: the LLM captures conversation and narrates; the deterministic engine in src/engine/ makes every programming decision (progression, volume, deloads, exercise substitution, run pacing, autoregulation). Same inputs, same plan, always.
Facts live in one place
docs/CURRENT-STATE.md is the source of truth for counts, constants, deployment identity, and what is and isn't built. This README deliberately restates as little of it as possible, because an August 2026 audit found this file, RUNBOOK, and SUBMISSION-PACK all independently claiming 11 tools when there were 22. If a number here disagrees with CURRENT-STATE, CURRENT-STATE wins and this file is stale. If CURRENT-STATE disagrees with the code, fix CURRENT-STATE first.
Related MCP server: WorkoutGuide MCP
Product mechanics
Raw log is append-only. Sessions, sets, feedback, runs, and recovery metrics are never edited — everything intelligent is derived state in
user_params(e1RMs, trends, stall detection, recovery score, volume landmarks, run fitness), refit on every planning call.Plans are versioned. Every
plan_my_weeksupersedes the old revision and records a parent pointer + a human-readable rationale — "git, minus git."Trial is a training block, not a clock.
TRIAL_DAYS = 35(a 28-day mesocycle + 7 days grace), starting at the firstlog_workout,plan_my_week, orlog_run. Onboarding andimport_historydeliberately do not start it. Read tools are never locked anddelete_my_accountis never gated — your data stays yours.Upgrade happens in the conversation. A blocked write tool returns a warm upgrade message as tool content (not an error) so the model relays it at the moment of intent.
EARLY_ACCESSis currently ON, so nothing is gated right now and the trial clock never starts. The gate is fully built and tested; the flag just holds it open. See CURRENT-STATE → Entitlements.Safety screen.
src/server/safety.tsruns a deterministic red-flag matcher over all 9 user free-text surfaces, enumerated in one place (freeTextSources()insrc/server/tools.ts). An emergency-tier match strips everything else out of the response, including the upgrade footer — and it runs on the entitlement-blocked path too, so a gated-out user reporting chest pain gets the escalation, not a sales pitch.
Quickstart (local)
npm install
npm test # full suite; see CURRENT-STATE for the current count
AUTH_MODE=dev npm run dev # Streamable HTTP MCP server on :3000AUTH_MODE is required and explicit — the server refuses to start if it is
unset or anything other than dev / supabase:
Fatal startup error: Error: Unknown or missing AUTH_MODE null. Set AUTH_MODE=dev or AUTH_MODE=supabaseNothing in this repo loads a .env file — there is no dotenv dependency
and no --env-file flag on the dev script. .env.example documents the
variables, but copying it to .env has no effect: pass variables inline (as
above), export them, or add --env-file=.env yourself.
Once running there are two probes, and the difference matters:
curl localhost:3000/healthz returns {"ok":true} without touching the
database (liveness — it is what Fly polls every 30s, so a DB blip must not fail
it), and curl localhost:3000/readyz makes a real query and returns
{"ok":true,"db":"up","durationMs":N} or a 503 db:down. /readyz is the one
external monitoring watches.
In dev mode any bearer token dev-<name> authenticates as user <name>; it
is refused outright when NODE_ENV=production.
Connect from Claude (custom connector) or MCP Inspector with URL
http://localhost:3000/mcp and header Authorization: Bearer dev-henry, then
try: set up a profile, set a goal, log a workout, and plan my week.
Other scripts: npm run build (tsc + copies migrations into dist/),
npm start (run the build), npm run test:watch, npm run provision
(Supabase), npm run seed-demo, npm run metrics, npm run deploy (see
Deploying).
Storage
One function decides the backend: createStorage() in
src/storage/select.ts, called once from
src/server/index.ts.
| Backend | Used for |
set |
| production |
unset, dev/test |
| dev and tests |
unset, production-like | throws at startup | — |
"Production-like" means NODE_ENV=production or AUTH_MODE=supabase, and
the refusal is deliberate. DATA_DIR is not set in fly.toml, so the old
PGlite fallback was in-memory: the server booted clean, /healthz stayed
green, tools succeeded, and every user got a fresh empty account that emptied
again on the next restart. A dropped secret looked exactly like a healthy
deploy. It now fails loudly instead (tests/storage-select.test.ts).
Both are complete implementations of the same Storage interface and run the
same migrations (src/storage/migrations/, 0001_init … 0015_rls_v7, with
RLS policies in the paired _rls_ files). PGlite is not a stub and
Postgres is not future work: PostgresStorage is a complete, shipped
implementation and is what the live deployment runs. The one
query where the two backends must not drift, the population-tuning aggregate,
is shared verbatim from src/storage/tuning-shared.ts.
PostgresStorage.init() applies every migration in order at boot. Portable
files are additive and idempotent, so re-running against a live database is
safe; the _rls_ files reference Supabase's auth.uid() and are applied
automatically only when the connected database exposes it — plain Postgres in
local dev and CI skips them.
Note that 71 tests skip unless a real DATABASE_URL is present. Run the suite
against Postgres before a release, not just PGlite.
Deploying
The Fly app is fitcoach-hs — not the package
name. Both fly.toml and scripts/deploy-fly.sh name it, so a bare deploy is
correct:
FLY_API_TOKEN=... npm run deploy(Until 0.7.1 both defaulted to fitcoach-mcp, so a bare deploy would create
that app, deploy there, and health-check its URL — a green run against an app
nobody uses. If a stray fitcoach-mcp app is still on the Fly account from
back then, flyctl apps destroy fitcoach-mcp it; a decoy that answers
/healthz is worse than no app.)
fly.toml declares a [[mounts]] volume and that is deliberate — it matches
the running machine, which keeps deploys prompt-free. The volume is unused
(prod data is in external Postgres) but it pins the app to a single machine,
which the in-process rate limiter depends on. Details in
docs/DEPLOY-NOTES.md.
Architecture
src/
types.ts # binding contracts: domain, Storage, Engine, TOOL_NAMES
storage/
migrations/ # 0001..0015; portable DDL + paired Supabase RLS policies
select.ts # createStorage(): DATABASE_URL ? Postgres : PGlite
postgres.ts # production Storage impl (Supabase Postgres)
pglite.ts # dev/test Storage impl (embedded Postgres)
tuning-shared.ts # the aggregates-only tuning evidence SQL, shared by both
seed-exercises.ts # exercise catalog: substitutes, movement pattern, fatigue cost
engine/ # deterministic; see docs/INTELLIGENCE-DESIGN.md
e1rm.ts # Epley + RPE→RIR adjustment
fitting.ts # fitParams: e1RM smoothing, trends, stalls, freshness, landmarks
planner.ts # planWeek: splits, progression, deloads, hybrid day layout
running.ts # run fitness, program-mode arbitration, run-week construction
adjust.ts # same-day autoregulation (short on time / beat up)
alignment.ts # goal-vs-behaviour drift detection, proactive check-ins
experiments.ts # 2-week n-of-1 plateau tests
recap.ts # weekly recap + PR detection
tuning.ts # bounded population tuning from aggregate evidence
server/
index.ts # express + stateless StreamableHTTP, per-request server factory
auth.ts # dev tokens / Supabase JWT (JWKS) + RFC 9728 metadata
consent.ts # OAuth 2.1 consent UI (Supabase as authorization server)
entitlements.ts # mesocycle trial gate + EARLY_ACCESS
metering.ts # idempotent usage events
safety.ts # deterministic red-flag screen (emergency / injury)
temporal.ts # server-side, timezone-aware natural-language dates
rate-limit.ts # in-process burst + sustained limits
tools.ts, tools-*.ts, tools/*.ts # the tool surface (see CURRENT-STATE)
pages/, site.ts, share.ts, ui/ # landing, /connect, /docs, share links
billing/provider.ts # BillingProvider interface + StubBillingProviderNo payment provider is wired. StubBillingProvider is what runs and
CHECKOUT_BASE_URL is unset, so checkout links fall back to the live
/#pricing section. Stripe is runbook Phase 4.
Documentation
Doc | What |
Source of truth — counts, identity, what is and isn't built | |
The engine: every algorithm, constant, and guardrail | |
Operating manual — env vars, deploys, | |
It's down (or looks down): triage probes and cause playbooks | |
This product stores injury notes and wellbeing text — treat as sensitive | |
Fly specifics | |
Recovery-metric ingestion | |
Directory submission material |
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceExposes Whoop fitness data (recovery, sleep, strain, workouts) to Claude for use as a daily training coach, enabling natural language queries about your health metrics and training readiness.MIT
- FlicenseNot gradedqualityCmaintenanceEnables workout tracking and coaching within Claude conversations, managing exercise configs, logs, streaks, and health metrics via an MCP server with PostgreSQL.
- AlicenseNot gradedqualityBmaintenanceEnables Claude to act as a personal health coach by connecting to Garmin wearable data and Notion workspace for automated calorie tracking, photo food logging, and coaching insights.MIT
- AlicenseNot gradedqualityAmaintenanceEnables Claude to analyze training data from spreadsheets and Amazfit watches, providing insights on strength progression, running metrics, recovery status, and readiness, with tools for weekly reviews, exercise progression, and health reporting.1MIT
Related MCP Connectors
Create Hevy routines and analyze your training from chat. Unofficial; BYO Hevy PRO API key.
WHOOP recovery, strain, sleep and workouts in Claude via official WHOOP OAuth. Free, open source.
Garmin data in Claude: 135 tools — activities, sleep, HRV, training, workouts. Free, open source.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/henryhf/fitcoach-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server