Skip to main content
Glama

目录

概述 ·  安装 ·  配置 ·  工具 ·  身份验证 ·  重要发现 ·  限制 ·  架构 ·  法律

Related MCP server: tonal-mcp-cloudflare-workers

概述

mcp-fitbod 将 Fitbod 账户置于一个基于 stdio 的 MCP 服务器之后,因此任何 MCP 客户端都可以直接使用你的训练数据。它横跨十个后端服务,而非仅仅一个端点:

服务

包含内容

工具

nautilus

训练计划、健身房、器械、生成器配置、个人资料、训练历史

36

metros

身体成分时间序列、力量评分、连续打卡、百分位

11

pyserve

训练生成器,包括一个由 LLM 驱动的变体

4

coach

具有持久记忆的 AI 教练会话

5

gympulse

公共健身房目录和 Places 搜索

3

prism

AI 聊天后端

1

blimp · partnerio · billing

应用内消息、Strava、订阅状态

4

gate-keeper

登录和按服务签发令牌

认证层

最有用的部分是 pyserve。大多数集成都是在应用之外编写训练计划;而本服务器会直接调用生成器本身,返回包含动作选择、组数、次数、负重和休息时间的完整训练会话,然后根据你实际拥有的器械对结果进行过滤,并对任何你无法完成的动作请求替换。

亮点

  • 每个写入工具默认设置 dry_run=True,并返回它将发送的确切载荷,而不会改动账户。

  • 包含约 1,400 个动作的离线语料库意味着目录查询、健身房过滤和肌肉映射无需任何网络调用。

  • build_routine 会在写入之前根据你的健身房验证每一个动作,并在部分失败时删除该训练计划,从而不会留下半成品。

  • 分析功能(总吨位、各肌群训练量、估算 1RM、停滞不前的动作)位于纯函数中,不依赖网络,并针对固定测试数据进行了单元测试。

  • 令牌签发、401 时刷新、速率限制、分页以及临时挑战重试均在客户端内部处理。

安装

需要 Python 3.10 或更高版本。

git clone https://github.com/Muno459/mcp-fitbod
cd mcp-fitbod
pip install -e ".[dev]"

只需认证一次。刷新令牌的有效期约为一年,并且只有该令牌会被持久化保存。

FITBOD_EMAIL='you@example.com' FITBOD_PASSWORD='...' python -m fitbod.auth

从你自己的 Fitbod 安装中构建离线动作语料库。解压 APK,然后将构建器指向其 res/raw 目录。

python build_reference.py --apk-res /path/to/fitbod/res/raw

描述你的健身房,以便工具能够筛选出可执行的动作。

cp data/gym-profile.example.json data/gym-profile.json
$EDITOR data/gym-profile.json

验证,然后运行。

python -m pytest tests/ -q     # offline: parsing and analysis
python smoke_test.py           # live: every tool, writes are dry-run
python server.py

配置

通过 stdio 将服务器注册到任何 MCP 客户端:

{
  "mcpServers": {
    "fitbod": {
      "command": "python",
      "args": ["/absolute/path/to/mcp-fitbod/server.py"]
    }
  }
}

变量

用途

FITBOD_EMAIL

仅由 python -m fitbod.auth 使用,从不存储

FITBOD_PASSWORD

仅由 python -m fitbod.auth 使用,从不存储

FITBOD_REFRESH_TOKEN

直接提供刷新令牌,而不使用凭据文件

凭据保存在 .fitbod-credentials.json 中,仅所有者可读且已被 gitignore。该文件只包含刷新令牌,别无其他。你的密码永远不会写入磁盘,也永远不会被记录。要撤销访问权限,请更改你的密码。

data/gym-profile.json 将你拥有的器械映射到 Fitbod 的 78 种器械类型,包括你可用的确切哑铃和杠铃片增量,从而确保开出的负重是你实际能够组合出来的。从 data/gym-profile.example.json 开始,并使用 preview_inventory_mapping 检查你的名称能否正确解析。

工具

共 97 个工具,分布在十二个模块中。每个写入工具都接受 dry_run。

工具

描述

list_workouts

已记录的训练,最新的在前

get_workout

单个训练的完整详情,每一组都已展开

exercise_history

某个动作的每一组已记录数据,含估算 1RM

volume_by_muscle

每个肌群的有效组数和总吨位

stalled_lifts

最佳估算 1RM 未再提升的动作

training_summary

一次调用即可获得总量、各肌群训练量和停滞动作

workout_totals

通过服务器自身的聚合获取训练总次数

body_metrics

来自个人资料的身体指标

log_workout

将一次已完成的训练记录到历史中

update_logged_workout

编辑历史中已有的训练

估算 1RM 采用 Epley 公式。热身组不计入有效组数和总吨位。空窗口会返回一条说明性的 note,而不是一个光秃秃的零。

工具

描述

generate_workout

让 Fitbod 自己的引擎生成一次训练会话

replace_exercises

生成后,将指定的动作替换掉

workout_insights

关于已生成训练的自由文本提问

generator_reference

生成器的接口及其已知约束

有三个引擎可供选择:foundational_model、algo_direct_client 和 algo_llamabod。结果会根据你的健身房进行后置过滤,任何无法完成的动作都会通过 exercise_replacement 自动替换。

工具

描述

list_gyms

账户上的健身房及器械数量

get_gym_equipment

当前关联到某个健身房的器械

preview_inventory_mapping

你的库存如何映射到 Fitbod 器械 id

create_gym_from_inventory

根据你的库存创建一个配置好的健身房

add_gym_equipment · remove_gym_equipment

挂载或移除一种器械类型

set_available_weights

声明某一种类型存在哪些具体重量

apply_inventory_weights

应用已记录的哑铃和杠铃片增量

delete_gym

删除一个健身房

工具

描述

get_workout_config · update_workout_config

目标、分化、经验、每周天数、超级组、热身、时长

get_blocks · create_block

训练阶段及其重点动作

set_exercise_priority · list_exercise_priorities

每个动作的系数,用于影响选择偏向

工具

描述

build_routine

一次调用创建完整训练计划,支持回滚

list_routines · get_routine

读取已保存的模板

create_routine · update_routine · delete_routine

模板生命周期

add_set_to_routine

添加一个规定动作

create_superset

创建一个动作组容器

create_custom_exercise

定义 Fitbod 未建模的动作

工具

描述

body_composition

当前成分及各指标的完整历史

lean_mass_trend

随时间变化的瘦体重和体重,含变化量

muscle_strength · muscle_strength_detail

各肌肉相对于人群的评分

population_percentiles

某个动作在所有人中的排名百分位

training_streak · set_goal_progress

连续打卡、每周次数、训练量目标

list_metric_types · metric_details

指标目录及其数字 id

record_body_metric · delete_body_metric

写入和删除读数

体重、瘦体重、脂肪量、体脂率、BMI、BMR 以及七项围度均有完整时间序列可用,数据来源于 Apple Health 或 Health Connect。

动作目录:find_exercises exercise_detail search_exercises_live exercise_details_live list_equipment muscle_groups warm_start_lookup onboarding_one_rep_maxes seed_one_rep_max api_surface gym_profile

个人资料:get_profile update_profile add_injury list_injuries delete_injury rate_exercise list_exercise_ratings registered_devices app_config selected_cardio add_selected_cardio remove_selected_cardio selected_resistance_bands

教练与聊天:coach_ask coach_sessions coach_new_session coach_memories coach_session_stats chat

分析:exercise_analytics exercise_benchmarks workout_achievements

其他服务:service_health subscription_status list_blimps dismiss_blimp strava_connection list_public_gyms public_gym_equipment search_places

营养:nutrition_targets todays_targets recalculate_targets cut_progress

逃生舱:raw_get 和 metros_raw_get,两者均为只读,并带有路径 校验。

身份验证

分为三步,每个微服务都从一个长期有效的刷新令牌(refresh token)自行铸造自己的短期令牌:

POST gate-keeper.fitbod.me/users/login   {"user":{"email","password"}}
  -> 201, refresh JWT in the Authorization RESPONSE header, exp about 1 year

POST <service>.fitbod.me/access_token    {"refresh_token":"<raw jwt>"}
  -> 201 {"access_token": ...}, aud=<service>.prod.fitbod.me, about 24h

Authorization: Bearer <access_token>  ->  https://<service>.fitbod.me/...

客户端会将访问令牌缓存 23 小时,并在收到 401 时透明地重新铸造。注意各服务之间的不一致:nautilus 要求在请求体中包含 refresh_token,而 prism、blimp 和 metros 也接受将其放在请求头中。

需要形如浏览器的 User-Agent,因为已知的机器人代理(如 curl/*)会在请求到达源站之前就被边缘节点拒绝。

重要发现

这些是需要花费实际时间才能摸索出来的行为,记录下来以免重复踩坑。

两套序列化机制并存。 JSON:API 属性使用 snake_case,但内嵌文档会原样使用源属性名,除非有显式注解覆盖。在 individual_sets 内部,isWarmup 和 restTime 保持 camelCase,而 _id、_created_at 和 is_amrap 则带有覆盖。混淆这两套机制会静默丢失所有字段。

有些映射无法凭猜测得知。 workoutConfigId 序列化为 default_workout_config_id,circuitsEnabled 序列化为 supersets_enabled,而 algorithmCoefficient 序列化为 algorithm_coeffecient——这个拼写错误出现在线上数据中。

已记录组不使用资源 id。 它们通过 exercise_external_resource_id 引用动作,这是一个不同的编号。Leg Press 的 id=291,但 external_resource_id=218。

POST 和 PUT 对 id 的要求不一致。 POST workout_data 拒绝任何 id(data.attributes.id should be type integer_id),而 PUT workout_data/{id} 要求 data.id 与路径匹配。

关系(relationships)与属性(attributes)之别。 gym_id 和 equipment_id 可读但不可写。创建 gym_equipment 记录需要使用 JSON:API 的关系(relationships),而不是属性。

枚举值是固定的,且顺序很重要。

FitnessGoal          0 GENERAL_FITNESS  1 STRENGTH_TRAINING  2 MUSCLE_TONE
                     3 BODYBUILDING     4 POWERLIFTING       5 OLYMPICWEIGHTLIFTING
MuscleSplit          0 FRESH_MUSCLE_GROUPS  1 UPPER_LOWER  2 FULL_BODY  3 PPL
ExperienceLevel      0 BEGINNER  1 INTERMEDIATE  2 EXPERT
WorkoutVariability   1 MORE_CONSISTENCY  3 SUGGESTED  5 MORE_VARIABILITY
StrengthAggregate    push, pull, lower   (there is no upper and no core)
ExerciseRating       like, dislike, exclude   (lowercase; uppercase returns 500)

生成器的怪癖。 algo_versions 是必填项,但其中的每个字段都可以为 null。空的 user_equipment 或 muscle_usages_from_client 会返回 500。exercise_replacement 需要将训练回显为 current_workout,并且 exercise_ids_to_replace 中的每个 id 都必须出现在其中。生成器不会严格遵循 user_equipment,所以始终要做后置过滤。

突发请求会被质询。 带有 HTML 响应体的 403 是暂时性的,大约 10 到 30 秒内就会解除。客户端会重试,而不是将其作为认证错误抛出——尽管乍一看它很像认证错误。

时长单位是秒。 已记录训练中的 duration 不是分钟,这一点很容易被忽略,直到一次 65 分钟的训练显示为 3908。

已知限制

已针对订阅账户,并尝试了各种载荷形态进行确认:

端点

行为

POST set_breakdown_templates

所有形态都返回 403,而 GET 正常。无法指定每组的具体重量和次数。请改用 theoretical_max 来控制负荷。

POST circuit_templates

403,同样的模式。无法通过 API 创建超级组。

rpe 在 POST workout_data 上

任何值(包括 null)都会返回 400。可读,但永远不可写。

教练会话

无法删除(405),因此测试从不创建它们。

根本没有营养 API。营养工具会在本地存储目标,并根据实时身体成分数据推导出这些目标。

架构

server.py                thin entrypoint, registers tool modules
fitbod/
  client.py              auth chain, rate limiting, retry, pagination
  auth.py                python -m fitbod.auth
  schemas.py             dataclass parsers for both serialisation regimes
  analysis.py            volume, stalled lifts, 1RM. Pure, network free
  reference.py           offline corpus, dual id index, gym filtering
  tools/                 read, catalogue, gym, config, program, profile,
                         metrics, generate, services, coach, extras, nutrition
tests/                   offline tests over recorded fixtures
docs/
  API-MAP.md             145 endpoints, 365 request and response models
  SCHEMAS.md             field level schemas with exact wire names
build_reference.py       builds the offline corpus from an extracted APK
smoke_test.py            exercises all 97 tools live, writes dry-run by default

请求在客户端被限速为每秒 6 个,突发上限为 10 个。这是一个礼貌性预算,而非实测到的上限:50 个并发请求可持续达到每秒约 32 个,且没有出现任何 429,任何响应上也没有速率限制头。如果你需要更高吞吐量,还有余量。

动作语料库使用双索引作为键,因为已记录组和目录条目使用不同的 id 空间。reference.by_id() 和 reference.by_external_id() 正是为此而同时存在。

文档

文件

内容

docs/API-MAP.md

完整的接口面:12 个接口中共 145 个端点声明,以及 365 个经传递解析的请求和响应模型

docs/SCHEMAS.md

字段级模式,包含精确的线上名称、类型和必填标志

docs/GAPS.md

尚未解决的问题及其原因

动作目录

build_reference.py 会从解压后的 Fitbod APK 的 res/raw 目录构建 data/exercise-reference.json:大约 1,400 个带有文字说明的动作、78 种器械类型、肌群映射和器械重量表。这些内容归 Fitbod 所有,因此不在此分发。请从你自己的安装中构建。

法律声明

本项目使用未记录的 API,极有可能违反 Fitbod 的服务条款,尽管它只会访问你自己的账户,并且不规避付费。它的存在是为了与你自己的训练数据进行个人互操作。请仅在你自己的账户上使用,风险自负,且不要将其指向任何其他人的账户。

横幅中的六边形标志是一幅原创绘图,灵感来自 Fitbod 的视觉形象,并非其商标;本项目与 Fitbod 没有任何关联、背书或联系。

许可证

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to access and manage fitness programs, exercise catalog, workout resources, activity metrics, journaled plan edits, and change tracking through authenticated tools.
    2 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables conversational logging and retrieval of workouts, sets, weigh-ins, meals, goals, plans, and progress photos through MCP-capable AI clients, with authenticated per-user storage and export/query capabilities.
    ISC