Tracking MCP
Generic MCP server for tracking any entity type with schema-less JSON Hybrid storage.
Track body weight, daily scorecards, fitness sessions, books, or any custom entity without defining rigid schemas. Auto-discovery, self-documenting, and SQL-queryable.
Features
- Schema-less Design: Track any entity type (weight, scorecard, fitness, books, custom) without ALTER TABLE
- Auto-Discovery: Entity types automatically registered on first use
- Self-Documenting: MCP Resources expose schema examples and usage guides
- SQL-Queryable: Use
json_extract()for advanced analytics - Local-First: Privacy-friendly, zero external dependencies
- Hybrid Storage: SQLite with JSON columns for flexibility + performance
- CRUD Operations: Insert, update, query, delete via MCP Tools
- Built-in Prompts: Pre-configured templates for common tracking scenarios
Installation
From PyPI (when published)
pip install tracking-mcp
From Source
git clone https://github.com/mariomosca/tracking-mcp.git
cd tracking-mcp
pip install -e .
Initialize Database
# Database will be auto-created in data/tracking.db
# Or manually initialize:
cd data
sqlite3 tracking.db < schema.sql
Quick Start
Claude Desktop Configuration
Add to your Claude Desktop MCP settings (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"tracking": {
"command": "tracking-mcp",
"env": {
"DB_PATH": "/path/to/your/data/tracking.db"
}
}
}
}
Basic Usage
From Claude Desktop, you can now:
Track my weight: 72.5kg today
Show me my weight trend for the last 30 days
Log workout: HYROX for 45 minutes today
MCP Server Specification
Tools (4)
1. track_event
Insert or update tracking event for any entity type.
Parameters:
entity_type(string, required): Entity type (e.g., 'weight', 'scorecard', 'fitness', 'book', or custom)date(string, required): Event date in YYYY-MM-DD formatdata(object, required): Entity-specific data (schema-free JSON)entity_id(string, optional): Unique ID for entity instance (e.g., 'book_atomic_habits')
Example:
track_event(
entity_type="weight",
date="2026-01-14",
data={"weight_kg": 72.8, "day_type": "MAR", "source": "manual"}
)
2. query_events
Query tracking events with filters.
Parameters:
entity_type(string, optional): Filter by entity typeentity_id(string, optional): Filter by entity IDstart_date(string, optional): Start date (inclusive)end_date(string, optional): End date (inclusive)limit(integer, optional): Maximum results (default: 100)
Example:
query_events(
entity_type="weight",
start_date="2025-12-15",
end_date="2026-01-14",
limit=30
)
3. delete_event
Delete tracking event by ID.
Parameters:
event_id(integer, required): Event ID to delete
4. list_entity_types
Get all registered entity types with schema examples.
Returns: JSON array of entity types with descriptions and schema examples.
Resources (3)
1. tracking://schema/entity_types
List of all registered entity types with schema examples (JSON).
2. tracking://docs/usage
Usage guide for tracking new entity types dynamically (Markdown).
3. tracking://stats/summary
Current statistics: total events, entity types, date range, events by type (JSON).
Prompts (3)
1. track-weight
Template for tracking body weight.
Arguments: weight_kg, date
2. track-workout
Template for logging workout session.
Arguments: workout_type, duration_min, date
3. query-trend
Get trend data for entity type over date range.
Arguments: entity_type, days (default: 30)
Database Schema
tracking_events Table
| Column | Type | Description |
|---|---|---|
id |
INTEGER PRIMARY KEY | Auto-increment ID |
entity_type |
TEXT | Entity type ('weight', 'scorecard', etc.) |
entity_id |
TEXT | Optional unique ID for entity instances |
date |
DATE | Event date (YYYY-MM-DD) |
data |
JSON | Schema-free JSON data |
created_at |
TIMESTAMP | Auto-generated creation timestamp |
updated_at |
TIMESTAMP | Auto-updated modification timestamp |
Indexes: entity_type, date, entity_id
entity_types Table
| Column | Type | Description |
|---|---|---|
entity_type |
TEXT PRIMARY KEY | Entity type name |
description |
TEXT | Human-readable description |
schema_example |
JSON | Example JSON schema |
created_at |
TIMESTAMP | Registration timestamp |
updated_at |
TIMESTAMP | Last update timestamp |
Pre-seeded entity types: weight, scorecard, fitness, book
Advanced Usage Examples
Track Custom Entity Type
# Sleep quality tracking (auto-registered)
track_event(
entity_type="sleep_quality",
date="2026-01-14",
data={
"hours": 7.5,
"quality_score": 8,
"dreams": True,
"interruptions": 2,
"notes": "Felt refreshed"
}
)
Track Entity with Unique ID
# Reading progress for specific book
track_event(
entity_type="book",
entity_id="book_atomic_habits",
date="2026-01-14",
data={
"title": "Atomic Habits",
"author": "James Clear",
"current_page": 150,
"total_pages": 320,
"rating": 5
}
)
Query with Filters
# Get all weight entries for January 2026
query_events(
entity_type="weight",
start_date="2026-01-01",
end_date="2026-01-31"
)
# Get all entries for specific book
query_events(
entity_type="book",
entity_id="book_atomic_habits"
)
Update Existing Event
To update an event, call track_event() with the same entity_type + date (+ entity_id if used). The tool will automatically UPDATE instead of INSERT.
SQL Analytics
Since data is stored in SQLite with JSON columns, you can run advanced analytics:
Weight Trend (Last 30 Days)
SELECT
date,
json_extract(data, '$.weight_kg') as weight,
json_extract(data, '$.delta_kg') as delta
FROM tracking_events
WHERE entity_type = 'weight'
AND date >= date('now', '-30 days')
ORDER BY date DESC;
Scorecard Weekly Average
SELECT
strftime('%Y-W%W', date) as week,
AVG(CAST(json_extract(data, '$.total_score') AS INTEGER)) as avg_score,
COUNT(*) as days
FROM tracking_events
WHERE entity_type = 'scorecard'
AND date >= date('now', 'weekday 0', '-7 days')
GROUP BY week;
Fitness Volume by Workout Type (This Month)
SELECT
json_extract(data, '$.workout_type') as type,
COUNT(*) as sessions,
SUM(CAST(json_extract(data, '$.duration_min') AS INTEGER)) as total_minutes,
AVG(CAST(json_extract(data, '$.duration_min') AS INTEGER)) as avg_minutes
FROM tracking_events
WHERE entity_type = 'fitness'
AND date >= date('now', 'start of month')
GROUP BY type;
Project Structure
tracking-mcp/
├── data/
│ ├── tracking.db # SQLite database
│ └── schema.sql # Database schema
├── tracking_mcp/
│ ├── tracking_server.py # MCP server implementation
│ └── __init__.py
├── tests/
│ └── test_server.py
├── pyproject.toml
├── LICENSE
├── CHANGELOG.md
└── README.md
Architecture Decisions
Why JSON Hybrid (SQLite + JSON)?
- ✅ Flexibility: Add new entity types without schema migrations
- ✅ Performance: SQLite indexes +
json_extract()for fast queries - ✅ SQL-queryable: Standard SQL for analytics
- ❌ EAV alternative: Too many JOINs, poor performance for analytics
Why Custom MCP vs Official SQLite MCP?
- ✅ Auto-discovery: New entity types registered automatically
- ✅ Self-documenting: Resources expose schemas and usage
- ✅ Dynamic: No rigid schema required
- ❌ Official SQLite MCP: Requires predefined schema
Why SQLite vs PostgreSQL?
- ✅ Zero setup: File-based, no server required
- ✅ Local-first: Privacy-friendly for personal tracking
- ✅ Sufficient: Perfect for single-user personal use
- ❌ PostgreSQL: Unnecessary overhead for personal tracking
Development
Run Tests
pytest
Code Quality
# Format code
black mcp_server/
# Lint
ruff check mcp_server/
Install Development Dependencies
pip install -e ".[dev]"
Version History
See CHANGELOG.md for version history.
Current version: 1.0.0 (Initial public release)
Related Projects
- viz-mcp: Companion MCP server for auto-generating data visualizations from tracking data
- work-hub: Personal productivity system using tracking-mcp for daily scorecard and habit tracking
License
MIT License - see LICENSE file for details.
Author
Mario Mosca - GitHub
Contributing
Contributions welcome! Please open an issue or pull request.
Support
For issues, questions, or feature requests, please open an issue on GitHub: https://github.com/mariomosca/tracking-mcp/issues
Metadata
Release files for tracking-mcp 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tracking_mcp-1.0.1.tar.gz | 13.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tracking_mcp-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.6 kB
Release files / tracking_mcp-1.0.1.tar.gz
| Download URL | tracking_mcp-1.0.1.tar.gz |
|---|---|
| Size | 13.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cc61cdb3a5461f888d7505d25313d4ae06e81162b52e85a65f8abff85728095f
|
|
BLAKE2b-256 checksum How to use checksums |
4d59f93578a1d41f21143a8437add76c01199b4cba67edb0840988d873f78e8b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.8
|
Release files / tracking_mcp-1.0.1-py3-none-any.whl
| Download URL | tracking_mcp-1.0.1-py3-none-any.whl |
|---|---|
| Size | 10.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d5b27d05868c0b620c5620559f12bbc1ea2215ce92ce10dd312752d4be57dc1f
|
|
BLAKE2b-256 checksum How to use checksums |
9ec6bbe039c46d2621febe3fa115b1e755c028a6010f3a4f356edc03fbd9baef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.8
|