Vitals is this person's health log. You are the parser and Vitals is the ledger: you read the photo or the sentence, and Vitals stores the structured result with full provenance. Call get_health_overview first in any session — it carries their timezone, their targets and a goal note they wrote for you. Everything is metric on the wire: weightKg, energyKcal, distanceM — a display block beside those numbers renders them in the units they prefer. Omit a value you do not know rather than sending 0; null means unknown and 0 means a measured zero, and the difference reaches every daily total. Every logging tool takes a clientRequestId — reuse it verbatim if you retry, and a repeat returns the entry already stored instead of creating a second one. This person has a coaching memory that outlives your session: five short slots for how they want to be spoken to, what motivates them, what they eat, what constrains them, and what has already been tried. get_health_overview returns it; read it and coach in the style it describes. When the conversation teaches you something that will still be true in a month, call update_context — but REWRITE the slot rather than adding to it. Each slot is capped, a write replaces it whole, and keeping it short is the job: it is a note to your successor, not a transcript of this session.
Discoverability
Unverified—6 unverified
Client listings and public setup information.
mcp.json on main domain
A declared HTTPS website is needed to identify the main domain.
How to fix: On each tool, declare annotations.readOnlyHint, annotations.destructiveHint, and annotations.openWorldHint as booleans. The policy review separately assesses whether their values match the tool's actual behavior.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Everything you need to give advice about this person's health, in one call. Call this FIRST, before anything else in a session: it returns their profile (including the timezone every entry is filed against, and a goal note they wrote for you), the daily targets in force, what they have logged so far today, today's energy balance, and their intake, weight and activity trends over the last 7, 30 and 90 days. You should not need a second call to answer "how am I doing". It also returns `context` — what earlier sessions learned about how to coach this person: their preferred tone, what motivates them, injuries and other hard constraints, and what has already been tried. READ IT BEFORE YOU ANSWER, and match it. A slot that is null has never been filled in; if this conversation teaches you something durable, call update_context to leave it for the next session. Null means not recorded, never zero — no target means no target, and an unknown nutrient is not a measured zero. Any figure whose name ends in Estimated is a calculation, not a measurement: say so when you quote it.
The description explains the capability, when to use it, and what to expect.
Inputs99/100
Input documentation gives an agent enough context to populate the arguments.
asOf
The local day to report as 'today', YYYY-MM-DD. Omit it unless the user is asking about a specific past day — omitted means today in their own timezone, which is what you want almost every time.
Clear enough to supply this argument.
Annotations50/100
Declare destructiveHint, idempotentHint based on the tool’s actual behavior.
{
"readOnlyHint": true,
"openWorldHint": false
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "get_health_overview",
"title": "Health overview",
"description": "Everything you need to give advice about this person's health, in one call. Call this FIRST, before anything else in a session: it returns their profile (including the timezone every entry is filed against, and a goal note they wrote for you), the daily targets in force, what they have logged so far today, today's energy balance, and their intake, weight and activity trends over the last 7, 30 and 90 days. You should not need a second call to answer \"how am I doing\". It also returns `context` — what earlier sessions learned about how to coach this person: their preferred tone, what motivates them, injuries and other hard constraints, and what has already been tried. READ IT BEFORE YOU ANSWER, and match it. A slot that is null has never been filled in; if this conversation teaches you something durable, call update_context to leave it for the next session. Null means not recorded, never zero — no target means no target, and an unknown nutrient is not a measured zero. Any figure whose name ends in Estimated is a calculation, not a measurement: say so when you quote it.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"asOf": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "The local day to report as 'today', YYYY-MM-DD. Omit it unless the user is asking about a specific past day — omitted means today in their own timezone, which is what you want almost every time."
}
}
},
"annotations": {
"readOnlyHint": true,
"openWorldHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description97/100
Per-day totals for a date range: intake, activity, weight and the target in force, one row per local day, with a summary over the whole range FIRST — read the summary before the rows, it already has the totals and the daily averages. Days with nothing logged are absent rather than zeroed: that is a day nobody wrote down, not a day they ate nothing. Every sum carries an unknown count beside it saying how many items had no value for that nutrient; a total with unknowns is short, not low. The range is capped at 366 days — narrow it, or call this twice.
The description explains the capability, when to use it, and what to expect.
Inputs75/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
from
First local day to include, inclusive. YYYY-MM-DD. The range is capped at 366 days — ask for a narrower window, or call this twice.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
to
Last local day to include, inclusive. YYYY-MM-DD.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations50/100
Declare destructiveHint, idempotentHint based on the tool’s actual behavior.
{
"readOnlyHint": true,
"openWorldHint": false
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "get_daily_summary",
"title": "Daily summary for a range",
"description": "Per-day totals for a date range: intake, activity, weight and the target in force, one row per local day, with a summary over the whole range FIRST — read the summary before the rows, it already has the totals and the daily averages. Days with nothing logged are absent rather than zeroed: that is a day nobody wrote down, not a day they ate nothing. Every sum carries an unknown count beside it saying how many items had no value for that nutrient; a total with unknowns is short, not low. The range is capped at 366 days — narrow it, or call this twice.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"from",
"to"
],
"properties": {
"to": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "Last local day to include, inclusive. YYYY-MM-DD."
},
"from": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "First local day to include, inclusive. YYYY-MM-DD. The range is capped at 366 days — ask for a narrower window, or call this twice."
}
}
},
"annotations": {
"readOnlyHint": true,
"openWorldHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description96/100
Entries with their items, newest first. Use this when the user asks about a specific meal, or when you need the line items to correct something with amend_consumption. The summary over the whole range comes first — read it before paging, because it already answers 'how much did they eat'. from defaults to 7 days ago and to defaults to today, in their own timezone. limit is 1-200 and defaults to 50. When a result carries nextCursor there are more entries: send it back verbatim as cursor. When nextCursor is ABSENT you have reached the end — there is no empty cursor to check for. A null nutrient on an item means nobody recorded it, not zero.
The description explains the capability, when to use it, and what to expect.
Inputs81/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
from
First local day to include, YYYY-MM-DD. Defaults to 7 days ago in their timezone.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
to
Last local day to include, YYYY-MM-DD. Defaults to today in their timezone.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
limit
How many entries to return, 1-200. Defaults to 50.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
cursor
From the previous page's nextCursor. Omit for the first page; when nextCursor is absent from a result you have reached the end.
Clear enough to supply this argument.
Annotations50/100
Declare destructiveHint, idempotentHint based on the tool’s actual behavior.
{
"readOnlyHint": true,
"openWorldHint": false
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "list_consumption",
"title": "List consumption entries",
"description": "Entries with their items, newest first. Use this when the user asks about a specific meal, or when you need the line items to correct something with amend_consumption. The summary over the whole range comes first — read it before paging, because it already answers 'how much did they eat'. from defaults to 7 days ago and to defaults to today, in their own timezone. limit is 1-200 and defaults to 50. When a result carries nextCursor there are more entries: send it back verbatim as cursor. When nextCursor is ABSENT you have reached the end — there is no empty cursor to check for. A null nutrient on an item means nobody recorded it, not zero.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"to": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "Last local day to include, YYYY-MM-DD. Defaults to today in their timezone."
},
"from": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "First local day to include, YYYY-MM-DD. Defaults to 7 days ago in their timezone."
},
"limit": {
"type": "integer",
"maximum": 200,
"minimum": 1,
"description": "How many entries to return, 1-200. Defaults to 50."
},
"cursor": {
"type": "string",
"minLength": 1,
"description": "From the previous page's nextCursor. Omit for the first page; when nextCursor is absent from a result you have reached the end."
}
}
},
"annotations": {
"readOnlyHint": true,
"openWorldHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description91/100
Weigh-ins in a date range, with the trend first: the change over the range and a 7-day moving average, then the raw readings. from defaults to 90 days ago and to defaults to today, in their own timezone. latest is their most recent weigh-in on or before to, which may be older than from — it carries its own date, so say how old it is rather than presenting it as current. Everything is kilograms; a display block beside it renders their preferred units. A null change means fewer than two readings in the range, which is no basis for saying anything changed — not a change of zero.
The description explains the capability, when to use it, and what to expect.
Inputs98/100
Input documentation gives an agent enough context to populate the arguments.
from
First local day to include, YYYY-MM-DD. Defaults to 90 days ago in their timezone.
Clear enough to supply this argument.
to
Last local day to include, YYYY-MM-DD. Defaults to today in their timezone.
Clear enough to supply this argument.
Annotations50/100
Declare destructiveHint, idempotentHint based on the tool’s actual behavior.
{
"readOnlyHint": true,
"openWorldHint": false
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "list_weight",
"title": "List weigh-ins",
"description": "Weigh-ins in a date range, with the trend first: the change over the range and a 7-day moving average, then the raw readings. from defaults to 90 days ago and to defaults to today, in their own timezone. latest is their most recent weigh-in on or before to, which may be older than from — it carries its own date, so say how old it is rather than presenting it as current. Everything is kilograms; a display block beside it renders their preferred units. A null change means fewer than two readings in the range, which is no basis for saying anything changed — not a change of zero.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"to": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "Last local day to include, YYYY-MM-DD. Defaults to today in their timezone."
},
"from": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "First local day to include, YYYY-MM-DD. Defaults to 90 days ago in their timezone."
}
}
},
"annotations": {
"readOnlyHint": true,
"openWorldHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description88/100
Activity sessions in a date range, with the range total first, then weekly rollups, then the sessions. from defaults to 28 days ago and to defaults to today, in their own timezone. Distances are metres and durations are minutes; a display block beside them renders their preferred units. A null distance or energy means the session was logged without one — an indoor session covered an unknown distance, not zero — and the unknown-session counts beside each total say how many are missing.
The description explains the capability, when to use it, and what to expect.
Inputs88/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
from
First local day to include, YYYY-MM-DD. Defaults to 28 days ago in their timezone.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
to
Last local day to include, YYYY-MM-DD. Defaults to today in their timezone.
Clear enough to supply this argument.
Annotations50/100
Declare destructiveHint, idempotentHint based on the tool’s actual behavior.
{
"readOnlyHint": true,
"openWorldHint": false
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "list_activity",
"title": "List activity sessions",
"description": "Activity sessions in a date range, with the range total first, then weekly rollups, then the sessions. from defaults to 28 days ago and to defaults to today, in their own timezone. Distances are metres and durations are minutes; a display block beside them renders their preferred units. A null distance or energy means the session was logged without one — an indoor session covered an unknown distance, not zero — and the unknown-session counts beside each total say how many are missing.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"to": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "Last local day to include, YYYY-MM-DD. Defaults to today in their timezone."
},
"from": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "First local day to include, YYYY-MM-DD. Defaults to 28 days ago in their timezone."
}
}
},
"annotations": {
"readOnlyHint": true,
"openWorldHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description92/100
Record one eating or drinking occasion. You are the parser and Vitals is the ledger: look at the photo or read the sentence, then send the structured result here. Split the meal into one item per distinct food or drink — the totals are built from those, and a single blob cannot be corrected later. Omit any nutrient you cannot tell rather than sending 0: omitted means unknown, 0 means you measured a zero, and the difference reaches every daily total. Reuse the same clientRequestId if you retry.
The description explains the capability, when to use it, and what to expect.
Inputs98/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
clientRequestId
A stable id you generate for this logging attempt. Reuse it VERBATIM if you retry — a repeat returns the entry already stored instead of creating a second one. Generate a new one only for a genuinely new event.
Clear enough to supply this argument.
occurredAt
When it was eaten or drunk, with a UTC offset (2026-08-29T12:35:00+02:00). Not when you are logging it. If the user says "this morning", resolve it against their timezone from get_health_overview.
Clear enough to supply this argument.
description
One sentence in the user's own words: "Chicken caesar salad, no croutons, and a sparkling water". This is what they will recognise in the log.
Clear enough to supply this argument.
captureSource
photo if you looked at an image, text if they typed it, voice if they spoke it.
Clear enough to supply this argument.
confidence
high | medium | low — your own honest assessment. A packaged item with a label is high; a shared restaurant plate is low. This is shown to the user; do not inflate it.
Clear enough to supply this argument.
items › items › name
What it is, in words a person would recognise: "Grilled chicken breast", "Sparkling water". There is no food database behind this — your description is the record.
Clear enough to supply this argument.
items › items › amount
How much, as a number. Omit it if you can only say "a handful". Must travel with amountUnit — one without the other is not a measurement.
Clear enough to supply this argument.
items › items › amountUnit
g | ml | item | serving — the unit for amount. Send it whenever you send amount, and omit it whenever you do not. Prefer serving only when you cannot state grams or millilitres, and say why in sourceNote.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
items › items › energyKcal
Total energy for this item in kilocalories. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero. Estimate it: this is the one number the user is almost always asking about.
Clear enough to supply this argument.
items › items › proteinG
Protein in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › carbsG
Carbohydrate in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › fatG
Fat in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › fibreG
Fibre in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › sugarG
Sugar in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › satFatG
Saturated fat in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › sodiumMg
Sodium in milligrams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › alcoholG
Alcohol in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › caffeineMg
Caffeine in milligrams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › waterMl
How much this contributes to hydration, in millilitres. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › items › sourceNote
How you arrived at these numbers — "~250 g portion estimated from the plate". This is the only audit trail a single figure will ever have.
Clear enough to supply this argument.
mealSlot
breakfast | lunch | dinner | snack | drink. Omit it if you are guessing — a coffee at 15:00 is not obviously a snack.
Clear enough to supply this argument.
note
Anything worth keeping that is not a nutrient — context, a brand, who they were with.
Clear enough to supply this argument.
Annotations75/100
Declare openWorldHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "log_consumption",
"title": "Log what they ate or drank",
"description": "Record one eating or drinking occasion. You are the parser and Vitals is the ledger: look at the photo or read the sentence, then send the structured result here. Split the meal into one item per distinct food or drink — the totals are built from those, and a single blob cannot be corrected later. Omit any nutrient you cannot tell rather than sending 0: omitted means unknown, 0 means you measured a zero, and the difference reaches every daily total. Reuse the same clientRequestId if you retry.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"clientRequestId",
"occurredAt",
"description",
"captureSource",
"confidence",
"items"
],
"properties": {
"note": {
"type": [
"string",
"null"
],
"description": "Anything worth keeping that is not a nutrient — context, a brand, who they were with."
},
"items": {
"type": "array",
"items": {
"type": "object",
"required": [
"name"
],
"properties": {
"fatG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Fat in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"name": {
"type": "string",
"minLength": 1,
"description": "What it is, in words a person would recognise: \"Grilled chicken breast\", \"Sparkling water\". There is no food database behind this — your description is the record."
},
"amount": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "How much, as a number. Omit it if you can only say \"a handful\". Must travel with amountUnit — one without the other is not a measurement."
},
"carbsG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Carbohydrate in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"fibreG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Fibre in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"sugarG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Sugar in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"satFatG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Saturated fat in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"waterMl": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "How much this contributes to hydration, in millilitres. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"alcoholG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Alcohol in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"proteinG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Protein in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"sodiumMg": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Sodium in milligrams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"amountUnit": {
"anyOf": [
{
"enum": [
"g",
"ml",
"item",
"serving"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "g | ml | item | serving — the unit for amount. Send it whenever you send amount, and omit it whenever you do not. Prefer serving only when you cannot state grams or millilitres, and say why in sourceNote."
},
"caffeineMg": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Caffeine in milligrams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"energyKcal": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Total energy for this item in kilocalories. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero. Estimate it: this is the one number the user is almost always asking about."
},
"sourceNote": {
"type": [
"string",
"null"
],
"description": "How you arrived at these numbers — \"~250 g portion estimated from the plate\". This is the only audit trail a single figure will ever have."
}
}
},
"minItems": 1,
"description": "One entry per distinct food or drink, at least one. Split a meal into its components — the totals are built from these, and a single blob cannot be corrected later."
},
"mealSlot": {
"anyOf": [
{
"enum": [
"breakfast",
"lunch",
"dinner",
"snack",
"drink"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "breakfast | lunch | dinner | snack | drink. Omit it if you are guessing — a coffee at 15:00 is not obviously a snack."
},
"confidence": {
"enum": [
"high",
"medium",
"low"
],
"type": "string",
"description": "high | medium | low — your own honest assessment. A packaged item with a label is high; a shared restaurant plate is low. This is shown to the user; do not inflate it."
},
"occurredAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"description": "When it was eaten or drunk, with a UTC offset (2026-08-29T12:35:00+02:00). Not when you are logging it. If the user says \"this morning\", resolve it against their timezone from get_health_overview."
},
"description": {
"type": "string",
"minLength": 1,
"description": "One sentence in the user's own words: \"Chicken caesar salad, no croutons, and a sparkling water\". This is what they will recognise in the log."
},
"captureSource": {
"enum": [
"photo",
"text",
"voice"
],
"type": "string",
"description": "photo if you looked at an image, text if they typed it, voice if they spoke it."
},
"clientRequestId": {
"type": "string",
"minLength": 1,
"description": "A stable id you generate for this logging attempt. Reuse it VERBATIM if you retry — a repeat returns the entry already stored instead of creating a second one. Generate a new one only for a genuinely new event."
}
}
},
"annotations": {
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description84/100
Correct an eating or drinking entry that is already logged. Send only what changes — any field you omit is left alone. If you send items it REPLACES the whole list, so include the items that did not change. You may amend any of this person's entries, including ones another agent or the dashboard wrote. A reason is required and is the only explanation anyone reading the history later will have. Prefer this over deleting and re-logging.
The description explains the capability, when to use it, and what to expect.
Inputs96/100
Explain the meaning of this value, not just its name.
entryId
From a previous log_consumption or list_consumption call.
Clear enough to supply this argument.
reason
What changed and why, in the user's terms: "user said it had croutons". This is the only explanation anyone reading the history later will have.
Clear enough to supply this argument.
items › anyOf › 0 › items › name
What it is, in words a person would recognise: "Grilled chicken breast", "Sparkling water". There is no food database behind this — your description is the record.
Clear enough to supply this argument.
items › anyOf › 0 › items › amount
How much, as a number. Omit it if you can only say "a handful". Must travel with amountUnit — one without the other is not a measurement.
Clear enough to supply this argument.
items › anyOf › 0 › items › amountUnit
g | ml | item | serving — the unit for amount. Send it whenever you send amount, and omit it whenever you do not. Prefer serving only when you cannot state grams or millilitres, and say why in sourceNote.
Clear enough to supply this argument.
items › anyOf › 0 › items › energyKcal
Total energy for this item in kilocalories. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero. Estimate it: this is the one number the user is almost always asking about.
Clear enough to supply this argument.
items › anyOf › 0 › items › proteinG
Protein in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › carbsG
Carbohydrate in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › fatG
Fat in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › fibreG
Fibre in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › sugarG
Sugar in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › satFatG
Saturated fat in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › sodiumMg
Sodium in milligrams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › alcoholG
Alcohol in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › caffeineMg
Caffeine in milligrams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › waterMl
How much this contributes to hydration, in millilitres. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero.
Clear enough to supply this argument.
items › anyOf › 0 › items › sourceNote
How you arrived at these numbers — "~250 g portion estimated from the plate". This is the only audit trail a single figure will ever have.
Clear enough to supply this argument.
description
Only if the sentence itself was wrong.
Explain the meaning of this value, not just its name.
mealSlot
breakfast | lunch | dinner | snack | drink.
Clear enough to supply this argument.
confidence
Raise it if the correction came from the user rather than from you re-guessing.
Clear enough to supply this argument.
note
Context that is not a nutrient.
Clear enough to supply this argument.
occurredAt
⚠️ Moving this can move the entry to a different day. Only send it if the time itself was wrong.
Clear enough to supply this argument.
Annotations75/100
Declare openWorldHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "amend_consumption",
"title": "Correct an entry",
"description": "Correct an eating or drinking entry that is already logged. Send only what changes — any field you omit is left alone. If you send items it REPLACES the whole list, so include the items that did not change. You may amend any of this person's entries, including ones another agent or the dashboard wrote. A reason is required and is the only explanation anyone reading the history later will have. Prefer this over deleting and re-logging.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"entryId",
"reason"
],
"properties": {
"note": {
"type": [
"string",
"null"
],
"description": "Context that is not a nutrient."
},
"items": {
"anyOf": [
{
"type": "array",
"items": {
"type": "object",
"required": [
"name"
],
"properties": {
"fatG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Fat in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"name": {
"type": "string",
"minLength": 1,
"description": "What it is, in words a person would recognise: \"Grilled chicken breast\", \"Sparkling water\". There is no food database behind this — your description is the record."
},
"amount": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "How much, as a number. Omit it if you can only say \"a handful\". Must travel with amountUnit — one without the other is not a measurement."
},
"carbsG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Carbohydrate in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"fibreG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Fibre in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"sugarG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Sugar in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"satFatG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Saturated fat in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"waterMl": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "How much this contributes to hydration, in millilitres. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"alcoholG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Alcohol in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"proteinG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Protein in grams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"sodiumMg": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Sodium in milligrams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"amountUnit": {
"anyOf": [
{
"enum": [
"g",
"ml",
"item",
"serving"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "g | ml | item | serving — the unit for amount. Send it whenever you send amount, and omit it whenever you do not. Prefer serving only when you cannot state grams or millilitres, and say why in sourceNote."
},
"caffeineMg": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Caffeine in milligrams. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero."
},
"energyKcal": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Total energy for this item in kilocalories. Omit it rather than guess — omitting means unknown, and 0 would be recorded as a measured zero. Estimate it: this is the one number the user is almost always asking about."
},
"sourceNote": {
"type": [
"string",
"null"
],
"description": "How you arrived at these numbers — \"~250 g portion estimated from the plate\". This is the only audit trail a single figure will ever have."
}
}
},
"minItems": 1
},
{
"type": "null"
}
],
"description": "Replaces EVERY item on the entry. Send the complete corrected list, not just the changed one — include the items that did not change."
},
"reason": {
"type": "string",
"minLength": 1,
"description": "What changed and why, in the user's terms: \"user said it had croutons\". This is the only explanation anyone reading the history later will have."
},
"entryId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
"description": "From a previous log_consumption or list_consumption call."
},
"mealSlot": {
"anyOf": [
{
"enum": [
"breakfast",
"lunch",
"dinner",
"snack",
"drink"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "breakfast | lunch | dinner | snack | drink."
},
"confidence": {
"anyOf": [
{
"enum": [
"high",
"medium",
"low"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Raise it if the correction came from the user rather than from you re-guessing."
},
"occurredAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
{
"type": "null"
}
],
"description": "⚠️ Moving this can move the entry to a different day. Only send it if the time itself was wrong."
},
"description": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
],
"description": "Only if the sentence itself was wrong."
}
}
},
"annotations": {
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description75/100
Record a weigh-in. Always kilograms — if the user says pounds, convert before sending; display units are their preference, not the store's. Send bodyFatPct only if a scale actually reported it; do not estimate body composition. Reuse the same clientRequestId if you retry.
Describe the returned information so the agent knows whether it will answer the request.
Inputs79/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
clientRequestId
A stable id you generate for this logging attempt. Reuse it VERBATIM if you retry — a repeat returns the entry already stored instead of creating a second one. Generate a new one only for a genuinely new event.
Clear enough to supply this argument.
occurredAt
When they stood on the scale, with a UTC offset. Not when you are logging it.
Clear enough to supply this argument.
weightKg
Always kilograms. If the user says pounds, convert before sending — the store is metric and display units are their preference, not yours.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
bodyFatPct
Only if a scale actually reported it. Do not estimate body composition.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
skeletalMuscleKg
Only if a scale actually reported it.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
note
"after the run", "first thing, fasted".
Explain the meaning of this value, not just its name.
Annotations75/100
Declare openWorldHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "log_weight",
"title": "Log a weigh-in",
"description": "Record a weigh-in. Always kilograms — if the user says pounds, convert before sending; display units are their preference, not the store's. Send bodyFatPct only if a scale actually reported it; do not estimate body composition. Reuse the same clientRequestId if you retry.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"clientRequestId",
"occurredAt",
"weightKg"
],
"properties": {
"note": {
"type": [
"string",
"null"
],
"description": "\"after the run\", \"first thing, fasted\"."
},
"weightKg": {
"type": "number",
"description": "Always kilograms. If the user says pounds, convert before sending — the store is metric and display units are their preference, not yours.",
"exclusiveMinimum": 0
},
"bodyFatPct": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Only if a scale actually reported it. Do not estimate body composition."
},
"occurredAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"description": "When they stood on the scale, with a UTC offset. Not when you are logging it."
},
"clientRequestId": {
"type": "string",
"minLength": 1,
"description": "A stable id you generate for this logging attempt. Reuse it VERBATIM if you retry — a repeat returns the entry already stored instead of creating a second one. Generate a new one only for a genuinely new event."
},
"skeletalMuscleKg": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Only if a scale actually reported it."
}
}
},
"annotations": {
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description78/100
Record a workout, a walk, anything that burned energy. Distance is in metres and duration in minutes. Omit distanceM for a gym session rather than sending 0 — omitting means unknown and 0 would record a session that covered no ground. Omit energyKcal rather than guessing wildly. Reuse the same clientRequestId if you retry.
The description explains the capability, when to use it, and what to expect.
Inputs58/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
clientRequestId
A stable id you generate for this logging attempt. Reuse it VERBATIM if you retry — a repeat returns the entry already stored instead of creating a second one. Generate a new one only for a genuinely new event.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
occurredAt
When it started, with a UTC offset. Not when you are logging it.
Clear enough to supply this argument.
kind
run · walk · cycle · swim · row · strength · hiit · yoga · sport · other. Use other rather than forcing a bad fit.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
description
"Easy run along the harbour", "Gym — upper body".
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
durationMin
Minutes, 1–1440. How long they were actually moving.
Resolve the mismatch between this description and its schema constraints.
distanceM
Metres. Omit it for a gym session — omitting is not the same as sending 0, and 0 would be recorded as a measured zero distance.
Clear enough to supply this argument.
energyKcal
Your estimate of energy burned. Omit it rather than guess wildly; the user is told this is an estimate either way.
Clear enough to supply this argument.
avgHeartRate
Beats per minute, only if a device actually reported it.
Resolve the mismatch between this description and its schema constraints.
perceivedEffort
1–10, only if the user offered one. Do not score it for them.
Resolve the mismatch between this description and its schema constraints.
note
Anything worth keeping about the session.
Explain the meaning of this value, not just its name.
Annotations75/100
Declare openWorldHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "log_activity",
"title": "Log a session",
"description": "Record a workout, a walk, anything that burned energy. Distance is in metres and duration in minutes. Omit distanceM for a gym session rather than sending 0 — omitting means unknown and 0 would record a session that covered no ground. Omit energyKcal rather than guessing wildly. Reuse the same clientRequestId if you retry.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"clientRequestId",
"occurredAt",
"kind",
"description",
"durationMin"
],
"properties": {
"kind": {
"enum": [
"run",
"walk",
"cycle",
"swim",
"row",
"strength",
"hiit",
"yoga",
"sport",
"other"
],
"type": "string",
"description": "run · walk · cycle · swim · row · strength · hiit · yoga · sport · other. Use other rather than forcing a bad fit."
},
"note": {
"type": [
"string",
"null"
],
"description": "Anything worth keeping about the session."
},
"distanceM": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Metres. Omit it for a gym session — omitting is not the same as sending 0, and 0 would be recorded as a measured zero distance."
},
"energyKcal": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"description": "Your estimate of energy burned. Omit it rather than guess wildly; the user is told this is an estimate either way."
},
"occurredAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"description": "When it started, with a UTC offset. Not when you are logging it."
},
"description": {
"type": "string",
"minLength": 1,
"description": "\"Easy run along the harbour\", \"Gym — upper body\"."
},
"durationMin": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Minutes, 1–1440. How long they were actually moving."
},
"avgHeartRate": {
"anyOf": [
{
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
{
"type": "null"
}
],
"description": "Beats per minute, only if a device actually reported it."
},
"clientRequestId": {
"type": "string",
"minLength": 1,
"description": "A stable id you generate for this logging attempt. Reuse it VERBATIM if you retry — a repeat returns the entry already stored instead of creating a second one. Generate a new one only for a genuinely new event."
},
"perceivedEffort": {
"anyOf": [
{
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
{
"type": "null"
}
],
"description": "1–10, only if the user offered one. Do not score it for them."
}
}
},
"annotations": {
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description97/100
Remove an entry you or the user got wrong, from the intake, weight or activity log. The delete is soft — the row is kept and the deletion is recorded — and there is no undo tool, so re-log if it was removed in error. If the entry is merely wrong rather than unwanted, use amend_consumption instead. A reason is required and lands in the audit trail.
The description explains the capability, when to use it, and what to expect.
Inputs92/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
entryType
consumption | weight | activity — which log the entry is in.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
entryId
From a previous log or list call.
Clear enough to supply this argument.
reason
Why. "User said the salad had croutons — re-logging." This lands in the audit trail and is the only explanation anyone will have later. The delete is soft and there is no undo tool: re-log instead.
Clear enough to supply this argument.
Annotations75/100
Declare openWorldHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "delete_entry",
"title": "Delete an entry",
"description": "Remove an entry you or the user got wrong, from the intake, weight or activity log. The delete is soft — the row is kept and the deletion is recorded — and there is no undo tool, so re-log if it was removed in error. If the entry is merely wrong rather than unwanted, use amend_consumption instead. A reason is required and lands in the audit trail.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"entryType",
"entryId",
"reason"
],
"properties": {
"reason": {
"type": "string",
"minLength": 1,
"description": "Why. \"User said the salad had croutons — re-logging.\" This lands in the audit trail and is the only explanation anyone will have later. The delete is soft and there is no undo tool: re-log instead."
},
"entryId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
"description": "From a previous log or list call."
},
"entryType": {
"enum": [
"consumption",
"weight",
"activity"
],
"type": "string",
"description": "consumption | weight | activity — which log the entry is in."
}
}
},
"annotations": {
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description81/100
Set or change what Vitals knows about this person. Send only the fields you are changing; at least one is required. The timezone decides which calendar day an entry lands on, so set it before logging much — a new account has no profile at all, and the first call must set both timezone and unitPreference. goalNote is free text you can read and rewrite: put anything there you would otherwise ask about every session.
The description explains the capability, when to use it, and what to expect.
Inputs66/100
6 of 8 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
displayName
Not provided
Missing description. Explain what this value means and how to supply it.
birthDate
YYYY-MM-DD.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
heightCm
Centimetres, always.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sexAtBirth
Used only as an input to the resting-burn estimate.
Clear enough to supply this argument.
timezone
IANA name, e.g. Europe/Copenhagen. This decides which calendar day an entry lands on — get it right before logging much.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
unitPreference
metric | imperial. Affects what they see, never what is stored.
Clear enough to supply this argument.
activityBaseline
Not provided
Missing description. Explain what this value means and how to supply it.
goalNote
Free text you can read and rewrite: goals, constraints, dietary rules, what they are training for. Put anything here you would otherwise ask about every session.
Clear enough to supply this argument.
Annotations75/100
Declare openWorldHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "update_profile",
"title": "Update the profile",
"description": "Set or change what Vitals knows about this person. Send only the fields you are changing; at least one is required. The timezone decides which calendar day an entry lands on, so set it before logging much — a new account has no profile at all, and the first call must set both timezone and unitPreference. goalNote is free text you can read and rewrite: put anything there you would otherwise ask about every session.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"goalNote": {
"type": [
"string",
"null"
],
"description": "Free text you can read and rewrite: goals, constraints, dietary rules, what they are training for. Put anything here you would otherwise ask about every session."
},
"heightCm": {
"anyOf": [
{
"type": "number",
"exclusiveMinimum": 0
},
{
"type": "null"
}
],
"description": "Centimetres, always."
},
"timezone": {
"type": "string",
"description": "IANA name, e.g. Europe/Copenhagen. This decides which calendar day an entry lands on — get it right before logging much."
},
"birthDate": {
"anyOf": [
{
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
{
"type": "null"
}
],
"description": "YYYY-MM-DD."
},
"sexAtBirth": {
"anyOf": [
{
"enum": [
"female",
"male",
"intersex",
"unspecified"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Used only as an input to the resting-burn estimate."
},
"displayName": {
"type": [
"string",
"null"
]
},
"unitPreference": {
"enum": [
"metric",
"imperial"
],
"type": "string",
"description": "metric | imperial. Affects what they see, never what is stored."
},
"activityBaseline": {
"anyOf": [
{
"enum": [
"sedentary",
"light",
"moderate",
"high",
"athlete"
],
"type": "string"
},
{
"type": "null"
}
]
}
}
},
"annotations": {
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description90/100
Set this person's daily targets, effective from a date — usually today. This appends a new set and leaves earlier days judged against the targets that were in force then. Omit any target you are not setting: an omitted target means no target, which is not the same as a target of zero. The note is why they changed, and it is cheap now and valuable in six months.
The description explains the capability, when to use it, and what to expect.
Inputs34/100
3 of 8 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
effectiveFrom
Usually today, YYYY-MM-DD. Targets before this date are untouched.
Clear enough to supply this argument.
energyKcal
Omit a target to leave it unset — an unset target means no target, not zero.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
proteinG
Not provided
Missing description. Explain what this value means and how to supply it.
carbsG
Not provided
Missing description. Explain what this value means and how to supply it.
fatG
Not provided
Missing description. Explain what this value means and how to supply it.
waterMl
Not provided
Missing description. Explain what this value means and how to supply it.
targetWeightKg
Not provided
Missing description. Explain what this value means and how to supply it.
note
Why they changed. Cheap now, valuable in six months.
Clear enough to supply this argument.
Annotations75/100
Declare openWorldHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "set_targets",
"title": "Set daily targets",
"description": "Set this person's daily targets, effective from a date — usually today. This appends a new set and leaves earlier days judged against the targets that were in force then. Omit any target you are not setting: an omitted target means no target, which is not the same as a target of zero. The note is why they changed, and it is cheap now and valuable in six months.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"effectiveFrom"
],
"properties": {
"fatG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
]
},
"note": {
"type": [
"string",
"null"
],
"description": "Why they changed. Cheap now, valuable in six months."
},
"carbsG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
]
},
"waterMl": {
"anyOf": [
{
"type": "integer",
"maximum": 9007199254740991,
"minimum": 0
},
{
"type": "null"
}
]
},
"proteinG": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
]
},
"energyKcal": {
"anyOf": [
{
"type": "integer",
"maximum": 9007199254740991,
"minimum": 0
},
{
"type": "null"
}
],
"description": "Omit a target to leave it unset — an unset target means no target, not zero."
},
"effectiveFrom": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "Usually today, YYYY-MM-DD. Targets before this date are untouched."
},
"targetWeightKg": {
"type": [
"number",
"null"
]
}
}
},
"annotations": {
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description91/100
Remember something durable about how to coach this person, so the next session starts where this one ended. Five slots and no others: coachingStyle, motivation, foodPreferences, constraints, whatWorks. Call this when the conversation reveals something that will still be true in a month — how they want to be spoken to, what derails them, an injury, a food they will never eat, a habit that did or did not stick. Do NOT call it for one day's mood, one meal, or anything already in the log: what they ate is data, not memory. Each slot you send REPLACES that slot entirely — there is no way to append. Read the current value first (get_health_overview returns it), then re-author it whole, keeping it under 800 characters by dropping what the new information supersedes. Send only the slots you are changing; omit the rest. Send null to clear one. If a slot comes back rejected for length, compact it and send it again — do not continue it in another slot. Write it as notes to your future self, in the third person, and keep it specific: "prefers one suggestion at a time" is usable, "likes encouragement" is not.
The description explains the capability, when to use it, and what to expect.
Inputs75/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
coachingStyle
How they want to be spoken to: tone, how much detail, how hard to push, what lands and what puts them off. e.g. "Gentle. Positive about progress, one small suggestion at a time; blunt criticism makes them disengage." Send null to clear. 800 characters at most.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
motivation
What keeps them going and what derails them — the durable pattern, not this week's mood. e.g. "Loses momentum after one missed week; restarting a streak deliberately works better than trying to catch up." Send null to clear. 800 characters at most.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
foodPreferences
What they actually eat: likes, dislikes, cuisines, how they cook, what they will never do. NOT a food log — the log is already in this database. The durable shape of their diet. Send null to clear. 800 characters at most.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
constraints
Hard limits to respect: injuries, allergies, conditions, medication, schedule, budget. Anything that makes a suggestion unsafe or impossible. Send null to clear. 800 characters at most.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
whatWorks
Habits and approaches already tried, and how each went. The record that stops you suggesting in October the thing that failed in March. Send null to clear. 800 characters at most.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations75/100
Declare openWorldHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "update_context",
"title": "Remember how to coach this person",
"description": "Remember something durable about how to coach this person, so the next session starts where this one ended. Five slots and no others: coachingStyle, motivation, foodPreferences, constraints, whatWorks. Call this when the conversation reveals something that will still be true in a month — how they want to be spoken to, what derails them, an injury, a food they will never eat, a habit that did or did not stick. Do NOT call it for one day's mood, one meal, or anything already in the log: what they ate is data, not memory. Each slot you send REPLACES that slot entirely — there is no way to append. Read the current value first (get_health_overview returns it), then re-author it whole, keeping it under 800 characters by dropping what the new information supersedes. Send only the slots you are changing; omit the rest. Send null to clear one. If a slot comes back rejected for length, compact it and send it again — do not continue it in another slot. Write it as notes to your future self, in the third person, and keep it specific: \"prefers one suggestion at a time\" is usable, \"likes encouragement\" is not.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"whatWorks": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
],
"description": "Habits and approaches already tried, and how each went. The record that stops you suggesting in October the thing that failed in March. Send null to clear. 800 characters at most."
},
"motivation": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
],
"description": "What keeps them going and what derails them — the durable pattern, not this week's mood. e.g. \"Loses momentum after one missed week; restarting a streak deliberately works better than trying to catch up.\" Send null to clear. 800 characters at most."
},
"constraints": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
],
"description": "Hard limits to respect: injuries, allergies, conditions, medication, schedule, budget. Anything that makes a suggestion unsafe or impossible. Send null to clear. 800 characters at most."
},
"coachingStyle": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
],
"description": "How they want to be spoken to: tone, how much detail, how hard to push, what lands and what puts them off. e.g. \"Gentle. Positive about progress, one small suggestion at a time; blunt criticism makes them disengage.\" Send null to clear. 800 characters at most."
},
"foodPreferences": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
],
"description": "What they actually eat: likes, dislikes, cuisines, how they cook, what they will never do. NOT a food log — the log is already in this database. The durable shape of their diet. Send null to clear. 800 characters at most."
}
}
},
"annotations": {
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": false
}
}
Loading score analytics…
Put your MCP to the test
A few tasks worth trying with this server, chosen from its reviewed tools. These have not been run.
01List weigh-insWeigh-ins in a date range, with the trend first: the change over the range and a 7-day moving average, then the raw readings.
02List activity sessionsActivity sessions in a date range, with the range total first, then weekly rollups, then the sessions.
03Daily summary for a rangePer-day totals for a date range: intake, activity, weight and the target in force, one row per local day, with a summary over the whole range FIRST — read th…
04List consumption entriesEntries with their items, newest first.
05Health overviewEverything you need to give advice about this person's health, in one call.
Want to run these tasks against your MCP server with us?
vitals setup, tools, quality score, publishing readiness, and alternatives.
How do I add vitals to Claude, ChatGPT, or Cursor?
Add vitals to Claude, ChatGPT, or Cursor by connecting its remote MCP URL in each client's MCP settings. In Claude, add a custom connector. In ChatGPT, add an MCP app. In Cursor, add an MCP server under Settings. The MCP URL is https://vitals-staging.fly.dev/mcp.
Is vitals MCP ready for ChatGPT and Claude?
As of October 23, 2026, vitals scores 94/100 on Manufact's MCP publishing checklist. The scan does not yet meet ChatGPT publishing checks and meets Claude publishing checks. Passing these checks does not guarantee marketplace approval.
How clear is vitals's MCP tool documentation?
As of October 23, 2026, vitals scores 77/100 in Manufact's review of tool titles, descriptions, input and output schemas, and behavior annotations. The review covers 13 of 13 discovered tools. The quality score measures documentation clarity; runtime behavior and marketplace readiness require separate checks.
How can vitals improve its MCP documentation?
set_targets is the lowest-scoring reviewed tool at 65/100. No output schema is declared. Add one for structured results so clients can interpret returned fields. Open its review for feedback and a copyable fix prompt, then rerun the documentation review after updating your tool metadata.
Not your MCP?
Review any public or OAuth MCP server for protocol compatibility, tool documentation, and ChatGPT and Claude publishing readiness. No account required.