Skip to main content
Glama
Wellness Project MCP

Wellness Project MCP

Wellness Project MCP

MCP Marketplace MCPVault: claimed MCP status Listed on mcpservers.org Wellness Project MCP server — quality and maintenance score on Glama AllMCPs Verified

Bring connected health and fitness data into Claude, ChatGPT, Gemini Spark, Gemini CLI, Grok, Mistral, and other MCP clients. Wellness Project is a hosted Model Context Protocol server. Your devices and logs sync into one account, and supported assistants can read or update workouts, nutrition, sleep, recovery, body metrics, goals, labs, wellbeing, and more in plain English.

This repository is the public documentation and catalog for the hosted server. It is not a self-hosted backend and contains no private server implementation.

  • App: https://wellnessproject.ai

  • MCP endpoint: https://wellnessproject.ai/api/mcp

  • 73 advertised public tools generated from the production tool registry

  • 15 active interactive widgets for compatible MCP Apps UI clients

  • OAuth 2.1 authentication with Dynamic Client Registration


What you can ask

Once connected, ask naturally and the assistant can call the matching Wellness Project tool:

  • "How did my training look this week?"

  • "Show my sleep for the last month."

  • "How is my bench progressing?"

  • "Log today's lunch: chicken burrito bowl, about 700 calories."

  • "What was my resting heart rate trend vs my HRV this quarter?"

  • "How am I doing against my goals?"

  • "Log 16 ounces of water."

Read tools return your logged and synced health data. Write tools add, update, or delete entries when you ask. Widget tools can render structured interactive views instead of a wall of numbers.

Related MCP server: health-mcp

Connect Wellness Project to an MCP client

First create an account at https://wellnessproject.ai and connect the health sources you want under Settings → Devices. Every client below uses the same hosted endpoint:

https://wellnessproject.ai/api/mcp

Authentication is handled by OAuth. Personal API keys are not part of the current public connection flow.

Claude

  1. Open Claude on the web.

  2. Go to Customize → Connectors → Add custom connector.

  3. Paste https://wellnessproject.ai/api/mcp.

  4. Leave Client ID and Client Secret blank if Claude shows those fields. Claude can register itself dynamically.

  5. Sign in to Wellness Project and authorize the connection.

Claude Code

Claude Code installs Wellness Project as a plugin. The plugin carries nothing but this server's configuration and a setup skill.

/plugin marketplace add turnnoblindeye/wellness-project-mcp
/plugin install wellness-project

Restart Claude Code, then run /mcp, select wellness-project, and authorize. There is no client ID, client secret, or API key to enter. Run /wellness-project:setup if you would rather be walked through it.

Gemini CLI

Wellness Project is listed in the official Gemini CLI Extensions Gallery. Install the extension from this public repository:

gemini extensions install https://github.com/turnnoblindeye/wellness-project-mcp

Restart Gemini CLI, then run /mcp list to check for the wellness-project server. If authentication is needed, run /mcp auth wellness-project and sign in to Wellness Project in your browser. After authorization, ask Gemini about your workouts, nutrition, sleep, recovery, or goals, or request a log update.

This connects to the hosted MCP endpoint, so no local server or personal API key is needed. Gemini CLI's OAuth flow requires a browser and access to a localhost callback. See Gemini CLI's MCP authentication documentation for details.

Cline

Cline connects to Wellness Project as a remote MCP server. Nothing is cloned, installed, or run locally.

  1. Open the MCP Servers icon in the Cline sidebar and choose Remote Servers.

  2. Enter a server name, for example wellness-project.

  3. Paste https://wellnessproject.ai/api/mcp as the server URL and add it.

  4. Complete the Wellness Project OAuth flow when Cline opens it in your browser.

To edit cline_mcp_settings.json directly instead:

{
  "mcpServers": {
    "wellness-project": {
      "type": "streamableHttp",
      "url": "https://wellnessproject.ai/api/mcp",
      "disabled": false,
      "autoApprove": []
    }
  }
}

Set "type": "streamableHttp" explicitly. Cline falls back to the legacy SSE transport when the type is omitted. There is no client ID, client secret, or API key to enter. llms-install.md has the same steps written for an agent doing the setup.

ChatGPT

ChatGPT custom MCP apps use developer mode. Current OpenAI availability is plan-dependent: full MCP support including write/modify actions is available in beta for Business, Enterprise, and Edu, while Pro can connect MCPs with read/fetch permissions in developer mode.

  1. Enable developer mode for your account or workspace as permitted by your ChatGPT plan.

  2. Create a custom MCP app from ChatGPT's Apps settings.

  3. Use https://wellnessproject.ai/api/mcp as the remote MCP server.

  4. Complete the Wellness Project OAuth flow.

OpenAI's current setup and plan details: https://help.openai.com/en/articles/12584461

Gemini Spark

Custom MCP apps require Gemini Spark access and are added from the Gemini web app.

  1. Go to https://gemini.google.com.

  2. Open Settings & help → Connected Apps. If needed, open Personal Intelligence → Connected Apps first.

  3. Under Custom apps for Spark, choose Add a custom app.

  4. Enter https://wellnessproject.ai/api/mcp and click Next.

  5. Complete the Wellness Project OAuth flow.

Google's current eligibility and availability rules: https://support.google.com/gemini/answer/17209137

Grok

  1. Go to https://grok.com/connectors and choose New Connector → Custom.

  2. Paste https://wellnessproject.ai/api/mcp.

  3. Leave Client ID and Client Secret blank if those fields appear.

  4. Complete the Wellness Project OAuth flow.

Grok connector availability may depend on your Grok plan.

Mistral Le Chat

  1. In Le Chat, open Intelligence → Connectors → Add Connector → Custom MCP Connector.

  2. Paste https://wellnessproject.ai/api/mcp.

  3. Leave Client ID and Client Secret blank if those fields appear.

  4. Complete the Wellness Project OAuth flow.

Workspace permissions may require an owner or admin to add a connector.

Demo

A short screen recording of the Wellness Project connector running inside ChatGPT:

Watch the demo

Interactive widgets

Fifteen active tools render interactive views through the MCP Apps UI extension in compatible clients:

Ask

Widget tool

"Give me a health overview"

show_health_overview

"How did my Fit Score look?"

show_week_fit_score

"Show my workouts"

show_week_workouts

"Show that workout"

show_workout

"Show my macros"

show_week_macros

"Show my meal diary"

show_meal_diary

"How's my sleep trending?"

show_week_sleep

"Show last night's sleep"

show_sleep_detail

"Steps this week?"

show_week_steps

"My weight trend"

show_body_weight

"Show my body composition"

show_body_composition

"Recovery trend"

show_recovery

"How's my running?"

show_runs

"How's my bench progressing?"

show_exercise_progression

"Show my wellbeing"

show_wellbeing

Many trend widgets support multiple time ranges; detail widgets use the date or record relevant to the request.

Tool catalog

The complete production-generated list of 73 advertised public tools, grouped by domain, is in TOOLS.md. The machine-readable descriptions, annotations, and JSON Schemas are in catalog/tools.json.

Both files are generated from the same production tool registry used by tools/list. Admin-only tools and retired tools that remain callable only for older cached clients are not advertised in this catalog.

Do not edit the generated catalog by hand.

Data sources and integrations

Wellness Project combines native mobile health stores, direct integrations, relay sources, and manual/chat logging.

Source

Current support

Apple Health

Native iOS health and fitness sync

Google Health Connect

Native Android health and fitness sync

Fitbit / Google Health

Activity, sleep, heart, workout, body, and nutrition data when available

Oura

Sleep, readiness/recovery, heart, and activity data

Withings

Body, sleep, activity, heart, blood pressure, and other supported health data

Wyze

Supported Wyze health data

Hevy

Strength workout history via direct integration

Ultrahuman

Ring data and supported metabolic/CGM data

Liftosaur

Strength workout history via direct integration

Polar

Activity, sleep, recovery, heart, and training data

WHOOP

Direct integration is rolling out behind availability gating

Manual / chat

Workouts, meals, hydration, body metrics, labs, injuries, supplements, goals, wellbeing, and more

Garmin, Samsung Health, Amazfit/Zepp, Coros, Wahoo, Strava, Peloton, smart scales, and other compatible sources can also reach Wellness Project through Apple Health or Health Connect when those services write the relevant data there.

Pricing and status

Pricing below reflects the current production configuration as of September 7, 2026. Local app-store pricing may vary.

Plan

Price

Status

Free Basic

$0

Logging and editing remain free; starting October 15, 2026, Free includes 3 analysis questions per day

Founder Pro monthly

$4.99/month

Founder pricing through October 15, 2026

Founder Pro annual

$39.99/year

Founder pricing through October 15, 2026

Founder Lifetime

$199 one-time

Limited founder option, sunsetting

Pro monthly

$9.99/month

Standard pricing

Pro annual

$99.99/year

Standard pricing

Privacy and auth

  • The public MCP endpoint uses OAuth 2.1; supported clients can register dynamically.

  • Every MCP request is scoped to the authenticated Wellness Project account.

  • Row-level security protects user-owned records in the data layer.

  • Connector access can be revoked without self-hosting or rotating a long-lived personal API key.

Wellness Project is informational software, not a medical product.

FAQ

Do I have to self-host anything?

No. https://wellnessproject.ai/api/mcp is the hosted production server. This GitHub repository publishes documentation and schemas only.

Does the same endpoint work across AI assistants?

Yes. Claude, eligible ChatGPT accounts/workspaces, Gemini Spark, Gemini CLI, Grok, Mistral, and other compatible remote MCP clients can use the same endpoint. Client-side MCP availability and permissions vary by product and plan.

Is Wellness Project free?

Free Basic is available. Paid Founder Pro and standard Pro plans add analysis capacity and other paid capabilities; current pricing is listed above.

Is my health data private?

MCP access requires an authenticated OAuth grant and each tool operates on the signed-in user's account. You can revoke connector access when you no longer want a client connected.

License

The tool catalog and schemas in this repository are published under the MIT License so MCP clients and directories can reference them freely. "Wellness Project" and the app itself remain the property of Wellness Project LLC. See NOTICE for the scope of the grant.

Available Tools

73 tools
add_or_update_personal_contextAInspect

Add a new Personal Context memory, or update an existing one by id. A memory is a durable circumstance or preference that should carry across future unrelated conversations (e.g. "travels most weeks", "gym has no squat rack", "prefers short home workouts", "wants blunt feedback"). Use list_personal_context first to check whether an existing memory already covers the subject, and pass its id with operation update rather than creating a duplicate.

Health history does not belong here. Injuries, lab results, meals, workouts, sleep and body metrics each have their own dedicated tools that store them as structured data the app can chart and reason over; writing any of them as a memory duplicates that record and degrades it to loose text.

This writes immediately with no separate approval step. Free accounts are capped at 3 memories and Pro accounts at 50; updating an existing memory by id is always allowed even at the cap. There is no delete or bulk-write capability here.

Inputs: content (required), operation (required), memory_id. Returns: result

cancel_rest_dayA
DestructiveIdempotent
Inspect

Remove a previously declared rest day. Use when the user changes their mind ("scratch that, I'm going to lift today after all") or wants to undo a mistaken declaration.

INFER — do not ask:

  • date: parse the user's reference; default to today.

Inputs: date. Returns: result

create_goalAInspect

UNIT INPUTS: never convert units yourself. Pass the user's number for a _lb / _mi / _in field exactly as stated, and when they gave kg / km / cm set input_weight_unit / input_distance_unit / input_length_unit in that same object. Omit the companion when the number is already lb / mi / in. The tool converts once before storage, so this overrides any wording that asks you to do the arithmetic.

Create a new Wellness Project goal or standard target. Call this directly when the user wants to establish a goal; there is no schema-discovery or list_goals prerequisite. Available goal types and inputs come from the canonical Goals definitions.

This tool loads the user's current goals itself before writing, so do not call list_goals first: it reports what a standard target changed from, and refuses to stack a second goal on top of one that already covers the same thing, naming that goal's ID to use with update_goal. Infer the goal_type and canonical inputs from the request. Standard targets use target_value. Formal goal fields are described on the generated inputs.

Inputs: goal_type (required), title, weeks, metric, +25 more. Returns: result

delete_cycleA
DestructiveIdempotent
Inspect

Delete a period record. Only delete if the user explicitly asks to remove a specific record. Do not delete to "fix" a record — use update_cycle instead.

SELECTOR — pass id if known, or date (the period's start date, or any date that falls within it) to resolve it. Exactly one required. If date matches more than one record, the call errors with candidate IDs to retry with.

Inputs: id, date. Returns: result

delete_injuryA
DestructiveIdempotent
Inspect

Permanently delete an injury entry. Also removes all severity history for that injury.

SELECTOR — pass id if known, or injury (a body part or injury type substring, case-insensitive, e.g. "shoulder") optionally narrowed by date (an injury active on that day). Exactly one of id or injury required. If injury matches more than one entry, the call errors with candidate IDs to retry with.

Inputs: id, date, injury. Returns: result

delete_lab_resultA
DestructiveIdempotent
Inspect

Permanently delete one or more lab results. Use when the user explicitly asks to remove or delete a logged lab result. Never guess a selector.

SELECTOR, pass exactly one of id, date, or date+marker:

  • id: deletes a single marker's row.

  • date (optionally narrowed by panel_name): deletes every result from that draw at once. This is irreversible and can remove many rows in one call. Confirm with the user before a date-scoped delete, especially one not narrowed by panel_name or marker.

  • date + marker (a marker-name substring, case-insensitive, optionally narrowed by panel_name): resolves to and deletes one marker's row, same as id. Errors with candidate IDs if more than one marker on that date matches.

Inputs: id, date, marker, panel_name. Returns: result

delete_mealA
DestructiveIdempotent
Inspect

Permanently delete a meal entry. Use when the user explicitly asks to remove or delete a logged meal.

FIND THE MEAL: pass id if already known. Otherwise pass date (YYYY-MM-DD, defaults to today) and, only if more than one meal was logged that day, name (a substring of the food description, case-insensitive) to narrow it down. This action is irreversible — a match that isn't exactly one meal returns an error explaining why, with nothing deleted; retry with id or a narrower name, never guess.

HYDRATION: any assistant hydration events linked to this meal are deleted by the database in the same food-row delete. Do not issue a separate hydration delete.

Inputs: id, date, name. Returns: result

delete_recovery_sessionA
DestructiveIdempotent
Inspect

Permanently delete a recovery session log entry. This action is irreversible. If the user's intent is ambiguous, ask which session to remove.

SELECTOR — pass id if known, or session_date (+ optional session_category to narrow) to resolve it. Exactly one of id or session_date required. If it matches more than one session, the call errors with candidate IDs to retry with.

Inputs: id, session_date, session_category. Returns: result

delete_runA
DestructiveIdempotent
Inspect

UNIT INPUTS: never convert units yourself. Pass the user's number for a _lb / _mi / _in field exactly as stated, and when they gave kg / km / cm set input_weight_unit / input_distance_unit / input_length_unit in that same object. Omit the companion when the number is already lb / mi / in. The tool converts once before storage, so this overrides any wording that asks you to do the arithmetic.

Delete a run. Use when the user wants to remove a run entry. ASK for confirmation if the user's intent is ambiguous.

SELECTOR — pass id if known, or date (+ optional distance_mi to narrow, matched approximately within 0.25 mi) to resolve it. Exactly one of id or date required. If it matches more than one run, the call errors with candidate IDs to retry with.

Inputs: id, date, distance_mi, input_distance_unit. Returns: result

delete_wellbeingA
DestructiveIdempotent
Inspect

Permanently delete a wellbeing entry.

SELECTOR — pass id if known, or date (any day within the entry's period) to resolve it. Exactly one of id or date required. If date matches more than one entry, the call errors with candidate IDs to retry with.

Inputs: id, date. Returns: result

delete_workoutA
DestructiveIdempotent
Inspect

Permanently delete a workout session and all its exercises and sets. Use when the user wants to remove a logged workout entirely.

FIND THE SESSION: pass session_id if already known. Otherwise pass session_date (YYYY-MM-DD, defaults to today) and, only if more than one session was logged that day, name (a substring of the workout's focus/type, e.g. "Push" or "Leg Day", case-insensitive) to narrow it down. This action is irreversible and removes the session, all supersets, and all sets — a match that isn't exactly one session returns an error explaining why, with nothing deleted; retry with session_id or a narrower name, never guess.

SAVED WORKOUTS: pass saved_workout_id to delete a reusable Saved Workout instead of completed workout history.

Inputs: name, session_id, session_date, saved_workout_id. Returns: result

get_app_guide_sectionA
Read-onlyIdempotent
Inspect

Look up general customer help for the Wellness Project app. Use this only for broad questions about where a feature lives, how to use it, what a visible feature does, common troubleshooting steps, or pricing.

The returned guide is intentionally limited to stable, customer-facing help. Do not add or infer implementation details, technical architecture, policy or legal interpretation, privacy or security claims beyond the exact returned text, billing mechanics, release or version history, internal timing or targeting rules, or other details that are not in the returned section.

For navigation, the guide result is the source of truth. Navigation grounding: use only app sections, routes, labels, buttons, gestures, and menu paths explicitly named in this guide result. Do not infer, invent, or autocomplete nearby navigation. If the requested path or action is not confirmed here, say you are not sure where it lives rather than guessing.

For cost, price, Free vs Pro, Founding Member, upgrading, or the 3-analysis limit, use topic=pricing. That result consists of the two approved product messages plus the subscription page link. Reproduce exactly one appropriate message verbatim, include the supplied subscription link, and add no other pricing detail. Use the Founding Member message for ordinary pricing questions and the exhausted message only when the user says they already used the daily analysis allowance. In the in-app coach only, append this CTA block exactly after the chosen message: [CHIPS] Get Pro Now|open_paywall [/CHIPS]

Examples: "where do I see my PRs?" -> pages_training; "what does Fit Score include?" -> pages_dashboard; "how do I connect Oura?" -> wearables; "how do I set a calorie goal?" -> goals; "how do I log a meal?" -> logging; "how much does it cost?" -> pricing.

Inputs: topic (required). Returns: result

get_exercise_historyA
Read-onlyIdempotent
Inspect

Look up everything the user has done for ONE exercise: all-time PR plus recent performance, across many sessions.

USE FOR:

  • PR lookups — "what's my bench PR?", "have I ever squatted 315?". Returns the est. 1RM PR and the exact set it came from (date, weight, reps, RPE, banded vs unbanded, superset siblings, notes), plus rep-range bests (1RM/3RM/5RM/10RM). Banded and unbanded PRs are shown side-by-side when both exist.

  • Recent-activity questions — "how has my squat been lately?", "when did I last deadlift?". Returns the most recent N sessions containing the exercise, formatted like get_workout.

  • Trend questions — "am I getting stronger on incline DB press?". Includes a one-line delta of current best vs ~30-90 days ago.

NOT for a full session (every exercise in one workout — use get_workout) or a date-window list regardless of exercise (use list_workouts).

INFER — do not ask: exercise_name (take the user's words; resolves to canonical, or says so if never logged), recent_limit (default 10 sessions), since_date (optional — narrows only the Recent block; the PR is always all-time).

Inputs: exercise_name (required), since_date, recent_limit. Returns: result

get_workoutA
Read-onlyIdempotent
Inspect

Retrieve full detail of a workout session: exercises, sets, reps, weights, superset groupings, heart points, notes, and NSI scoring at every grain. Use for detailed questions about a past workout, reviewing training before recommendations, confirming what was logged, or comparing a session to population strength standards.

NSI: session NSI/rating in the header; per-exercise NSI (max set NSI), rating, est. 1RM, and the population_1rm_lb/population_reps benchmark it was measured against; per-set NSI and est. 1RM to see which set drove the exercise score.

EQUIPMENT: shown per exercise when every set shares a tag, else per set; missing means untagged. A wrong or missing tag on a dumbbell exercise silently halves or doubles its NSI score — fix it via update_workout's set_updates or add_exercises equipment field.

REQUIRED WORKFLOW: call list_workouts first to find the session ID — never guess it.

SAVED WORKOUTS: pass saved_workout_id to read a reusable Saved Workout prescription. Do not combine it with session_id/session_date.

Inputs: session_id (required), saved_workout_id. Returns: result

list_blog_postsA
Read-onlyIdempotent
Inspect

Search the public Crew Blog at /blog for advisor-authored daily posts. Only call when the user explicitly asks about the blog or what an advisor has written; don't volunteer posts in normal conversation.

Returns each matching post's slug, title, summary, advisor name, and date. Link a post inline as /blog/.

Inputs: limit, query, advisor_slug. Returns: result

list_body_metricsA
Read-onlyIdempotent
Inspect

List body composition entries within a date range. Use when the user asks about their weight history, body fat trend, or any body metrics over time.

Maximum range: 31 days per call. For longer periods, make multiple calls with sequential date ranges.

INFER — do not ask:

  • start_date: default to 30 days ago

  • end_date: default to today

BMI in the output is derived from the user's canonical height and that day's resolved weight -- do not recompute it yourself.

Inputs: end_date, start_date. Returns: result

list_cycleA
Read-onlyIdempotent
Inspect

List the user's logged period records within a date range. update_cycle and delete_cycle can resolve a record on their own from date, so this is no longer required before either — use it when the user asks about their cycle history, or get an id after an ambiguous update_cycle/delete_cycle match.

INFER — do not ask:

  • start_date: default to 6 months ago

  • end_date: default to today

Inputs: end_date, start_date. Returns: result

list_exercisesA
Read-onlyIdempotent
Inspect

Returns all canonical exercise names from the exercise library, grouped by muscle group. Call this before log_workout or update_workout to match user-described exercise names to canonical ones. Canonical names ensure proper exercise tracking and NSI score calculation.

Inputs: no named parameters. Returns: result

list_goalsA
Read-onlyIdempotent
Inspect

Analyze or show the user's current and past goals. Returns active/paused formal goals, completed/historical formal goals, and current standard targets.

Use this when the user asks what goals they have or asks to review/analyze their goals. Pass include_capabilities: true ONLY when the user asks what kinds of goals Wellness Project supports; it appends the full catalog of goal types and their inputs, which is large. Do not call this tool merely to obtain an ID before create_goal or update_goal; those write tools resolve current goals themselves.

Inputs: include_capabilities. Returns: result

list_hydrationA
Read-onlyIdempotent
Inspect

Review hydration events and stored effective hydration totals. Use when the user explicitly asks about hydration history or fluid intake. Hydration tracking must already be enabled in Settings. Maximum range 31 days. Defaults to the last 7 days.

Inputs: end_date, start_date. Returns: result

list_injuriesA
Read-onlyIdempotent
Inspect

List injuries from the injury log. update_injury and delete_injury can resolve an injury on their own from injury (+ optional date), so this is no longer required before either — use it to review the injury log, answer questions about injury history or rehab progress, or get an id after an ambiguous update_injury/delete_injury match. Defaults to active and monitoring injuries.

INFER — do not ask:

  • status: default to showing Active and Monitoring; use 'all' to include Resolved; use 'Resolved' for history only.

Inputs: status. Returns: result

list_lab_markersA
Read-onlyIdempotent
Inspect

Returns all LOINC-coded markers in the reference library: canonical name, LOINC code, panel, typical unit, and common aliases. Call this BEFORE log_lab_results to match user-provided marker names to canonical entries — same pattern as list_exercises for workouts. Prevents name drift and ensures trending works across lab visits.

Inputs: no named parameters. Returns: result

list_lab_resultsA
Read-onlyIdempotent
Inspect

List lab/biomarker results within a date range, including each result's ID. update_lab_result and delete_lab_result can resolve a result on their own from date (+ optional marker or panel_name), so this is no longer required before either — use it to review lab history, answer questions about blood work trends or specific marker values over time, or get an id after an ambiguous update_lab_result/delete_lab_result match. Optionally filter by panel or marker name.

INFER — do not ask:

  • start_date: default to 365 days ago (labs are infrequent)

  • end_date: default to today

Inputs: end_date, panel_name, start_date, marker_name. Returns: result

list_mealsA
Read-onlyIdempotent
Inspect

List all meals logged for a date or date range, including each meal's ID, date, type, food description, and macros. update_meal and delete_meal can resolve a meal on their own from date (+ optional name substring), so this is no longer required before either — use it to answer "what did I eat today/this week/yesterday?", review what has been logged, or get an id after an ambiguous update_meal/delete_meal match.

Maximum range: 31 days per call. For longer periods, make multiple calls with sequential date ranges.

INFER — do not ask:

  • date: default to today

  • end_date: if the user asks about a week or range, set end_date to cover the full period (e.g. "this week" → date=Monday, end_date=today; "last 7 days" → date=7 days ago, end_date=today). For a single day, omit end_date.

Inputs: date, end_date. Returns: result

list_personal_contextA
Read-onlyIdempotent
Inspect

List the user's active Personal Context memories: durable circumstances and preferences remembered across conversations (e.g. travels most weeks, gym has no squat rack, trains early mornings, wants blunt feedback). Use when the user asks what has been remembered about them, or before proposing a new memory to check whether an existing one already covers the subject. Read-only.

Inputs: no named parameters. Returns: result

list_recovery_sessionsA
Read-onlyIdempotent
Inspect

List logged recovery sessions (completions and skips) within a date range, each with its ID. list_recovery_strategies only returns the recurring strategies (the schedule), never the individual logged entries against them — this is the only way to see those.

update_recovery_session and delete_recovery_session can resolve a session on their own from session_date (+ optional session_category), so this is no longer required before either — use it to answer "what recovery sessions have I logged", audit/spot-check past entries (e.g. a sauna and a cold plunge logged separately on the same day that should have been one contrast_therapy entry), or get an id after an ambiguous update_recovery_session/delete_recovery_session match.

INFER — do not ask:

  • start_date / end_date: default to the last 30 days. Widen the range yourself for an older lookup instead of asking the user for exact dates.

  • category: omit to return every category.

Maximum range: 90 days per call. To audit or correct a longer history, make multiple sequential calls walking backwards (days 0-90, then 90-180, then 180-270...) until you have covered the period the user means. Don't stop after one call and report that as the whole history.

Inputs: limit, category, end_date, start_date. Returns: result

list_recovery_strategiesA
Read-onlyIdempotent
Inspect

List the user's recovery and mindfulness strategies. Use when the user asks about their recovery practices, mindfulness routines, or you need strategy IDs before logging a session.

INFER — do not ask:

  • filter: default to 'active'; use 'all' for history; use 'historical' for ended strategies only.

Returns each strategy's id, name, category, schedule, start_date, and end_date.

Inputs: filter. Returns: result

list_rest_daysA
Read-onlyIdempotent
Inspect

List the dates a user has marked as rest days within a range. Use when the user asks about their rest pattern ("how many rest days have I taken this month?", "did I rest last week?").

INFER — do not ask:

  • start_date: default to 30 days ago

  • end_date: default to today

Inputs: end_date, start_date. Returns: result

list_runsA
Read-onlyIdempotent
Inspect

List runs within a date range. Returns a compact Runner State summary first, then individual runs. This is the preferred single read for Elias: current-week volume, four-week baseline, longest run, confirmed easy/quality mix, unclassified mileage, pace trend, heart points and available HR are computed together rather than pieced together from several calls.

Maximum range: 92 days. Defaults to 7 days ago through today. For a longer span, make several calls covering consecutive windows.

Inputs: end_date, start_date. Returns: result

list_sleepA
Read-onlyIdempotent
Inspect

List sleep log entries within a date range. Each entry includes total duration, sleep score, stage breakdown, and the canonical bedtime and wake_time (full ISO 8601 timestamps with preserved timezone offset) for the user's primary overnight sleep session (excluding daytime naps).

Maximum range: 31 days per call. For longer periods, make multiple calls with sequential date ranges.

INFER — do not ask:

  • start_date: default to 14 days ago

  • end_date: default to today

Inputs: end_date, start_date. Returns: result

list_supplementsA
Read-onlyIdempotent
Inspect

List the user's medications and supplements. manage_supplement can resolve an item on its own from supplement_name, so this is no longer required before it — use it when the user asks what medications or supplements they're taking, asks to review their stack, or to get an id after an ambiguous manage_supplement match.

INFER — do not ask:

  • filter: default to 'active' (current items); use 'all' if the user asks about history or a specific past period; use 'historical' for ended items only.

  • category: omit to return both medications and supplements; set to 'medication' or 'supplement' to filter by type.

Returns each item's id, category, name, brand, dose, schedule, start_date, and end_date.

Inputs: filter, category. Returns: result

list_wearable_dataA
Read-onlyIdempotent
Inspect

List daily wearable data (steps, RHR, HRV, Zone Minutes / AZM including the vigorous-intensity breakdown, VO2max, calories eaten / dietary energy, calories burned / active energy / total energy expenditure, maintenance calories / TDEE, stress, and physiological vital signs reported by connected sources or manual overrides) within a date range. Use when the user asks about their step count, heart rate, HRV trends, vigorous minutes, calories eaten / dietary energy, calories burned, active or total energy expenditure, maintenance calories, TDEE, cardio fitness, blood glucose, vital signs, or any wearable metrics over time.

Zone Minutes (a.k.a. Active Zone Minutes) are shown as a daily total plus, when the per-zone breakdown is available, a moderate (1 pt/min) vs vigorous (2 pts/min — Cardio + Peak zones) split. The zone boundaries are personalized to the user's own resting and maximum heart rate, so they are not a fixed BPM.

Calories burned per day shows active + resting where both are known; when a device reports active energy with no resting figure, a resting estimate is derived from the user's profile BMR and labelled an estimate, never shown as measured. A trailing Maintenance (TDEE) line reports current maintenance calories and which method produced it (formula estimate vs. logged weight trend), or names the missing profile fields when TDEE can't be computed.

Maximum range: 31 days per call. For longer periods, make multiple calls with sequential date ranges.

INFER — do not ask:

  • start_date: default to 14 days ago

  • end_date: default to today

Inputs: end_date, start_date. Returns: result

list_wellbeingA
Read-onlyIdempotent
Inspect

List wellbeing log entries within a date range. update_wellbeing and delete_wellbeing can resolve an entry on their own from date, so this is no longer required before either — use it to answer questions about mood, energy, stress, or soreness trends over time, or get an id after an ambiguous update_wellbeing/delete_wellbeing match.

Maximum range: 31 days per call. For longer periods, make multiple calls with sequential date ranges.

INFER — do not ask:

  • start_date: default to 14 days ago

  • end_date: default to today

Inputs: end_date, start_date. Returns: result

list_workoutsA
Read-onlyIdempotent
Inspect

List workout sessions in a date range: ID, date, focus type, location, and session-level NSI with rating. Use before get_workout to find a session ID, or to answer "how many times did I train this week?", "when was my last leg day?", "did I work out yesterday?", "how is my NSI trending?".

Each row's NSI is the mean of per-exercise NSIs (after dropping anything below 50% of the user's median for that exercise), with a rating band (Below Average, Novice, Average, Intermediate, Advanced, Elite). 100 = the population intermediate standard for the user's bodyweight, age, and sex. Use the rolling average across rows for trend questions.

Maximum range: 90 days per call. For longer periods (PR lookups, "have I ever done X", "when was the last time I did Y"), make multiple sequential calls walking backwards (days 0-89, then 90-179, then 180-269...) until you find what you need. Don't give up after one call.

INFER — default start_date to 7 days ago, end_date to today. Widen up to 90 days for trend questions. Chain calls for anything older.

SAVED WORKOUTS: set saved_workouts=true to list the user's reusable Saved Workouts library instead of completed workout history. Saved workout IDs are separate from workout session IDs.

Inputs: end_date, start_date, saved_workouts. Returns: result

log_body_metricsAInspect

UNIT INPUTS: never convert units yourself. Pass the user's number for a _lb / _mi / _in field exactly as stated, and when they gave kg / km / cm set input_weight_unit / input_distance_unit / input_length_unit in that same object. Omit the companion when the number is already lb / mi / in. The tool converts once before storage, so this overrides any wording that asks you to do the arithmetic.

Log or update body composition metrics for a given date. Use when the user shares weight, body fat percentage, or any other body composition reading — whether typed manually, copy-pasted from a smart scale app, or described from a photo of a scale display.

PROACTIVE DATA COLLECTION: If the user hasn't shared their data yet, ask them to copy-paste the output from their scale app or upload a photo of the display — this lets you parse all fields at once instead of asking one by one.

INFER — do not ask:

  • date: default to today; infer from context ("this morning", "yesterday")

  • derived fields (lean_mass_lb, fat_mass_lb): calculate from weight and body fat % if possible — lean = weight × (1 - bf%/100), fat = weight × bf%/100

The *_pct fields are percentages 0-100. The *_in fields are manual tape measurements, not bioimpedance scale readings.

BMI is not a field here. It is derived automatically at read time from the user's canonical height and their resolved weight for the day -- never ask the user for BMI, and never try to log it.

Every field except date is optional; log any subset. One row per day. Calling this tool twice on the same date updates the existing entry (upsert).

Inputs: date (required), notes, hips_in, chest_in, +19 more. Returns: result

log_cycleAInspect

Log a period to the user's cycle log. Handles all cases:

  • Starting a period today: "my period started today"

  • Backfilling a past period: "my period started May 3rd and ended May 8th"

  • Resuming a period ended today: "actually I'm still on my period" — detects that today's period was marked ended and reopens it

  • Logging just a start with no end yet: "I just got my period"

Before logging, check that cycle tracking is enabled (cycle_prefs.tracking_enabled AND consented_at, both required -- a user can have consented in the past and later turned tracking off). If not, tell the user to turn it on from the dashboard first.

INFER — do not ask:

  • started_on: default to today for current-period statements

  • ended_on: omit unless the user says it ended; infer from context ("5-day period starting May 3" → ended_on May 7)

Do NOT use this tool to log future dates.

Inputs: started_on (required), ended_on. Returns: result

log_injuryAInspect

Log a new injury or aggravation. Use when the user mentions getting hurt, feeling pain, straining something, or describes an injury. Injuries are date ranges — they start on a date and are ongoing until an end_date is set.

INFER — do not ask:

  • start_date: default to today

  • severity: estimate from description (minor twinge=2-3, moderate pain=5-6, severe/acute=8-9)

  • status: default to 'Active' for new injuries

  • affected_movements: infer from body part and injury type (e.g. shoulder strain → pressing, overhead)

  • side: infer from description if mentioned (e.g. "right shoulder" → Right)

ASK only if body_part is entirely unclear.

Inputs: severity (required), body_part (required), injury_type (required), side, +5 more. Returns: result

log_lab_resultsAInspect

Log one or more blood test or biomarker results. Use when the user shares lab values — copy-pasted from a Quest/LabCorp PDF, typed from a paper report, or described from a photo of their results.

GLUCOSE ROUTING: use this tool for glucose only when it is an actual lab/blood-draw result or part of a reported lab panel. Finger-stick, CGM, home meter, wearable, Apple Health, or Health Connect glucose — including a manual correction to daily glucose — belongs in log_wearable as blood_glucose_mg_dl, not here.

REQUIRED WORKFLOW: 1) call list_lab_markers for canonical names and LOINC codes. 2) for each marker the user provides, find the best match and use its canonical marker_name and loinc_code. 3) if no match exists, use the name as stated and omit loinc_code.

If the user says they have lab results but hasn't shared them, prompt: "You can paste the text from your lab report PDF, or upload a photo of the results page — I'll parse all the values at once."

INFER — do not ask: date (look for a collection/drawn date in the pasted text, default today), panel_name (from list_lab_markers for matched markers, infer for unmatched), flag (extract from the report if present: "H", "L", "HH", "LL", "A"), ref_range_low/high (parse from the report if shown), lab_name (from the report header, same for all markers in a visit).

Submit all markers from a single lab visit in one call.

Inputs: results (required). Returns: result

log_mealAInspect

Log a meal to the user's food diary. Use when the user mentions eating, describes a meal, or asks to log food.

INFER:

  • date: today, or from context ("yesterday", "last night")

  • meal_type: canonical time mapping (00-05 Snack, 05-10 Breakfast, 10-14 Lunch, 14-17 Snack, 17-22 Dinner, 22-24 Snack); context overrides ("post-workout shake"=Post-Workout)

MACRO SOURCE: strongest evidence wins. Never replace known stored macros with a fresh estimate.

  1. REPEATS: if the user refers to a previously logged item ("same", "another", "more", "again", or equivalent in any language), call list_meals for the referenced date/range first. If one row unambiguously matches, reuse its stored calories/protein_g/fat_g/carbs_g/alcohol_g and scale by the quantity ratio when the row's quantity is known. If the match or quantity is ambiguous, ask instead of re-estimating. If nothing matches, continue below.

  2. SAVED RECIPES: if the user says the food is saved/usual, pass recipe_name. It supplies stored food and macros; explicit fields override them. Relay no-match/ambiguous errors instead of guessing. If the recipe reports missing macros, estimate only those fields and retry. If food_items adds food beyond the recipe, pass all four macros as the combined total.

  3. BRAND NAMES: for a branded, restaurant, or specific product, use published macros for the stated size/variant before a generic estimate.

  4. Otherwise estimate calories, protein_g, fat_g, carbs_g from the food description. Never ask the user for macros.

MACROS: food_items plus calories/protein_g/fat_g/carbs_g are required unless recipe_name supplies them. Ask only if food_items are absent and no recipe_name applies. Never call without all four macros populated.

FASTING: if the user ate nothing / fasted all day, log one "Fast day" Snack with calories/protein_g/fat_g/carbs_g all 0.

DUPLICATES: if this tool returns a duplicate error, tell the user what's already logged and ask whether this is a separate serving (retry with force=true) or should update the existing entry instead (update_meal with adjusted values).

DRINKS / HYDRATION: this is the single write path for consumed drinks too. When a drink amount is known or reasonably inferable, include it in fluids even when the same drink also contributes calories/macros/alcohol. The server decides whether hydration tracking is enabled; never use a separate hydration write tool. A plain fluid-only intake may omit food_items and macros and send only fluids. For alcoholic drinks, include that drink's alcohol_g in its fluid item; if there is exactly one drink, the top-level alcohol_g can stand in.

Inputs: meal_type (required), date, fat_g, force, +7 more. Returns: result

log_recovery_sessionAInspect

Log a completed or skipped recovery/mindfulness session. Use when the user says they did (or skipped) a breathing exercise, meditation, cold plunge, sauna, stretching, or any recovery practice. Also use for one-off standalone sessions not linked to a recurring strategy.

INFER — do not ask:

  • date: default to today

  • category: infer from the practice name

  • strategy_name: use the strategy name if linked, or the user's description

  • duration_minutes: infer if mentioned (omit for skipped sessions)

  • quality: only include if the user rates it (1-5 scale)

  • skipped: true when the user says they skipped, missed, or didn't do a session; false (default) for completed sessions

PREFERRED WORKFLOW: call list_recovery_strategies first to link the session to an active strategy for adherence tracking. If no matching strategy exists, log as standalone.

Inputs: category (required), strategy_name (required), date, notes, +4 more. Returns: result

log_rest_dayAInspect

Mark a date as an intentional rest day. Use when the user says they took a rest day, are taking one today, or wants to mark a past day as rest after the fact (e.g. "this past Monday was a rest day", "today is a rest day", "I rested yesterday"). Suppresses the workout-prompt nudges for that date and lets the engine treat the day as planned, not skipped.

INFER — do not ask:

  • date: parse the user's reference. "today" = today, "yesterday" = today minus 1, "last Monday" = the most recent Monday before today, etc. Default to today when nothing is specified.

Idempotent — calling twice on the same date is a no-op (the second call returns the same confirmation). To remove a rest day, use cancel_rest_day.

Inputs: date. Returns: result

log_runAInspect

UNIT INPUTS: never convert units yourself. Pass the user's number for a _lb / _mi / _in field exactly as stated, and when they gave kg / km / cm set input_weight_unit / input_distance_unit / input_length_unit in that same object. Omit the companion when the number is already lb / mi / in. The tool converts once before storage, so this overrides any wording that asks you to do the arithmetic.

Create an editable running card. Use for a completed run OR a future run plan.

intent:

  • log (default): the run happened. date, distance_mi and duration_sec are required. This writes the completed run and returns a card marker for in-app editing.

  • plan: the run has NOT happened yet. Create a planned run card. Never put a future run in completed history.

RUN TYPE: distinguish easy, long, tempo, interval, recovery, race, fartlek, threshold, progression and hills when the runner or workout structure supports it. If a wearable run is unspecified, do NOT call it easy merely because it was a run.

DETAIL: preserve elapsed time, HR, cadence, power, elevation, RPE, splits and structured segments only when supplied by the user/source. Never invent sensor data or splits.

Inputs: intent (required), rpe, date, notes, +15 more. Returns: result

log_sleepAInspect

Log a sleep entry. Use when the user shares sleep data — total duration, score, stage breakdown, bedtime, or wake time — from Fitbit, Oura, Whoop, Apple Health, or manual recall.

PROACTIVE DATA COLLECTION: If the user says they want to log sleep but hasn't shared numbers, ask: "How many hours did you sleep, and do you have a sleep score or stage breakdown from your tracker?" They can paste or describe the summary screen.

INFER — do not ask:

  • date: date the primary sleep session ended / wake date (night ending on this date); default to today

You may log any subset of fields. One row per day. Calling this tool twice on the same date updates the existing entry (upsert). Entries made through this tool are always tagged as manual — the wearable-provider sources (Fitbit/Oura/Apple Health) are reserved for the actual auto-sync pipelines.

Inputs: date (required), bedtime, wake_time, awakenings, +5 more. Returns: result

log_supplement_takenAInspect

Mark a medication or supplement as taken or not taken for a specific date. Only relevant when the user has daily tracking mode enabled. Use when the user says they took (or missed) a medication or supplement on a particular day.

INFER — do not ask:

  • date: default to today

  • taken: default to true (marking as taken)

SELECTOR — pass supplement_id if known, or supplement_name (case-insensitive substring) to resolve it. Exactly one required. If supplement_name matches more than one item, the call errors with candidate IDs to retry with.

Inputs: date, notes, taken, supplement_id, +1 more. Returns: result

log_wearableAInspect

Log daily wearable/manual health metrics (RHR, HRV, Zone Minutes / AZM, VO2max, calories eaten / dietary energy, stress, supplemental steps, and physiological vitals including SpO₂, respiratory rate, skin temperature, blood pressure, blood glucose, and core temperature).

VITALS — use the vital fields for manual/home/device readings and corrections, including a finger-stick, CGM, home glucose meter, or wearable/Apple Health/Health Connect value the user explicitly wants stored manually. A glucose value from an actual lab report or blood draw belongs in log_lab_results instead, not here.

STEPS — read before using step_count: manual step_count is ADDITIVE — it adds on top of whatever a connected wearable (Fitbit, Oura, Apple Health, Health Connect) already recorded that day; it never replaces or overrides device data. Only use it when the user explicitly says they walked steps their device did NOT capture (phone left home, battery died, device not worn). If the user says sync is wrong, steps look doubled, or they want to fix/override/replace device data: do NOT pass step_count — explain that manual steps add on top, and sync issues need investigating at the device level.

ALL OTHER FIELDS (RHR, HRV, AZM, VO2max, stress, and physiological vitals) replace the existing manual value for that day and are safe to use for corrections.

INFER — do not ask: date defaults to today unless the user says otherwise.

IDEMPOTENT: if the values you'd log already exist for that date (any source), the tool returns a no-op success — report this as "already had data", not "failed".

Inputs: date (required), resting_hr, step_count, hrv_morning, +13 more. Returns: result

log_wellbeingAInspect

Log subjective wellbeing ratings for a day, week, month, or custom date range. Use when the user describes how they feel — energy level, mood, stress, or muscle soreness.

Supports single-day entries ("how I feel today") and period entries ("this week was stressful", "March was great").

If an overlapping entry already exists for the requested period, returns a warning with the conflicting entry IDs — the user must update or delete existing entries first.

INFER — do not ask:

  • period_start: default to today

  • period_end: default to same as period_start (single day). For "this week" use Monday–Sunday, for "this month" use first–last day.

  • ratings: estimate from description ("exhausted"=2, "great energy"=8, "stressed out"=8 stress, "feeling good"=7 mood)

You may log any subset of rating fields.

Inputs: mood, notes, energy, stress, +3 more. Returns: result

log_workoutA
Destructive
Inspect

UNIT INPUTS: never convert units yourself. Pass the user's number for a _lb / _mi / _in field exactly as stated, and when they gave kg / km / cm set input_weight_unit / input_distance_unit / input_length_unit in that same object. Omit the companion when the number is already lb / mi / in. The tool converts once before storage, so this overrides any wording that asks you to do the arithmetic.

Log a complete workout session: exercises, sets, reps, weights, and session metadata. Use when the user describes finishing a workout, lists exercises performed, or asks to log training. A workout they have not done yet is not a log: use propose_workout for that.

EXERCISE NAMES:

  • Call list_exercises first; match each exercise to the closest canonical name. No reasonable match → use the name as stated. Don't ask before logging, match silently and log.

  • "Chest press" (machine) and "bench press" (barbell) are DISTINCT — pass the user's term through so the resolver's aliases pin the right one.

  • name is ONLY the exercise name, never reps/weights/sets — those go in the sets array.

  • LITERAL NAME: literal_name: true keeps the user's exact wording instead of the closest library match, skips the resolver, and gets no NSI score (no benchmark to compare an unmatched name against). Use for "call it exactly X", "not the standard one", "literally X", or a rejected match.

  • The result says when a name was matched to something other than what the user said. Relay it in your own words rather than repeating the line verbatim. If a name matches nothing closely enough, the result names near-miss library exercises; ask the user which they meant rather than accept the unscored custom log silently.

  • EQUIPMENT (load basis): dumbbell_pair is one dumbbell in EACH hand, weight_lb PER HAND (2x for NSI); dumbbell_single is one implement total. Laterality (single-leg/arm) does NOT decide this alone. Set it when the user describes the load (each hand, machine, band); a wrong or missing tag silently halves or doubles NSI. Values: barbell, dumbbell_pair, dumbbell_single, machine, kettlebell, bodyweight, band, cable, trx, other.

SETS:

  • "3 sets of 15 reps" → 3 set objects with reps: 15. "15/12/10" → 3 sets with reps 15, 12, 10.

  • Pure isometric holds (planks, dead hangs, wall sits) have no reps: "30 second plank" = { hold_length_sec: 30 }.

  • Tempo/pause work combines reps + weight_lb + hold_length_sec (seconds per rep) on the same set, never in notes.

  • Loaded carries (farmers carry, sled push, weighted plank) are one set per trip: hold_length_sec + weight_lb, omit reps unless a trip count is given. weight_lb is PER HAND for a two-implement carry, TOTAL for one implement. Distance has no column and is never a duration — put it in notes.

INFER — do not ask:

  • date: today, or from context

  • focus_type: from the exercises (bench/shoulders/triceps=Push, rows/pulldowns/curls=Pull, squats/deadlifts/lunges=Legs, mixed upper=Upper, everything=Full Body)

  • is_bodyweight: true for pull-ups, push-ups, dips, bodyweight squats

  • superset_group: same integer for exercises done back-to-back or as a superset

  • slot_type: 'warmup' for prep at the start, 'finisher' for burnout/cardio at the end, 'working' (default) otherwise

RPE (Rate of Perceived Exertion) — 1-10 scale, half steps allowed (7.5, 8.5):

  • Session-level RPE: overall session difficulty. Infer from user comments like "brutal session" (8-9) or "easy day" (3-4). Optional.

  • Per-set RPE: how hard each individual set felt. Include only if the user explicitly mentions per-set effort or failure. Optional.

  • Scale: 1=minimal effort, 5=moderate, 7=hard, 8=few reps left, 9=one rep left, 10=maximal/failure.

ASK (single batched question) only if missing and not inferable: location, focus_type (list ambiguous), heart_points (tracker provides them but not mentioned).

RETURNS the new session's ID (as "[ID NN]"). Pass it to update_workout / delete_workout / get_workout / add_exercises for follow-ups in this conversation.

SAVED WORKOUT MODE: when the user asks to save a workout for reuse, set save_as_saved_workout=true and pass the full prescription through this same tool. In saved mode the workout is NOT logged as completed history. To replace an existing Saved Workout, also pass saved_workout_id; the supplied prescription fully replaces its prior prescribed sets/reps/weights. Use saved_workout_title when the reusable name should differ from focus_type.

Inputs: date (required), exercises (required), rpe, notes, +7 more. Returns: result

manage_recovery_strategyA
Destructive
Inspect

Add, update, end, or delete a recovery/mindfulness strategy. Use when the user describes a new practice, changes a schedule, stops a practice, or removes one. Infer category from name, start_date defaults to today, infer schedule from context. ASK only if name is missing.

SELECTOR for update/end/delete — pass id if known, or strategy_name (case-insensitive substring, e.g. "sauna") to resolve it. Exactly one of id or strategy_name required. If strategy_name matches more than one strategy, the call errors with candidate IDs to retry with.

AFTER a successful 'add': do NOT just confirm and stop. Reply by (1) restating the assumed schedule (sessions per period, duration, time of day, start date) in plain language, and (2) asking the user to confirm or correct it — especially any optional fields you did NOT set (duration_minutes, time_of_day). Example: "Logged sauna starting today, assuming once per week. Sound right? About how long do you usually go for, and what time of day — morning, evening?" If the user corrects anything, call this tool again with action='update'. The goal is accurate adherence data, not a silent confirmation.

Inputs: action (required), id, name, notes, +8 more. Returns: result

manage_supplementA
Destructive
Inspect

Add, update, end, or delete a medication or supplement. Use when the user describes their stack, adds a new item, changes a dose or schedule, says they stopped taking something, or wants to remove an entry.

INFER — do not ask:

  • action: 'add' for a new item, 'update' for changing a field, 'end' when they stopped/finished a course, 'delete' only to remove the record entirely

  • category: 'medication' for prescription/OTC drugs and pharmaceuticals, 'supplement' for vitamins/minerals/herbs/other dietary supplements — default 'supplement' if unclear

  • start_date: today for new entries

  • end_date (for 'end'): today unless the user specifies otherwise

ASK the user only if name is missing for a new entry, or 'end' (set end_date) vs 'delete' (remove record) intent is ambiguous.

SELECTOR for 'update', 'end', 'delete' — pass id if known, or supplement_name (case-insensitive substring, e.g. "magnesium") to resolve it. Exactly one of id or supplement_name required. If supplement_name matches more than one item, the call errors with candidate IDs to retry with.

Inputs: action (required), id, form, name, +14 more. Returns: result

mark_empty_dayA
DestructiveIdempotent
Inspect

Set, change, or undo the answer to "why is this day empty?" for a date with no real meals logged. Use when the user wants to flip a fast day to forgotten (or back), or undo either one, in chat instead of the in-app prompt.

There are exactly three states for a date, and this tool is the only way to move between them:

  • fast: writes the 0-kcal "Fast day" food_log entry (a real, counted 0-calorie day).

  • forgot: records that the day was reviewed and simply not logged. Writes nothing to food_log, so the day stays a true blank and is excluded from calorie/TDEE averages, never imputed as 0.

  • unanswered: clears both. The day goes back to being an open question and the in-app prompt may ask about it again.

Setting one answer always clears the other, so a date is never both a fast and a forgotten day at once.

Use list_meals first if unsure whether the date already has real food logged. This tool refuses to touch a day that has actual meals on it (other than an existing fast marker).

Inputs: date (required), answer (required). Returns: result

show_body_compositionA
Read-onlyIdempotent
Inspect

Show body composition over time with an interactive metric picker for weight, body fat, lean and muscle mass, hydration, visceral fat, BMI, waist, and related scale metrics. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_body_weightA
Read-onlyIdempotent
Inspect

Show the user their body weight (and body-fat %) trend over time as an interactive line chart with a 30/90-day/1-year range toggle. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_exercise_progressionA
Read-onlyIdempotent
Inspect

Show the user's estimated 1-rep-max progression for a lift over time as an interactive line chart, with filters for date range and muscle group, and an exercise picker. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range, exercise, muscle_group. Returns: kind, generatedAt

show_health_overviewA
Read-onlyIdempotent
Inspect

Show a rich overview of wearable health signals including steps, Zone Minutes, resting heart rate, HRV, VO2max, and stress. Prefer this for broad wearable or overall health-trend questions. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_meal_diaryA
Read-onlyIdempotent
Inspect

Show the meals logged on a day as a rich diary with daily calories and macros versus targets. Prefer this for what-did-I-eat and daily food-log review questions. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: date. Returns: kind, generatedAt

show_recoveryA
Read-onlyIdempotent
Inspect

Show the user their resting heart rate and HRV recovery trend over time as an interactive dual-line chart with a 30/90-day/1-year range toggle. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_runsA
Read-onlyIdempotent
Inspect

Show the user their running mileage over the last 14 days as an inline bar chart. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_sleep_detailA
Read-onlyIdempotent
Inspect

Show one night of sleep in detail with duration, score, stages, bedtime, wake time, awakenings, and recent-night context. Prefer this for last-night or specific-night sleep questions. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: date. Returns: kind, generatedAt

show_week_fit_scoreA
Read-onlyIdempotent
Inspect

Show the user their current Fit Score (the app's 0-100 composite), how it breaks down across its six components (Train, Fuel, Sleep, Recovery, Steps, Wellbeing), and the past 7 days of daily scores, as one inline card. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_week_macrosA
Read-onlyIdempotent
Inspect

Show the user their past 7 days of calories and macros (protein, carbs, fat) vs targets as an inline chart. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_week_sleepA
Read-onlyIdempotent
Inspect

Show the user their past 7 days of sleep (hours per night and sleep score) as an inline chart. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_week_stepsA
Read-onlyIdempotent
Inspect

Show the user their past 7 days of step counts vs their daily goal as an inline chart. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_week_workoutsA
Read-onlyIdempotent
Inspect

Show the user their past 7 days of workouts (heart points per day, days trained) as an inline chart. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_wellbeingA
Read-onlyIdempotent
Inspect

Show energy, mood, stress, and soreness together with recent context and an overall wellbeing trend. Prefer this for how-I-have-been-feeling and subjective recovery questions. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: range. Returns: kind, generatedAt

show_workoutA
Read-onlyIdempotent
Inspect

Show a single logged workout session's exercises and sets as an inline card. Defaults to the most recent workout; can target a specific date. When the user asks about this, prefer calling this tool and rendering the interactive MCP app over describing the underlying rows in text. Returns a short text summary alongside the visual view.

Inputs: date. Returns: kind, generatedAt

update_cycleA
Idempotent
Inspect

Update an existing period record. Use to correct dates, add a missing end date, or clear an end date (resume).

Common uses:

  • "my period ended on the 9th not the 8th" → update ended_on

  • "actually my period started the 2nd not the 3rd" → update started_on

  • "I'm still on my period" → clear ended_on (pass null) to reopen it

SELECTOR — pass id if known, or date (the period's start date, or any date that falls within it) to resolve it. Exactly one required. If date matches more than one record, the call errors with candidate IDs to retry with.

Inputs: id, date, ended_on, started_on. Returns: result

update_goalA
Destructive
Inspect

UNIT INPUTS: never convert units yourself. Pass the user's number for a _lb / _mi / _in field exactly as stated, and when they gave kg / km / cm set input_weight_unit / input_distance_unit / input_length_unit in that same object. Omit the companion when the number is already lb / mi / in. The tool converts once before storage, so this overrides any wording that asks you to do the arithmetic.

Change, complete, pause, stop/end, reopen, or delete an existing goal. Call this tool directly for ordinary goal changes. It already loads the user's current goals and resolves a unique goal from goal_id or a natural-language goal_ref, so do NOT call list_goals first just to find an ID.

For edit, pass only the fields to change. For complete/pause/end/reopen/delete, no edit fields are required. If goal_ref genuinely matches multiple goals, this tool returns the candidates and changes nothing. Formal goal end/delete follows the existing Goals UI cancel lifecycle; standard-target end/pause turns that target off while delete removes it.

Inputs: action (required), title, weeks, metric, +27 more. Returns: result

update_injuryA
Idempotent
Inspect

Update an existing injury entry. Use when the user reports an injury is improving, worsening, resolved, or wants to change details. When severity changes, the new value is automatically tracked in the severity history for trend analysis. Only send fields that need to change. Setting end_date automatically marks the injury as Resolved. Use severity_date to backfill historical severity changes (e.g., "it was a 7 in January, dropped to 4 by March").

SELECTOR — pass id if known, or injury (a body part or injury type substring, case-insensitive, e.g. "shoulder") optionally narrowed by date (an injury active on that day). Exactly one of id or injury required. If injury matches more than one entry, the call errors with candidate IDs to retry with.

Inputs: id, date, side, notes, +7 more. Returns: result

update_lab_resultA
Idempotent
Inspect

Update one or more fields on an existing lab result. Use when the user wants to correct a result already logged, most often its collection date. Only send the fields that need to change; omit all others.

SELECTOR, pass exactly one of id, date, or date+marker:

  • id: addresses one marker's row. Any editable field may change.

  • date (optionally narrowed by panel_name): addresses every result from that draw at once. Only new_date, panel_name_new, and lab_name may change this way. result_value, result_unit, marker_name, flag, and notes are per-marker fields and require a single row, so one call can never overwrite every marker in a draw with the same value.

  • date + marker (a marker-name substring, case-insensitive, optionally narrowed by panel_name): resolves to one marker's row, same as id. Errors with candidate IDs if more than one marker on that date matches.

Inputs: id, date, flag, notes, +8 more. Returns: result

update_mealA
DestructiveIdempotent
Inspect

Update an existing meal. Use only when the current message explicitly changes, corrects, or adds to a meal already logged. Never infer an update from earlier chat history. A plain food statement ("coffee with milk") is a new entry: use log_meal, even if that meal type already exists today.

FIND THE MEAL: use id if known. Otherwise use date (YYYY-MM-DD, defaults to today) plus name and/or target_meal_type to narrow the existing row. target_meal_type finds the current type and is never written; meal_type sets a new type. If the match is not exactly one row, nothing changes. On multiple matches, ask the user which meal they mean; never select a candidate id yourself. Send only fields that change.

THREE MODES. Picking the wrong one corrupts the meal.

  1. ADD SAVED FOOD -> add_recipe_name. "add my usual kombucha to breakfast", "add the protein shake I saved to lunch". Do NOT use log_meal for this, that logs a second, separate meal. Additive: the recipe's food text is appended to the meal's existing food_items and each of its macros is ADDED to the meal's current value for that field, so the result is both foods together with both foods' calories, not a replacement. Matched the same way as log_meal's recipe_name (case-insensitive exact title, then substring); no match or more than one substring match throws an error naming the candidates or the user's saved titles instead of guessing. If the matched recipe has no stored value for one of calories/protein_g/fat_g/carbs_g, this throws carrying the recipe's food text: estimate just the missing field(s) and call again with the same id (or date+name) and add_recipe_name plus those field(s) set explicitly. An explicit field passed alongside add_recipe_name takes the recipe's place for that one field and is still ADDED to the meal; it does not overwrite the meal's total the way it does without add_recipe_name.

  2. ADD UNSAVED FOOD -> add_food_items. "add a banana to my breakfast", "I also had a small coffee", where the extra food is not one of the user's saved recipes. Pass the new food's own description plus calories/protein_g/fat_g/carbs_g estimated for JUST that new food, not the meal's new total and not the existing food's macros. All four are required whenever add_food_items is set (there is no recipe to fall back on): estimate them from the description, never ask the user. Additive exactly like add_recipe_name: add_food_items is appended to the existing food_items (unless food_items is ALSO passed explicitly, which replaces the description outright instead of appending) and each macro is ADDED to the meal's current value; alcohol_g is optional and adds nothing when omitted. add_food_items and add_recipe_name are mutually exclusive: never set both in the same call. Adding both a saved recipe and separate ad-hoc food means two update_meal calls, one per addition.

  3. CORRECT A VALUE -> plain fields, both add_* unset. "that was 400 calories, not 600", "actually it was just eggs, no toast", "make it 500 calories": the meal's stored total needs to become a specific NEW number, not grow. Each of food_items/calories/protein_g/fat_g/carbs_g/alcohol_g you pass REPLACES the meal's current value for that field outright, so send the corrected TOTAL for that field, never an amount to add.

Reaching for mode 3 when the meal is GROWING is the exact bug this tool used to have: it silently REPLACES the whole meal with just the new food and throws away what was already logged.

If add-vs-correct intent is ambiguous, ask before updating.

DRINKS / HYDRATION WHEN UPDATING: a food update must not silently erase an already-linked hydration event. For changes unrelated to drinks, omit fluids and the existing hydration is preserved. When ADDING a drink with add_food_items/add_recipe_name, fluids contains only the newly added drink(s) and they are appended to the meal's hydration. When CORRECTING the meal's drinks with both add_* fields omitted, fluids is the complete corrected drink list and replaces the linked hydration only after replacement rows have been safely inserted. If the correction removes every drink, explicitly send fluids: [] and the linked hydration is deleted. Whenever a drink volume is known or reasonably inferable, include it.

Inputs: id, date, name, fat_g, +10 more. Returns: result

update_recovery_sessionA
Idempotent
Inspect

Update one or more fields on an existing recovery session log entry. Use when the user wants to correct or change something already logged (e.g. wrong duration, quality rating, category, or notes). Only send the fields that need to change; omit all others.

SELECTOR — pass id if known, or session_date (+ optional session_category to narrow) to resolve it. Exactly one of id or session_date required. If it matches more than one session, the call errors with candidate IDs to retry with.

Inputs: id, date, notes, quality, +7 more. Returns: result

update_wellbeingA
Idempotent
Inspect

Update an existing wellbeing entry. Only updates fields that are provided — omitted fields remain unchanged.

SELECTOR — pass id if known, or date (any day within the entry's period) to resolve it. Exactly one of id or date required. If date matches more than one entry, the call errors with candidate IDs to retry with.

Inputs: id, date, mood, notes, +3 more. Returns: result

update_workoutA
DestructiveIdempotent
Inspect

UNIT INPUTS: never convert units yourself. Pass the user's number for a _lb / _mi / _in field exactly as stated, and when they gave kg / km / cm set input_weight_unit / input_distance_unit / input_length_unit in that same object. Omit the companion when the number is already lb / mi / in. The tool converts once before storage, so this overrides any wording that asks you to do the arithmetic.

Update a workout session: correct metadata, fix set values, rename/add/remove exercises or individual sets, or move exercises between supersets. Use for any post-log correction.

FIND THE SESSION: pass session_id if already known. Otherwise pass session_date (YYYY-MM-DD, defaults to today) and, only if more than one session was logged that day, name (a substring of the workout's focus/type, case-insensitive) to narrow it down. A match that isn't exactly one session returns an error explaining why, with nothing changed — retry with session_id or a narrower name, never guess. get_workout still gives full detail (exercise names, slot names SS1/SS2/WarmUp/Finisher) when needed; list_exercises first if adding or renaming. Call with only the fields that change — operations can combine in one call.

OPERATIONS:

  • Metadata: date, focus_type, location, notes, rpe, heart_points_moderate/peak.

  • set_updates: patch reps/weight/notes/equipment on a set, addressed by set_id OR by exercise_name + set_position (1-based, matches get_workout's "Set N").

  • remove_sets: delete sets, same set_id-or-exercise_name+set_position addressing; remaining sets renumber; an emptied exercise/slot is removed automatically.

  • rename_exercises: renames every set of an exercise in place (preserves set IDs, RPE, notes; rebuilds NSI), never remove + add.

  • remove_exercises: deletes all sets for named exercises; empty slots removed automatically.

  • add_exercises: new exercises with sets; to_superset_slot joins an existing slot, omit for standalone.

  • move_exercises: reassigns an exercise to a different slot; "new" makes it standalone.

SUPERSET SLOTS: rename_exercises/remove_exercises match by exercise name alone unless scoped. If a name is in more than one slot and the user means only one, pass superset_slot (or { name, superset_slot } for remove_exercises) naming that slot from get_workout. Omitting it hits every occurrence, a real corruption risk.

LITERAL NAME: literal_name: true keeps the user's exact wording instead of the closest library match, skips the resolver, and gets no NSI score (no benchmark to compare an unmatched name against). Use for "call it exactly X", "not the standard one", "literally X", or a rejected match. Applies below.

EQUIPMENT (load basis): dumbbell_pair is one dumbbell in EACH hand, weight_lb PER HAND (2x for NSI); dumbbell_single is one implement total. Laterality (single-leg/arm) does NOT decide this alone. Set it when the user describes the load (each hand, machine, band); a wrong or missing tag silently halves or doubles NSI. Values: barbell, dumbbell_pair, dumbbell_single, machine, kettlebell, bodyweight, band, cable, trx, other.

A set_id or exercise_name+set_position matching more than one set (the same exercise in two superset slots) is ambiguous and errors rather than guessing — use the exact set_id from get_workout to disambiguate.

The result discloses a mismatched name from rename_exercises/add_exercises; relay it in your own words. If a name matches nothing closely enough, the result names near-miss library exercises; ask the user which they meant rather than accept the unscored custom log silently.

INFER — do not ask: session_date defaults to today, set positions count from 1 per exercise. Slot names and set_ids beyond what's inferable come from get_workout; canonical exercise names come from list_exercises.

SAVED WORKOUTS: pass saved_workout_id to edit a reusable Saved Workout instead of completed workout history. Use saved_workout_title and/or saved_exercise_updates. For progression requests, inspect real exercise history first rather than applying a deterministic formula.

Inputs: rpe, date, name, notes, +15 more. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 73 tools

    Disambiguation3/5

    Most tools are organized by clear domain and CRUD pairs, but there is substantial overlap between the 15+ show_* visualization tools and the list_/get_ data tools (e.g., show_meal_diary vs list_meals, show_workout vs get_workout, show_week_sleep vs list_sleep). Additionally, log_meal and mark_empty_day can both create a 'Fast day' entry, creating a real boundary ambiguity. The long descriptions help, but an agent will frequently need to choose between presentational and data-retrieval variants of the same underlying query.

    Naming Consistency4/5

    The set mostly follows a consistent log_/list_/get_/update_/delete_/show_ verb-noun pattern, which makes domains easy to recognize. Deviations exist: manage_supplement and manage_recovery_strategy bundle multiple actions under a vague verb, create_goal appears without a matching create_* family, and add_or_update_personal_context breaks the convention. Overall the naming is predictable and readable despite a few exceptions.

    Tool Count1/5

    73 tools is far beyond the 15-25 range where a single server starts to feel heavy, and it exceeds the 50+ extreme mismatch threshold. The server bundles a dozen-plus domains into one namespace, dramatically increasing selection difficulty for agents. This would be much better factored into domain-specific servers or a smaller set of more polymorphic tools.

    Completeness3/5

    Most domains have solid CRUD/lifecycle coverage: meals, workouts, labs, injuries, wellbeing, recovery sessions, and cycles all support create/read/update/delete. However, there are notable gaps: runs have no update tool (only log/list/delete), sleep/body-metrics/wearable entries have no delete path, and personal context explicitly has no delete capability. These create dead ends for common correction workflows, even though several can be partially worked around via upserts.

    Maintenance

    ActivityMaintained
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      An MCP server that securely syncs and queries your health data from Apple Health, storing it in your own Supabase Postgres database and exposing tools for AI assistants to retrieve weight, calories, macros, and more.
      20 npm
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Self-hosted fitness tracking MCP server that gives AI assistants access to your nutrition, training, weight, sleep, and accomplishment data via 77 tools and 5 resources. Enables natural-language logging and querying of personal health metrics through Claude or ChatGPT.
      62 npm
      1
      BSD 2-Clause "Simplified"