AI-FITNESS-COACH-MCP(7) NAME ai-fitness-coach-mcp - single-user nutrition, health, and workout data tools SYNOPSIS POST /api/mcp GET /api/mcp POST /api/mcp/images/upload DESCRIPTION Streamable HTTP MCP endpoint for the AI Fitness Coach single-user data collector. All writes use user_id = rt-primary-user. Nutrition corrections are immutable ledger entries. Large meal photos: POST /api/mcp/images/upload (Bearer auth, multipart or raw body, max 30 MiB), then pass returned urls in log_meal.image_urls / attach_meal_evidence.image_urls. MCP tool defensiveness: tools refuse ambiguous or evidence-weak writes with an instructive error naming the exact confirm_* boolean to set after asking the human. Three tiers: reject (correctness guarantees — e.g. image reuse across meal lineages), confirm_* (needs a human answer — backdate, no photo, EXIF drift), flag (advisory suspicion — duplicates, staleness). The server is the enforcement point; agent goodwill is never assumed. TOOLS log_meal Description: Durably logs one natural-language meal as one or more component rows. Send everything you have. When a food photo is available, include it in images[]; do not omit a photo you have. When no photo exists, ask the human and retry with confirm_no_photo=true. When exact values or calorie/protein estimates are available, include them. Optional evidence disclosure booleans help callers be explicit, but the receipt data_quality is based on actual payload contents. Parameters: description (string) required Plain-language meal description. Comma/semicolon/and-separated foods are itemized into separate rows when components are not supplied. idempotency_key (string) optional Optional explicit replay key. Reusing the same key returns existing component rows instead of inserting duplicates. external_id (string) optional Optional caller-owned external identifier with the same explicit replay behavior as idempotency_key. evidence_disclosure ({ has_photo?: boolean; has_exact_values?: boolean; has_agent_estimate?: boolean }) optional Optional honesty disclosure for available evidence. True values must be backed by matching input data. Omitted or false values never block logging by themselves; the server evaluates actual payload contents. components (array) optional Optional explicit component list. Each component can include description, quantity, unit, exact calories/protein, agent estimate, and value_source. images (string[]) optional Base64 encoded image strings or data URLs. Combined decoded image bytes must not exceed 3 MiB. For larger photos, POST to /api/mcp/images/upload with Authorization: Bearer (multipart field "file" or raw body; max 30 MiB), then pass the returned url in image_urls. When a food photo is available, include it. When neither images nor image_urls are provided, confirm_no_photo=true is required after asking the human. image_urls (string[]) optional Vercel Blob URLs from POST /api/mcp/images/upload (MCP/agent) or POST /api/nutrition/images/upload (browser) for photos larger than the base64 transport cap. Combined with images[], max 5 total. exact_calories_kcal (number) optional Exact calories for a single-component call. Include when genuinely known from a label, receipt, menu, or trusted source. exact_protein_g (number) optional Exact protein for a single-component call. Include when genuinely known from a label, receipt, menu, or trusted source. agent_estimated_calories_kcal (number) optional Caller/agent calorie estimate for a single-component call. When you have made an estimate, include it; do not invent one to improve quality. agent_estimated_protein_g (number) optional Caller/agent protein estimate for a single-component call. When you have made an estimate, include it; do not invent one to improve quality. value_source (label | historical | agent_estimate | nim_estimate | manual | unknown) optional Source for supplied exact/caller values. Receipts show this per component. meal_time (string) optional Optional ISO 8601 timestamp with offset for when the meal was eaten (e.g. 2026-06-28T14:00:00Z or 2026-06-28T20:00:00+06:00). Defaults to now. confirm_backdate (boolean) optional Required as true when meal_time is more than ~10 minutes in the past. confirm_no_photo (boolean) optional Required as true when logging without images[] or image_urls[] after asking the human and confirming no photo exists. confirm_image_time_mismatch (boolean) optional Required as true when EXIF capture time differs from meal_time/logged time by more than 12 hours. Returns: Terminal receipt with meal group ID, data_quality { quality, reason, guidance }, every component row ID, value source, exact/agent/backend estimates, historical calibration, divergence flags, launch activity context, today totals, and verify URLs. correct_meal Description: Creates an immutable correction for a logged meal. Include correction images when available. The original row is never updated, and the corrected row is inserted before queued backend NIM re-estimation. Parameters: original_row_id (uuid) required nutrition_log.id of the row being corrected. correction_text (string) required What was wrong and what the corrected food entry should be. images (string[]) optional Base64 encoded correction images, including data URLs when available. Combined decoded image bytes must not exceed 3 MiB. For larger photos, POST to /api/mcp/images/upload then use image_urls on tools that accept them. meal_time (string) optional Optional ISO 8601 timestamp with offset for the corrected meal time. Defaults to now. confirm_backdate (boolean) optional Required as true when meal_time is more than ~10 minutes in the past. confirm_image_time_mismatch (boolean) optional Required as true when correction image EXIF capture time differs from meal_time by more than 12 hours. Returns: Correction receipt with original entry, corrected pending entry, calorie/protein deltas, new row ID, queued backend NIM status, and verify URLs for both rows. list_meals Description: Searches active nutrition_log meal rows by date range and/or description keyword. This is read-only and never estimates nutrition. Parameters: start_date (string) optional Optional YYYY-MM-DD user-local date or ISO timestamp lower bound for logged_at. end_date (string) optional Optional YYYY-MM-DD user-local inclusive date or ISO timestamp upper bound for logged_at. keyword (string) optional Optional case-insensitive substring match against description. limit (number) optional Maximum active rows to return, from 1 to 100. Defaults to 50. Returns: JSON array of matching rows with id, logged_at, description, calories, protein, and meal_group_id. annotate_meal Description: Appends context to an existing meal by inserting an immutable nutrition_log row that references the original row. Calories and protein are copied unchanged and NIM is skipped. Parameters: meal_id (uuid) required nutrition_log.id of the row receiving extra context. context (string) required Context to append to the meal description. Returns: Annotation receipt with original entry, annotated entry, copied calories/protein, skipped NIM status, and verify URLs for both rows. void_meal Description: Excludes a duplicate or invalid meal from active totals by inserting an immutable zero-calorie/zero-protein row that supersedes the original. Parameters: meal_id (uuid) required nutrition_log.id of the row to exclude from active totals. reason (string) optional Audit reason stored in raw_submission and notes. idempotency_key (string) optional Optional caller replay key. Defaults to void:{meal_id}. Returns: Void receipt with original entry, immutable zero-value superseding row, active totals effect, and verify URLs for both rows. track_metric Description: Tracks an observed manual health metric. Use the actual device/app/manual value available to you; do not fabricate missing measurements. Weight goes to body_measurements; others (water, caffeine, steps, etc.) go to health_metrics. Parameters: metricType (weight | sleep | mood | steps | water | caffeine) required Metric category. value (number) required Observed metric value. unit (string) optional Unit label. For weight, pass kg or lb (lb converts to kg). Other metrics accept hours, steps, ml, oz, mg, etc. measured_at (string) optional ISO timestamp with offset for weight. Defaults to now. confirm_backdate (boolean) optional Required true when measured_at is more than 10 minutes in the past. Returns: Terminal receipt with inserted row ID, metric value, and timestamp. get_user_history Description: Reads recent logged nutrition, body measurements, and health metrics for the single hardcoded user. Parameters: metricType (meals | weight | sleep | mood | steps | water | caffeine | all) optional History category filter. days (number) optional Lookback window from 1 to 90 days. Defaults to 7. include_raw_fields (boolean) optional When true and metricType is weight or all, include raw_fields and unmapped key values on weight rows. Returns: JSON string containing matching history rows. get_nutrition_guidance Description: Returns static evidence-based nutrition guidance by goal. Parameters: goal (weight_loss | muscle_gain | maintenance | general_health) required Nutrition goal. dietaryRestrictions (string[]) optional Optional restrictions. Returns: Plain text guidance. import_apple_health Description: Imports a HealthAutoExport JSON payload into health_metrics. Parameters: payload (object) required Full HealthAutoExport JSON payload. Rejected when the serialized payload exceeds the 4 MiB direct-import limit; use import_apple_health_document for larger exports. Returns: Terminal receipt with immutable import receipt row ID, timestamp, row counts, date range, metric names, and a verify URL. import_apple_health_document Description: Hands off an OpenClaw Apple Health export document for asynchronous blob import job processing. Use when OpenClaw transport delivers a zip/json export by URL rather than inline HealthAutoExport JSON. Parameters: original_filename (string) required Original export filename, e.g. HealthAutoExport.zip. size_bytes (number) required Exact byte size of the document (max 100MB). content_type (string) required MIME type such as application/zip or application/json. blob_url (string) optional Vercel Blob URL when the document is already stored in blob storage. Provide exactly one of blob_url or file_url. file_url (string) optional HTTPS URL on an allowed host when OpenClaw fetched the document elsewhere. Provide exactly one of blob_url or file_url. blob_pathname (string) optional Optional blob pathname hint when using blob_url. Returns: Async handoff receipt with job_id, status (processing or failed), filename/size echo, and note that completion is import-job based. Poll GET /api/import/apple-health/jobs for completion. import_document Description: Hands off an arbitrary document (scale export, spreadsheet, PDF, image) via blob_url or file_url for asynchronous universal import processing. Flag tier: caller should disclose uncertain file provenance when known. Parameters: original_filename (string) required Original document filename. size_bytes (number) required Exact byte size of the document (max 50MB). content_type (string) required MIME type such as application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/pdf, or image/jpeg. blob_url (string) optional Vercel Blob URL when the document is already stored. Provide exactly one of blob_url or file_url. file_url (string) optional HTTPS URL on an allowed host when the document was fetched elsewhere. Provide exactly one of blob_url or file_url. Returns: Async handoff receipt with job_id and status. Poll GET /api/import/universal/jobs for completion. Low-confidence observations may require confirm_import_observations. confirm_import_observations Description: Confirms and writes low-confidence universal import observations that were flagged on an import job. Without confirm_import_observations=true, returns the flagged rows and the exact boolean to set after asking the human. Parameters: job_id (uuid) required import_jobs.id of the universal import job with flagged observations. observation_indexes (number[]) optional Optional subset of flagged observation indexes to confirm. Defaults to all flagged observations. confirm_import_observations (boolean) optional Must be true after human confirmation to write the flagged observations. Returns: Confirmation receipt with written/skipped counts, or an instructive gate listing flagged rows when confirm_import_observations is not true. import_body_measurements Description: Imports body composition scale measurement payloads (spreadsheet row shape or compatible vendor measure-group JSON). Timestamps without an offset are interpreted in your configured timezone. Parameters: payload (object) required Body composition scale measurement payload (row array, measurements object, or compatible vendor measure-group JSON). source (string) optional Optional source label to persist with the row. weight_unit (kg | lb) optional Unit for bare numeric weight/mass values when the payload does not carry a suffix. Defaults to kg. Returns: Terminal receipt with parsed/inserted/updated counts and preserved-but-unmapped field names (stored in raw_fields). process_pending_nutrition Description: Retries pending or failed backend NIM enrichment for durable nutrition_log rows. Parameters: limit (number) optional Maximum rows to process, from 1 to 50. Defaults to 10. Returns: Terminal receipt with checked, processed, failed, skipped counts and per-row statuses. estimate_meal Description: Runs or queues backend AI nutrition comparison for an existing nutrition_log row without inserting duplicate food rows. Canonical logged calories/protein stay unchanged; backend NIM output is stored separately. Uses stored meal evidence only. Parameters: meal_id (uuid) required nutrition_log.id of the existing meal row to compare. process_now (boolean) optional Run immediately when true (default). When false, queue as pending for batch processing. Returns: Comparison receipt with canonical logged totals, provided vs backend NIM estimates, delta lines when both sides exist, estimate status, and verify URL. attach_meal_evidence Description: Attaches new photo evidence to an active meal by inserting an immutable superseding nutrition_log row, merging images (max 5 total), and running backend NIM comparison immediately. Parameters: meal_id (uuid) required nutrition_log.id of the active meal row receiving new evidence. images (string[]) optional Base64 image strings or data URLs for new evidence photos. At least one new image is required across images and image_urls. Combined decoded base64 bytes must not exceed 3 MiB; larger photos go through POST /api/mcp/images/upload then image_urls. image_urls (string[]) optional Vercel Blob URLs from POST /api/mcp/images/upload or POST /api/nutrition/images/upload for large new photos. note (string) optional Optional context about the newly attached evidence. confirm_image_time_mismatch (boolean) optional Required as true when new image EXIF capture time differs from meal logged time by more than 12 hours. Returns: Evidence attach receipt with original and superseding row IDs, merged image counts, NIM status, duplicate/EXIF advisory flags, and verify URLs. set_user_timezone Description: Sets the calendar timezone used for date buckets, day bounds, and history windows. Parameters: timezone (string) required Valid IANA timezone name, e.g. America/Edmonton. Returns: Confirmation with the persisted timezone. Takes effect within the 60-second settings cache window. EXAMPLE RECEIPT LOGGED ✓ Meal group ID: e640a70a-a13a-46c7-b9f0-5c3c91cc8468 Components logged: 2 Images received: 1 Quality tier: high Guidance: Keep including photos plus exact values or your calorie/protein estimate when available. Data quality: {"quality":"high","quality_tier":"high","image_count":1,"has_exact_values":true,"has_agent_estimate":false,"reason":"Photo evidence and exact nutrition values were provided.","guidance":"Keep including photos plus exact values or your calorie/protein estimate when available."} COMPONENT 1/2 Row ID: 3f7a7e78-88fd-4c39-9c9a-590bd0be9e7d two strips of bacon 100 kcal | 5g protein Source: historical pattern Winning estimate: historical pattern Exact value: none Agent estimate: none Backend NIM estimate: none NIM status: skipped (historical pattern reused). Estimate status: succeeded Meal time: 2026-06-28T06:45:00.000Z HISTORICAL PATTERN Historical: two strips bacon -> 100 kcal, 5g protein (n=4, last Jun 14) Verify: https://ai-fitness-coach-ten-henna.vercel.app/verify/3f7a7e78-88fd-4c39-9c9a-590bd0be9e7d COMPONENT 2/2 Row ID: b77b65c4-d814-4eef-9391-36b1eef7d6e6 toast with kaya jam 250 kcal | 4g protein Source: label Winning estimate: label Exact value: 250 kcal | 4g protein Agent estimate: none Backend NIM estimate: none NIM status: skipped (exact value provided). Estimate status: succeeded Meal time: 2026-06-28T06:45:00.000Z HISTORICAL PATTERN Historical: none found for toast with kaya jam. Verify: https://ai-fitness-coach-ten-henna.vercel.app/verify/b77b65c4-d814-4eef-9391-36b1eef7d6e6 STRAVA CONTEXT Strava: parked for launch TODAY SO FAR Calories: 1640 kcal Protein: 122g Meals logged: 4