FitCoach MCP

FitCoach MCP

Enables Claude or ChatGPT to act as a personalized fitness coach with persistent goals, conversational workout logging, and weekly generated training plans.

Category
访问服务器

README

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.

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_week supersedes 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 first log_workout, plan_my_week, or log_run. Onboarding and import_history deliberately do not start it. Read tools are never locked and delete_my_account is 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_ACCESS is 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.ts runs a deterministic red-flag matcher over all 9 user free-text surfaces, enumerated in one place (freeTextSources() in src/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 :3000

AUTH_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=supabase

Nothing 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.

DATABASE_URL Backend Used for
set PostgresStorage — Supabase Postgres, ideally the transaction-pooler URL (port 6543) production
unset, dev/test PgliteStorage — embedded Postgres, optionally persisted via DATA_DIR 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 + StubBillingProvider

No 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
docs/CURRENT-STATE.md Source of truth — counts, identity, what is and isn't built
docs/INTELLIGENCE-DESIGN.md The engine: every algorithm, constant, and guardrail
docs/RUNBOOK.md Operating manual — env vars, deploys, EARLY_ACCESS, rate limits, auth
docs/INCIDENT-RUNBOOK.md It's down (or looks down): triage probes and cause playbooks
docs/PRIVACY-CHECKLIST.md This product stores injury notes and wellbeing text — treat as sensitive
docs/DEPLOY-NOTES.md Fly specifics
docs/WEARABLES.md Recovery-metric ingestion
docs/SUBMISSION-PACK.md Directory submission material

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选