Skip to main content
Glama
neonwatty

Food Tracker MCP Server

by neonwatty
database.ts4.51 kB
import Database from "better-sqlite3"; import path from "path"; import { fileURLToPath } from "url"; import type { FoodLogEntry, Goals, NutritionInfo } from "../types.js"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const DB_PATH = path.join(__dirname, "../../data.db"); let db: Database.Database | null = null; export function getDb(): Database.Database { if (!db) { db = new Database(DB_PATH); db.pragma("journal_mode = WAL"); initializeSchema(); } return db; } function initializeSchema(): void { const database = db!; database.exec(` CREATE TABLE IF NOT EXISTS goals ( id INTEGER PRIMARY KEY DEFAULT 1, daily_calories INTEGER, protein_g INTEGER, carbs_g INTEGER, fat_g INTEGER, updated_at TEXT DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS food_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, logged_at TEXT DEFAULT CURRENT_TIMESTAMP, date TEXT NOT NULL, meal TEXT, food_name TEXT NOT NULL, fdc_id INTEGER, serving_size REAL NOT NULL, serving_unit TEXT NOT NULL, calories REAL NOT NULL, protein_g REAL, carbs_g REAL, fat_g REAL, fiber_g REAL, notes TEXT ); CREATE INDEX IF NOT EXISTS idx_food_logs_date ON food_logs(date); `); // Insert default goals row if not exists const goalsExist = database .prepare("SELECT COUNT(*) as count FROM goals") .get() as { count: number }; if (goalsExist.count === 0) { database .prepare( "INSERT INTO goals (id, daily_calories, protein_g, carbs_g, fat_g) VALUES (1, 2000, 150, 250, 65)" ) .run(); } } // Goals operations export function getGoals(): Goals | null { const db = getDb(); return db.prepare("SELECT * FROM goals WHERE id = 1").get() as Goals | null; } export function updateGoals(goals: Partial<Goals>): Goals { const db = getDb(); const current = getGoals(); const newGoals = { daily_calories: goals.daily_calories ?? current?.daily_calories, protein_g: goals.protein_g ?? current?.protein_g, carbs_g: goals.carbs_g ?? current?.carbs_g, fat_g: goals.fat_g ?? current?.fat_g, }; db.prepare( `UPDATE goals SET daily_calories = ?, protein_g = ?, carbs_g = ?, fat_g = ?, updated_at = CURRENT_TIMESTAMP WHERE id = 1` ).run( newGoals.daily_calories, newGoals.protein_g, newGoals.carbs_g, newGoals.fat_g ); return getGoals()!; } // Food log operations export function logFood(entry: Omit<FoodLogEntry, "id" | "logged_at">): FoodLogEntry { const db = getDb(); const result = db .prepare( `INSERT INTO food_logs (date, meal, food_name, fdc_id, serving_size, serving_unit, calories, protein_g, carbs_g, fat_g, fiber_g, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` ) .run( entry.date, entry.meal, entry.food_name, entry.fdc_id, entry.serving_size, entry.serving_unit, entry.calories, entry.protein_g, entry.carbs_g, entry.fat_g, entry.fiber_g, entry.notes ); return db .prepare("SELECT * FROM food_logs WHERE id = ?") .get(result.lastInsertRowid) as FoodLogEntry; } export function getDailyLog(date: string): FoodLogEntry[] { const db = getDb(); return db .prepare("SELECT * FROM food_logs WHERE date = ? ORDER BY logged_at") .all(date) as FoodLogEntry[]; } export function getLogsByDateRange(startDate: string, endDate: string): FoodLogEntry[] { const db = getDb(); return db .prepare( "SELECT * FROM food_logs WHERE date >= ? AND date <= ? ORDER BY date, logged_at" ) .all(startDate, endDate) as FoodLogEntry[]; } export function deleteEntry(id: number): boolean { const db = getDb(); const result = db.prepare("DELETE FROM food_logs WHERE id = ?").run(id); return result.changes > 0; } export function calculateTotals(entries: FoodLogEntry[]): NutritionInfo { return entries.reduce( (totals, entry) => ({ calories: totals.calories + (entry.calories || 0), protein_g: totals.protein_g + (entry.protein_g || 0), carbs_g: totals.carbs_g + (entry.carbs_g || 0), fat_g: totals.fat_g + (entry.fat_g || 0), fiber_g: totals.fiber_g + (entry.fiber_g || 0), }), { calories: 0, protein_g: 0, carbs_g: 0, fat_g: 0, fiber_g: 0 } ); } export function closeDb(): void { if (db) { db.close(); db = null; } }

Latest Blog Posts

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/neonwatty/food-tracker-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server