Skip to main content
Glama
neonwatty

Food Tracker MCP Server

by neonwatty
usda-api.ts3.29 kB
import type { USDASearchResponse, USDAFood, NutritionInfo, FoodSearchResult, } from "../types.js"; const USDA_API_BASE = "https://api.nal.usda.gov/fdc/v1"; // Nutrient IDs in USDA database const NUTRIENT_IDS = { ENERGY: 1008, // Calories (kcal) PROTEIN: 1003, CARBS: 1005, // Carbohydrate, by difference FAT: 1004, // Total lipid (fat) FIBER: 1079, // Fiber, total dietary }; export class USDAApi { private apiKey: string; constructor(apiKey: string) { this.apiKey = apiKey; } async searchFoods( query: string, pageSize: number = 10 ): Promise<FoodSearchResult[]> { const url = `${USDA_API_BASE}/foods/search?api_key=${this.apiKey}`; const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ query, pageSize, dataType: ["Foundation", "SR Legacy", "Branded"], }), }); if (!response.ok) { throw new Error(`USDA API error: ${response.status} ${response.statusText}`); } const data: USDASearchResponse = await response.json(); return data.foods.map((food) => ({ fdcId: food.fdcId, description: food.description, brandOwner: food.brandOwner, dataType: food.dataType, nutrition: this.extractNutrition(food), servingSize: food.servingSize, servingSizeUnit: food.servingSizeUnit, })); } async getFoodDetails(fdcId: number): Promise<USDAFood | null> { const url = `${USDA_API_BASE}/food/${fdcId}?api_key=${this.apiKey}`; const response = await fetch(url); if (!response.ok) { if (response.status === 404) { return null; } throw new Error(`USDA API error: ${response.status} ${response.statusText}`); } return response.json(); } async getNutrition(fdcId: number): Promise<NutritionInfo | null> { const food = await this.getFoodDetails(fdcId); if (!food) return null; return this.extractNutrition(food); } private extractNutrition(food: USDAFood): NutritionInfo { const getNutrientValue = (nutrientId: number): number => { const nutrient = food.foodNutrients.find( (n) => n.nutrientId === nutrientId ); return nutrient?.value ?? 0; }; return { calories: Math.round(getNutrientValue(NUTRIENT_IDS.ENERGY)), protein_g: Math.round(getNutrientValue(NUTRIENT_IDS.PROTEIN) * 10) / 10, carbs_g: Math.round(getNutrientValue(NUTRIENT_IDS.CARBS) * 10) / 10, fat_g: Math.round(getNutrientValue(NUTRIENT_IDS.FAT) * 10) / 10, fiber_g: Math.round(getNutrientValue(NUTRIENT_IDS.FIBER) * 10) / 10, }; } // Scale nutrition values based on serving size scaleNutrition( nutrition: NutritionInfo, servingSize: number, baseServingSize: number = 100 // USDA values are typically per 100g ): NutritionInfo { const scale = servingSize / baseServingSize; return { calories: Math.round(nutrition.calories * scale), protein_g: Math.round(nutrition.protein_g * scale * 10) / 10, carbs_g: Math.round(nutrition.carbs_g * scale * 10) / 10, fat_g: Math.round(nutrition.fat_g * scale * 10) / 10, fiber_g: Math.round(nutrition.fiber_g * scale * 10) / 10, }; } }

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