fitness-tracker-mcp
🏋️ Fitness Tracker — MCP Server
完全オフラインの Model Context Protocol (MCP) サーバーで、Claude Code、Claude Desktop、Cursor などの MCP 互換 AI クライアントが、ワークアウトの記録、食事マクロの追跡、日次ヘルスサマリーの取得 を、ネットワーク依存ゼロのローカル SQLite データベースを基盤として実現できます。
📖 目次
Related MCP server: Nutrition MCP
💡 このプロジェクトの目的は?
大規模言語モデル(LLM)は会話には優れていますが、セッションをまたいでユーザーデータを永続化することは本来できません。Model Context Protocol は、LLM が外部ツールを呼び出せるようにすることでこのギャップを埋め、ユーザーに代わって構造化データの読み取り、書き込み、クエリを実行できる真のアシスタントへと AI を変えます。
このプロジェクトは、実用的な MCP 統合のデモです。AI アシスタントがハンズフリーで操作できるフィットネストラッカーです。AI に 「30分のランニングで300カロリーを消費した」と記録して と伝えると、データを検証し、SQLite に保存し、確認まで行います。スプレッドシートを開く必要は一切ありません。
✨ 主な機能
機能 | 説明 |
ワークアウトの記録 | 種目、時間、消費カロリーを含む運動セッションを記録 |
マクロの追跡 | 1食ごとまたは1日ごとのタンパク質、炭水化物、脂質の摂取量を記録 |
日次サマリー | カロリー計算を含むワークアウトと栄養の集計ビュー |
完全オフライン | stdio トランスポート — ネットワーク呼び出しなし、API キー不要、クラウド依存なし |
厳格な検証 | Pydantic v2 スキーマが不正な LLM 出力を DB に到達する前に検出 |
SQL インジェクション対策 | すべてのクエリでパラメータ化を採用 — ユーザー入力が生の SQL に触れることはありません |
包括的なテスト | スキーマ検証、DB ロジック、エッジケースをカバーする 22 件の Pytest テスト |
🧱 技術スタック
レイヤー | 技術 | 目的 |
MCP フレームワーク | Python 関数を stdio 経由で 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レイヤーの責務
レイヤー | コンポーネント | 責務 |
クライアント | Claude Code / Desktop | 自然言語を MCP ツール呼び出しに変換して送信 |
トランスポート | stdio (JSON-RPC) | stdin/stdout 経由でツール呼び出しをシリアライズ — HTTP なし、ポートなし |
ルーター | FastMCP | 受信したツール名を Python ハンドラ関数にマッチング |
検証 | Pydantic スキーマ | 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)は初回実行時に自動生成され、2つのテーブルを含みます:
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ファイル内訳
ファイル | 行数 | 説明 |
| ~322 | 完全な MCP サーバー:DB 初期化、Pydantic モデル、CRUD 操作、FastMCP ツール定義、stdio エントリポイント |
| ~265 | 6 クラスにわたる 22 テスト — スキーマ検証(有効・無効な入力)、DB 挿入、日次集計、日付の分離、SQL インジェクション安全性 |
| 3 |
|
🚀 はじめに
前提条件
Python 3.10+ がインストールされていること
pip パッケージマネージャー
1. リポジトリのクローン
git clone https://github.com/MayankKapgate/fitness-tracker-mcp.git
cd MCP_Project2. 仮想環境の作成と有効化(推奨)
# Windows
python -m venv myvenv
myvenv\Scripts\activate
# macOS / Linux
python3 -m venv myvenv
source myvenv/bin/activate3. 依存関係のインストール
pip install -r requirements.txt4. テストスイートの実行
pytest test_server.py -v22 件のテストがパスする はずです ✅
5. サーバーの起動(スタンドアロン)
python server.py注記: サーバーは stdio トランスポート を使用します —
stdinから JSON‑RPC を読み取り、stdoutに書き込みます。シェルのプロンプトは表示されません。これは 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
単一のワークアウトセッションを記録します。
パラメータ | 型 | 制約 | 例 |
|
| ISO 8601 ( |
|
|
| 1〜100 文字 |
|
|
| > 0(分) |
|
|
| ≥ 0(kcal) |
|
戻り値:
{
"status": "success",
"workout": {
"id": 1,
"date": "2026-08-04",
"type": "running",
"duration": 30.0,
"calories": 300.0
}
}2. log_macros
1食または1日分のマクロ栄養素を記録します。
パラメータ | 型 | 制約 | 例 |
|
| ISO 8601 ( |
|
|
| ≥ 0(グラム) |
|
|
| ≥ 0(グラム) |
|
|
| ≥ 0(グラム) |
|
戻り値:
{
"status": "success",
"macros": {
"id": 1,
"date": "2026-08-04",
"protein": 150.0,
"carbs": 200.0,
"fat": 60.0
}
}3. get_daily_summary
指定された日付のワークアウトと栄養を組み合わせたサマリーを取得します。
パラメータ | 型 | 制約 | 例 |
|
| ISO 8601 ( |
|
戻り値:
{
"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 アシスタントと自然にチャットするだけです:
あなたの言葉 | 呼び出されるツール | 動作 |
「30分のランニングをして300カロリーを消費した」 |
| 今日の日付でワークアウトを保存 |
「昼食を記録して:タンパク質40g、炭水化物60g、脂質15g」 |
| マクロエントリを1件記録 |
「今日はどうだった?」 |
| 現在の日付の集計合計を返す |
「8月4日のワークアウトは何だった?」 |
|
|
🧪 テスト
テストスイート(test_server.py)には 6 つのテストクラス にわたる 22 件のテスト が含まれており、テストごとに分離された一時 SQLite データベースを使用します:
テストクラス | テスト数 | カバー内容 |
| 10 | 有効なワークアウト、不正な日付、負/ゼロの時間、負のカロリー、空/長すぎる種目、フィールド欠落、誤った型 |
| 6 | 有効なマクロ、不正な日付、負のタンパク質/炭水化物/脂質、フィールド欠落 |
| 2 | 有効なリクエスト、不正な日付 |
| 3 | 挿入と取得、複数挿入、SQL インジェクション安全性 |
| 2 | 挿入と取得、日付フィールド経由の SQL インジェクション |
| 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🔒 セキュリティと安全性
懸念事項 | 対策 |
SQL インジェクション | すべてのデータベースクエリはパラメータ化された |
This server cannot be deployed
Maintenance
Related MCP Connectors
Adaptive running coach MCP server — training data, plans, and recovery for AI assistants.
MCP server for Withings health data — sleep, activity, heart, and body metrics.
MCP server exposing supplements database used by iNutriPlan.com
Talk to your own gym log. Reps is a free workout tracker for iPhone and Android; connect it to Claude, ChatGPT or any MCP client and ask about your workout history, personal records, exercise progression, weekly summaries, routines and training plan. The assistant can also save a new routine, edit one, save a whole plan, add custom exercises and exercise notes, always after you confirm in the chat. It cannot log a workout or delete your history. Requires a free Reps account created in the app; you sign in with a one-time email code.
Related MCP Servers
- FlicenseBqualityDmaintenanceA 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-
- AlicenseNot gradedqualityDmaintenanceA 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 npmMIT
- FlicenseNot gradedqualityDmaintenanceLocal-first nutrition tracker MCP server for Hermes, enabling food, alias, recipe, and meal log management with SQLite persistence.-
- FlicenseAqualityDmaintenancePersonal 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-