fitness-tracker-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@fitness-tracker-mcpLog a 30-minute run and 150g protein for today"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
🏋️ Fitness Tracker — MCP Server
A fully offline Model Context Protocol (MCP) server that enables any MCP‑compatible AI client — such as Claude Code, Claude Desktop, or Cursor — to log workouts, track dietary macros, and retrieve daily health summaries, all backed by a local SQLite database with zero network dependency.
📖 Table of Contents
Related MCP server: Nutrition MCP
💡 Why This Project?
Large Language Models are great at conversation, but they can't natively persist user data across sessions. The Model Context Protocol bridges that gap by letting LLMs call external tools — turning the AI into a true assistant that can read, write, and query structured data on the user's behalf.
This project demonstrates a practical MCP integration: a fitness tracker that an AI assistant can operate hands‑free. Ask your AI "Log a 30‑minute run that burned 300 calories" and it will validate the data, store it in SQLite, and confirm — all without you ever opening a spreadsheet.
✨ Key Features
Feature | Description |
Workout Logging | Record exercise sessions with type, duration, and calories burned |
Macro Tracking | Log daily protein, carbs, and fat intake per meal or per day |
Daily Summaries | Aggregated view of workouts + nutrition with calorie calculations |
Fully Offline | Stdio transport — no network calls, no API keys, no cloud dependency |
Strict Validation | Pydantic v2 schemas catch malformed LLM outputs before they reach the DB |
SQL Injection Safe | Parameterised queries throughout — user input never touches raw SQL |
Comprehensive Tests | 22 Pytest cases covering schema validation, DB logic, and edge cases |
🧱 Technology Stack
Layer | Technology | Purpose |
MCP Framework | Exposes Python functions as MCP tools over stdio | |
Database | SQLite 3 | Lightweight, zero‑config local persistence |
Validation | Pydantic v2 | Schema enforcement and type coercion for LLM inputs |
Testing | Pytest | Isolated, per‑test in‑memory databases |
Language | Python 3.10+ | Core runtime |
🏗️ Architecture Overview
The system follows a layered architecture with clear separation of concerns:
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:#000Layer Responsibilities
Layer | Component | Responsibility |
Client | Claude Code / Desktop | Sends natural language → MCP tool calls |
Transport | stdio (JSON-RPC) | Serialises tool calls over stdin/stdout — no HTTP, no ports |
Router | FastMCP | Matches incoming tool names to Python handler functions |
Validation | Pydantic Schemas | Parses & validates every input field before DB access |
Business Logic | Core Functions | Executes inserts, aggregations, and calorie calculations |
Storage | SQLite via | Persists data in a single |
🔄 Data Flow
A step‑by‑step trace of what happens when a user says "Log a 30‑minute run":
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🗃️ Database Schema
The SQLite database (fitness_tracker.db) is auto‑created on first run and contains two tables:
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)"
}Calorie Calculation
The daily summary computes estimated calories consumed from macros using standard Atwater factors:
$$\text{Calories} = (\text{Protein} \times 4) + (\text{Carbs} \times 4) + (\text{Fat} \times 9) ;\text{kcal}$$
📂 Project Structure
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 fileFile Breakdown
File | Lines | Description |
| ~322 | Complete MCP server: DB init, Pydantic models, CRUD operations, FastMCP tool definitions, and stdio entrypoint |
| ~265 | 22 tests in 6 classes — schema validation (valid + invalid inputs), DB inserts, daily aggregation, date isolation, and SQL injection safety |
| 3 |
|
🚀 Getting Started
Prerequisites
Python 3.10+ installed
pip package manager
1. Clone the Repository
git clone https://github.com/MayankKapgate/fitness-tracker-mcp.git
cd MCP_Project2. Create & Activate a Virtual Environment (Recommended)
# Windows
python -m venv myvenv
myvenv\Scripts\activate
# macOS / Linux
python3 -m venv myvenv
source myvenv/bin/activate3. Install Dependencies
pip install -r requirements.txt4. Run the Test Suite
pytest test_server.py -vYou should see 22 tests pass ✅
5. Start the Server (Standalone)
python server.pyNote: The server uses stdio transport — it reads JSON‑RPC from
stdinand writes tostdout. You won't see a shell prompt; this is by design for MCP client consumption.
🔌 Connecting to MCP Clients
Claude Code
Register the server once from your terminal:
claude mcp add fitness-tracker --transport stdio -- python server.pyTip: If Claude Code isn't launched from the project directory, use the full path:
claude mcp add fitness-tracker --transport stdio -- python "C:\Users\Mayan\OneDrive\Documents\MCP_Project\server.py"
Claude Desktop
Add the following to your claude_desktop_config.json:
{
"mcpServers": {
"fitness-tracker": {
"command": "python",
"args": ["C:\\Users\\Mayan\\OneDrive\\Documents\\MCP_Project\\server.py"],
"transport": "stdio"
}
}
}Other MCP Clients
Any MCP‑compatible client can connect using:
Transport:
stdioCommand:
python server.py(or full path toserver.py)
🛠️ Tool Reference (API)
The server exposes 3 MCP tools:
1. log_workout
Log a single workout session.
Parameter | Type | Constraints | Example |
|
| ISO 8601 ( |
|
|
| 1–100 characters |
|
|
| > 0 (minutes) |
|
|
| ≥ 0 (kcal) |
|
Returns:
{
"status": "success",
"workout": {
"id": 1,
"date": "2026-08-04",
"type": "running",
"duration": 30.0,
"calories": 300.0
}
}2. log_macros
Log dietary macronutrients for a meal or full day.
Parameter | Type | Constraints | Example |
|
| ISO 8601 ( |
|
|
| ≥ 0 (grams) |
|
|
| ≥ 0 (grams) |
|
|
| ≥ 0 (grams) |
|
Returns:
{
"status": "success",
"macros": {
"id": 1,
"date": "2026-08-04",
"protein": 150.0,
"carbs": 200.0,
"fat": 60.0
}
}3. get_daily_summary
Retrieve a combined workout and nutrition summary for a given date.
Parameter | Type | Constraints | Example |
|
| ISO 8601 ( |
|
Returns:
{
"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
}
}💬 Example Usage
Once connected, simply chat with your AI assistant naturally:
You Say | Tool Called | What Happens |
"I did a 30‑minute run and burned 300 calories" |
| Stores the workout for today's date |
"Log my lunch: 40g protein, 60g carbs, 15g fat" |
| Records one macro entry |
"How did I do today?" |
| Returns aggregated totals for the current date |
"What was my workout on August 4th?" |
| Fetches data for |
🧪 Testing
The test suite (test_server.py) contains 22 tests across 6 test classes, using isolated temporary SQLite databases per test:
Test Class | Tests | What It Covers |
| 10 | Valid workout, bad dates, negative/zero duration, negative calories, empty/too-long type, missing fields, wrong types |
| 6 | Valid macros, invalid date, negative protein/carbs/fat, missing fields |
| 2 | Valid request, garbage date |
| 3 | Insert & retrieve, multiple inserts, SQL injection safety |
| 2 | Insert & retrieve, SQL injection via date field |
| 3 | Empty day, populated day with aggregation, cross-date isolation |
Running Tests
# 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🔒 Security & Safety
Concern | Mitigation |
SQL Injection | All database queries use parameterised |
Malformed LLM Output | Every tool input passes through a Pydantic v2 schema with strict field validators before reaching the database |
Date Validation | Custom |
Type Coercion | Pydantic's strict mode catches truly incompatible types (e.g., |
Network Exposure | stdio transport — zero network traffic, no open ports, no API keys required |
Data Privacy | All data stays in a local |
📝 License
MIT — use freely.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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 gradedqualityBmaintenanceA 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.20MIT
- FlicenseNot gradedqualityBmaintenanceLocal-first nutrition tracker MCP server for Hermes, enabling food, alias, recipe, and meal log management with SQLite persistence.
- FlicenseAqualityBmaintenancePersonal 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
Related MCP Connectors
MCP server for Withings health data — sleep, activity, heart, and body metrics.
GibsonAI MCP server: manage your databases with natural language
MCP server for Argo RPG Platform — connects AI assistants to campaign data via OAuth2
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/MayankKapgate/fitness-tracker-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server