Skip to main content
Glama
MayankKapgate

fitness-tracker-mcp

🏋️ Fitness Tracker — MCP Server

一个完全离线的 Model Context Protocol (MCP) 服务器,使任何兼容 MCP 的 AI 客户端(如 Claude Code、Claude Desktop 或 Cursor)都能记录锻炼、追踪饮食宏量营养素,并获取每日健康摘要,全部由本地 SQLite 数据库支持,零网络依赖。


📖 目录


Related MCP server: Nutrition MCP

💡 为什么选择这个项目?

大型语言模型擅长对话,但它们无法原生地跨会话持久化用户数据。Model Context Protocol 通过让 LLM 调用外部工具来弥合这一差距——将 AI 转变为真正能代表用户读取、写入和查询结构化数据的助手。

本项目展示了一个实用的 MCP 集成:一个 AI 助手可以免手动操作的健身追踪器。对你的 AI 说 "记录一次燃烧了 300 卡路里的 30 分钟跑步",它就会验证数据、将其存入 SQLite,并确认——全程无需你打开电子表格。


✨ 主要特性

Feature

Description

锻炼记录

记录运动会话的类型、时长和消耗的卡路里

宏量营养素追踪

按餐或按天记录每日蛋白质、碳水化合物和脂肪摄入量

每日摘要

锻炼 + 营养的聚合视图,包含卡路里计算

完全离线

stdio 传输——无网络调用、无 API 密钥、无云依赖

严格验证

Pydantic v2 模式在数据到达数据库之前捕获格式错误的 LLM 输出

SQL 注入安全

全程使用参数化查询——用户输入永远不会触及原始 SQL

全面测试

22 个 Pytest 用例,涵盖模式验证、数据库逻辑和边界情况


🧱 技术栈

Layer

Technology

Purpose

MCP 框架

FastMCP

通过 stdio 将 Python 函数暴露为 MCP 工具

数据库

SQLite 3

轻量、零配置的本地持久化

验证

Pydantic v2

对 LLM 输入进行模式强制和类型转换

测试

Pytest

每个测试使用隔离的内存数据库

语言

Python 3.10+

核心运行时


🏗️ 架构概览

系统采用分层架构,关注点清晰分离:

graph TB
    subgraph Client Layer
        A["🤖 MCP Client<br/>(Claude Code / Claude Desktop / Cursor)"]
    end

    subgraph Transport Layer
        B["📡 stdio<br/>(JSON-RPC over stdin/stdout)"]
    end

    subgraph MCP Server ["MCP Server (server.py)"]
        direction TB
        C["🔧 FastMCP Tool Router<br/>Routes tool calls to handlers"]
        D["📋 Pydantic Schemas<br/>WorkoutInput · MacrosInput · DailySummaryRequest"]
        E["⚙️ Core Business Logic<br/>insert_workout · insert_macros · fetch_daily_summary"]
        F["🗄️ Database Layer<br/>get_connection · init_db"]
    end

    subgraph Storage
        G[("💾 SQLite<br/>fitness_tracker.db")]
    end

    A <-->|"JSON-RPC"| B
    B <-->|"Tool calls & responses"| C
    C --> D
    D -->|"Validated data"| E
    E <--> F
    F <--> G

    style A fill:#4A90D9,stroke:#2C5F8A,color:#fff
    style B fill:#F5A623,stroke:#C77E1A,color:#fff
    style C fill:#7B68EE,stroke:#5A4DB2,color:#fff
    style D fill:#50C878,stroke:#3A9458,color:#fff
    style E fill:#FF6B6B,stroke:#CC5555,color:#fff
    style F fill:#DDA0DD,stroke:#AA70AA,color:#fff
    style G fill:#87CEEB,stroke:#5F9EAF,color:#000

各层职责

Layer

Component

Responsibility

客户端

Claude Code / Desktop

将自然语言 → MCP 工具调用

传输

stdio (JSON-RPC)

通过 stdin/stdout 序列化工具调用——无 HTTP、无端口

路由器

FastMCP

将传入的工具名称匹配到 Python 处理函数

验证

Pydantic 模式

在访问数据库之前解析并验证每个输入字段

业务逻辑

核心函数

执行插入、聚合和卡路里计算

存储

通过 sqlite3 的 SQLite

将数据持久化到单个 fitness_tracker.db 文件中


🔄 数据流

当用户说 "记录一次 30 分钟的跑步" 时,逐步追踪会发生什么:

sequenceDiagram
    participant User
    participant Client as MCP Client (Claude)
    participant Transport as stdio (JSON-RPC)
    participant Router as FastMCP Router
    participant Schema as Pydantic Validator
    participant Logic as Business Logic
    participant DB as SQLite DB

    User->>Client: "Log a 30-minute run that burned 300 calories"
    Client->>Transport: tool_call: log_workout(date, type, duration, calories)
    Transport->>Router: Deserialize JSON-RPC request
    Router->>Schema: WorkoutInput(date, type, duration, calories)

    alt Validation Fails
        Schema-->>Router: ❌ ValidationError (clear message)
        Router-->>Transport: Error response
        Transport-->>Client: Display error to user
    end

    Schema-->>Router: ✅ Validated WorkoutInput object
    Router->>Logic: insert_workout(validated_data)
    Logic->>DB: INSERT INTO workouts (date, type, duration, calories) VALUES (?, ?, ?, ?)
    DB-->>Logic: Row ID
    Logic-->>Router: {status: success, workout: {...}}
    Router-->>Transport: JSON-RPC response
    Transport-->>Client: "Logged: 30 min running — 300 kcal burned ✅"
    Client-->>User: Confirmation message

🗃️ 数据库模式

SQLite 数据库(fitness_tracker.db)在首次运行时自动创建,包含两个表:

erDiagram
    WORKOUTS {
        INTEGER id PK "Auto-increment"
        TEXT date "YYYY-MM-DD (NOT NULL)"
        TEXT type "e.g. running, cycling (NOT NULL)"
        REAL duration "Minutes, > 0 (NOT NULL)"
        REAL calories "kcal burned, >= 0 (NOT NULL)"
    }

    MACROS {
        INTEGER id PK "Auto-increment"
        TEXT date "YYYY-MM-DD (NOT NULL)"
        REAL protein "Grams, >= 0 (NOT NULL)"
        REAL carbs "Grams, >= 0 (NOT NULL)"
        REAL fat "Grams, >= 0 (NOT NULL)"
    }

卡路里计算

每日摘要使用标准 Atwater 系数从宏量营养素计算估计消耗的卡路里:

$$\text{Calories} = (\text{Protein} \times 4) + (\text{Carbs} \times 4) + (\text{Fat} \times 9) ;\text{kcal}$$


📂 项目结构

MCP_Project/
├── server.py              # MCP server — tools, schemas, DB helpers, entrypoint
├── test_server.py         # Pytest suite (22 tests across 6 test classes)
├── requirements.txt       # Python dependencies (fastmcp, pydantic, pytest)
├── fitness_tracker.db     # SQLite database (auto-created on first run)
├── .gitignore             # Ignores venv, __pycache__, .env
├── .env                   # Environment variables (git-ignored)
└── README.md              # This file

文件说明

File

Lines

Description

server.py

~322

完整的 MCP 服务器:数据库初始化、Pydantic 模型、CRUD 操作、FastMCP 工具定义和 stdio 入口点

test_server.py

~265

6 个类中的 22 个测试——模式验证(有效和无效输入)、数据库插入、每日聚合、日期隔离和 SQL 注入安全

requirements.txt

3

fastmcp、pydantic、pytest


🚀 快速开始

前提条件

  • 已安装 Python 3.10+

  • pip 包管理器

1. 克隆仓库

git clone https://github.com/MayankKapgate/fitness-tracker-mcp.git
cd MCP_Project

2. 创建并激活虚拟环境(推荐)

# Windows
python -m venv myvenv
myvenv\Scripts\activate

# macOS / Linux
python3 -m venv myvenv
source myvenv/bin/activate

3. 安装依赖

pip install -r requirements.txt

4. 运行测试套件

pytest test_server.py -v

你应该会看到 22 个测试通过 ✅

5. 启动服务器(独立运行)

python server.py

注意: 服务器使用 stdio 传输——它从 stdin 读取 JSON‑RPC 并写入 stdout。你不会看到 shell 提示符;这是有意为之,供 MCP 客户端使用。


🔌 连接 MCP 客户端

Claude Code

在终端中注册服务器一次:

claude mcp add fitness-tracker --transport stdio -- python server.py

提示: 如果 Claude Code 不是从项目目录启动的,请使用完整路径:

claude mcp add fitness-tracker --transport stdio -- python "C:\Users\Mayan\OneDrive\Documents\MCP_Project\server.py"

Claude Desktop

将以下内容添加到你的 claude_desktop_config.json:

{
  "mcpServers": {
    "fitness-tracker": {
      "command": "python",
      "args": ["C:\\Users\\Mayan\\OneDrive\\Documents\\MCP_Project\\server.py"],
      "transport": "stdio"
    }
  }
}

其他 MCP 客户端

任何兼容 MCP 的客户端都可以使用以下方式连接:

  • 传输: stdio

  • 命令: python server.py(或 server.py 的完整路径)


🛠️ 工具参考(API)

服务器暴露 3 个 MCP 工具:

1. log_workout

记录一次单独的锻炼会话。

Parameter

Type

Constraints

Example

date

string

ISO 8601 (YYYY-MM-DD)

"2026-08-04"

type

string

1–100 个字符

"running"

duration

float

> 0(分钟)

30.0

calories

float

≥ 0(千卡)

300.0

返回:

{
  "status": "success",
  "workout": {
    "id": 1,
    "date": "2026-08-04",
    "type": "running",
    "duration": 30.0,
    "calories": 300.0
  }
}

2. log_macros

记录一餐或一整天的饮食宏量营养素。

Parameter

Type

Constraints

Example

date

string

ISO 8601 (YYYY-MM-DD)

"2026-08-04"

protein

float

≥ 0(克)

150.0

carbs

float

≥ 0(克)

200.0

fat

float

≥ 0(克)

60.0

返回:

{
  "status": "success",
  "macros": {
    "id": 1,
    "date": "2026-08-04",
    "protein": 150.0,
    "carbs": 200.0,
    "fat": 60.0
  }
}

3. get_daily_summary

检索指定日期的锻炼和营养综合摘要。

Parameter

Type

Constraints

Example

date

string

ISO 8601 (YYYY-MM-DD)

"2026-08-04"

返回:

{
  "date": "2026-08-04",
  "workouts": {
    "count": 2,
    "entries": [
      {"id": 1, "date": "2026-08-04", "type": "running", "duration": 30.0, "calories": 300.0},
      {"id": 2, "date": "2026-08-04", "type": "weights", "duration": 45.0, "calories": 250.0}
    ],
    "total_duration_min": 75.0,
    "total_calories_burned": 550.0
  },
  "macros": {
    "count": 1,
    "entries": [
      {"id": 1, "date": "2026-08-04", "protein": 150.0, "carbs": 200.0, "fat": 60.0}
    ],
    "total_protein_g": 150.0,
    "total_carbs_g": 200.0,
    "total_fat_g": 60.0,
    "total_calories_consumed": 1940.0
  }
}

💬 使用示例

连接后,只需自然地与你的 AI 助手聊天:

You Say

Tool Called

What Happens

"我跑了 30 分钟,消耗了 300 卡路里"

log_workout

存储今天的锻炼记录

"记录我的午餐:40 克蛋白质、60 克碳水化合物、15 克脂肪"

log_macros

记录一条宏量营养素条目

"我今天表现如何?"

get_daily_summary

返回当前日期的聚合总计

"我 8 月 4 日的锻炼是什么?"

get_daily_summary

获取 2026-08-04 的数据


🧪 测试

测试套件(test_server.py)包含 22 个测试,分布在 6 个测试类中,每个测试使用隔离的临时 SQLite 数据库:

Test Class

Tests

What It Covers

TestWorkoutSchema

10

有效锻炼、错误日期、负/零时长、负卡路里、空/过长类型、缺失字段、错误类型

TestMacrosSchema

6

有效宏量营养素、无效日期、负蛋白质/碳水化合物/脂肪、缺失字段

TestDailySummarySchema

2

有效请求、垃圾日期

TestWorkoutDB

3

插入与检索、多次插入、SQL 注入安全

TestMacrosDB

2

插入与检索、通过日期字段进行 SQL 注入

TestDailySummary

3

空日、有数据的日子的聚合、跨日期隔离

运行测试

# Run all tests with verbose output
pytest test_server.py -v

# Run a specific test class
pytest test_server.py::TestWorkoutSchema -v

# Run with coverage (requires pytest-cov)
pip install pytest-cov
pytest test_server.py --cov=server --cov-report=term-missing

🔒 安全与保障

Concern

Mitigation

SQL 注入

所有数据库查询都使用参数化的 ? 占位符——用户输入永远不会被插入到 SQL 字符串中

格式错误的 LLM 输出

每个工具输入在到达数据库之前都会通过带有严格字段验证器的 Pydantic v2 模式

日期验证

自定义 @field_validator 确保符合 ISO 8601;像 "yesterday" 或 "'; DROP TABLE" 这样的垃圾字符串会被拒绝

类型转换

Pydantic 的严格模式会捕获真正不兼容的类型(例如,float 字段的 "slow")

网络暴露

stdio 传输——零网络流量、无开放端口、无需 API 密钥

数据隐私

所有数据都保存在你机器上的本地 fitness_tracker.db 文件中——没有任何数据离开你的系统


📝 许可证

MIT——自由使用。

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    A personal fitness tracking server that enables logging and querying workouts, nutrition, and body metrics through a local SQLite database. Integrates with OpenNutrition MCP for food logging and supports exercise history tracking for workout progression.
    17
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A filesystem-based MCP server that turns any MCP-capable AI agent into a conversational calorie and protein tracker with natural-language estimates, confidence-aware logging, daily/weekly progress, food-history search, and export, working offline with local fallback data.
    37 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Local-first nutrition tracker MCP server for Hermes, enabling food, alias, recipe, and meal log management with SQLite persistence.
    -
  • F
    license
    A
    quality
    D
    maintenance
    Personal workout coach MCP server that logs exercises in natural language, tracks progress with SQLite, and provides coaching signals like estimated 1RM and volume trends.
    6
    -