fitness-tracker-mcp
ποΈ Fitness Tracker β MCP Server
μμ ν μ€νλΌμΈμΌλ‘ λμνλ Model Context Protocol (MCP) μλ²λ‘, Claude Code, Claude Desktop, Cursor λ± MCP νΈν AI ν΄λΌμ΄μΈνΈκ° μ΄λ κΈ°λ‘, μλ¨ λ§€ν¬λ‘ μΆμ , μΌμΌ κ±΄κ° μμ½ μ‘°νλ₯Ό ν μ μκ² ν΄μ€λλ€. λͺ¨λ λ°μ΄ν°λ λ‘컬 SQLite λ°μ΄ν°λ² μ΄μ€μ μ μ₯λλ©° λ€νΈμν¬ μμ‘΄μ±μ΄ μ ν μμ΅λλ€.
π λͺ©μ°¨
Related MCP server: Nutrition MCP
π‘ μ μ΄ νλ‘μ νΈμΈκ°?
λκ·λͺ¨ μΈμ΄ λͺ¨λΈμ λνμλ λ°μ΄λμ§λ§, μΈμ μ λμ΄ μ¬μ©μ λ°μ΄ν°λ₯Ό κΈ°λ³Έμ μΌλ‘ μμνν μλ μμ΅λλ€. Model Context Protocolμ LLMμ΄ μΈλΆ λꡬλ₯Ό νΈμΆν μ μκ² ν¨μΌλ‘μ¨ μ΄ κ²©μ°¨λ₯Ό λ©μλλ€. μ¦, AIκ° μ¬μ©μλ₯Ό λμ ν΄ κ΅¬μ‘°νλ λ°μ΄ν°λ₯Ό μ½κ³ , μ°κ³ , μ‘°νν μ μλ μ§μ ν μ΄μμ€ν΄νΈκ° λλ κ²μ λλ€.
μ΄ νλ‘μ νΈλ μ€μ©μ μΈ MCP ν΅ν©μ 보μ¬μ€λλ€. AI μ΄μμ€ν΄νΈκ° μ§μ μ‘°μν μ μλ νΌνΈλμ€ νΈλ컀μ λλ€. AIμκ² *"300μΉΌλ‘리λ₯Ό μλͺ¨ν 30λΆ λ¬λμ κΈ°λ‘ν΄μ€"*λΌκ³ λ§νλ©΄, AIκ° λ°μ΄ν°λ₯Ό κ²μ¦νκ³ SQLiteμ μ μ₯ν λ€ νμΈν΄ μ€λλ€. μ€νλ λμνΈλ₯Ό μ΄μ΄λ³Ό νμκ° μ ν μμ΅λλ€.
β¨ μ£Όμ κΈ°λ₯
κΈ°λ₯ | μ€λͺ |
μ΄λ κΈ°λ‘ | μ΄λ μ ν, μκ°, μλͺ¨ μΉΌλ‘리λ₯Ό ν¬ν¨ν μ΄λ μΈμ κΈ°λ‘ |
λ§€ν¬λ‘ μΆμ | μμ¬λ³ λλ ν루 λ¨μλ‘ λ¨λ°±μ§, νμνλ¬Ό, μ§λ°© μμ·¨λ κΈ°λ‘ |
μΌμΌ μμ½ | μΉΌλ‘리 κ³μ°μ ν¬ν¨ν μ΄λ + μμ μ§κ³ 보기 |
μμ μ€νλΌμΈ | 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)λ 첫 μ€ν μ μλμΌλ‘ μμ±λλ©° λ κ°μ ν
μ΄λΈμ ν¬ν¨ν©λλ€:
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
μμ¬ λλ ν루 μ 체μ μμ΄ λ§€ν¬λ‘μμμλ₯Ό κΈ°λ‘ν©λλ€.
λ§€κ°λ³μ | νμ | μ μ½ μ‘°κ±΄ | μμ |
|
| 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" |
| λ§€ν¬λ‘ νλͺ© νλ κΈ°λ‘ |
"μ€λ λλ μ΄λ μ΄?" |
| νμ¬ λ μ§μ μ§κ³ ν©κ³ λ°ν |
"8μ 4μΌ μ΄λμ λμμ§?" |
|
|
π§ͺ ν μ€νΈ
ν
μ€νΈ μ€μνΈ(test_server.py)λ 6κ°μ ν
μ€νΈ ν΄λμ€μ κ±ΈμΉ 22κ°μ ν
μ€νΈλ₯Ό ν¬ν¨νλ©°, ν
μ€νΈλ§λ€ 격리λ μμ SQLite λ°μ΄ν°λ² μ΄μ€λ₯Ό μ¬μ©ν©λλ€:
ν μ€νΈ ν΄λμ€ | ν μ€νΈ μ | λ€λ£¨λ λ΄μ© |
| 10 | μ ν¨ν μ΄λ, μλͺ»λ λ μ§, μμ/0 μ§μ μκ°, μμ μΉΌλ‘리, λΉ/λ무 κΈ΄ μ ν, λλ½λ νλ, μλͺ»λ νμ |
| 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 μΈμ μ | λͺ¨λ λ°μ΄ν°λ² μ΄μ€ 쿼리λ λ§€κ°λ³μνλ |
μλͺ»λ LLM μΆλ ₯ | λͺ¨λ λꡬ μ λ ₯μ λ°μ΄ν°λ² μ΄μ€μ λλ¬νκΈ° μ μ μ격ν νλ κ²μ¦κΈ°κ° μλ Pydantic v2 μ€ν€λ§λ₯Ό ν΅κ³Ό |
λ μ§ κ²μ¦ | μ¬μ©μ μ μ |
νμ λ³ν | Pydanticμ μ격 λͺ¨λκ° μ€μ λ‘ νΈνλμ§ μλ νμ
(μ: |
λ€νΈμν¬ λ ΈμΆ | stdio μ μ‘ β λ€νΈμν¬ νΈλν½ 0, μ΄λ¦° ν¬νΈ μμ, API ν€ λΆνμ |
λ°μ΄ν° νλΌμ΄λ²μ | λͺ¨λ λ°μ΄ν°λ μ¬μ©μ λ¨Έμ μ λ‘컬 |
π λΌμ΄μ μ€
MIT β μμ λ‘κ² μ¬μ©νμΈμ.
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-