Skip to main content
Glama
Thecimal

Quantified Self MCP Server

Quantified Self MCP

Your health data. Your AI. Your machine.

CI PyPI Python License Quantified Self MCP Server MCP server โ€“ quality and maintenance score on Glama

Quantified Self MCP is a privacy-first Model Context Protocol (MCP) server that gives AI agents controlled access to your personal health data stored locally.

Built with Python, FastMCP, and SQLite, it works with both local LLMs and cloud-based LLMs. You choose where your AI runs.

Try it on Glama โ†’


What Is It?

Quantified Self MCP connects an AI agent to your personal health data through the Model Context Protocol (MCP).

The MCP server does not require a specific AI provider.

You can run the entire AI stack locally, or connect the server to an online model when you prefer.


Related MCP server: apple-health-mcp

๐Ÿ  Local AI or โ˜๏ธ Cloud AI

The important distinction is between the MCP server and the AI model.

Fully Local

With a local MCP-compatible agent and local LLM, your health data and AI inference can remain on your machine.

Cloud LLM

You can also connect the same MCP server to a hosted model.

In that setup, your database and MCP server remain local, while data returned by MCP tools may be sent to the cloud model provider.

The choice is yours.

Quantified Self MCP does not lock you into Claude, OpenAI, or any other model provider.


๐Ÿ”’ Privacy First

Your health data is stored locally in SQLite, and the MCP server runs on your machine.

The server itself does not require a cloud database, account, or hosted data store.

For maximum privacy, use a local LLM so the entire pipeline can remain on your machine.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚          YOUR MACHINE             โ”‚
โ”‚                                   โ”‚
โ”‚          Health Data              โ”‚
โ”‚               โ†“                   โ”‚
โ”‚          Local SQLite             โ”‚
โ”‚               โ†“                   โ”‚
โ”‚      Quantified Self MCP          โ”‚
โ”‚               โ†“                   โ”‚
โ”‚         Local AI Agent            โ”‚
โ”‚               โ†“                   โ”‚
โ”‚           Local LLM               โ”‚
โ”‚                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Optional Private Fields

If specific metrics should never be returned to the model, configure:

HEALTH_PRIVATE_FIELDS=weight_kg,mood

Private fields can still be stored and logged, but MCP read operations return them as null.

This gives you another layer of control over which health metrics an AI agent can access.


โค๏ธ What Can It Track?

Quantified Self MCP currently supports:

  • ๐Ÿ‘Ÿ Daily steps

  • ๐Ÿ˜ด Sleep duration

  • โค๏ธ Resting heart rate

  • โค๏ธ Heart rate

  • ๐Ÿ“ˆ Heart-rate variability (HRV)

  • โš–๏ธ Weight

  • ๐Ÿ‹๏ธ Workout minutes

  • ๐Ÿ™‚ Mood

  • ๐Ÿ’ง Water intake

Every metric is optional, so you can track only the measurements you actually use.


๐Ÿ’ฌ What Can You Ask?

Once connected to an MCP-compatible AI agent, you can ask questions naturally.

For example:

How has my sleep changed over the last 30 days?
What was my average step count this week?
Show me my resting heart rate trend.
How much water did I drink on average this month?
What patterns do you see in my recent health data?

You can also log information through the AI agent:

Log 7.5 hours of sleep for today.

Or correct a mistake:

Clear today's mood entry.

๐Ÿง  MCP Tools

The server exposes eighteen MCP tools, organized in three layers:

Layer 1 โ€” Data

Tool

Purpose

read_health_data

Read all health metrics for a selected date range

get_metric_history

Read a single metric's day-by-day values for a date range

log_daily_metric

Record one or more health metrics for a specific day

clear_metric

Clear a single metric without affecting other data

export_health_data_csv

Write a date range of metrics to a local CSV file

get_metric_provenance

Retrieve provenance information for a health metric and its source data

export_health_data_csv writes straight to disk next to the database and returns only the file's path and a row count โ€” not the row values themselves โ€” so exporting a long history doesn't have to pass through a cloud LLM's context just to get a file you can open elsewhere.

Layer 1b โ€” Raw measurements & workout sessions

Tool

Purpose

log_measurement

Record one raw observation (metric, value, timestamp, source) instead of a day total

read_measurements

Read individual measurement rows, most recent first, filterable by metric/source

log_workout_session

Record one workout as a structured event (activity, duration, intensity, heart rate)

read_workout_sessions

Read individual workout sessions, most recent day first

aggregate_measurements

Roll up a day's raw measurements into that day's daily_metrics row for analytics

Use log_measurement/log_workout_session when the source, exact time, or multiple same-day readings matter (e.g. two wearables both logging heart rate); aggregate_measurements then folds those into daily_metrics so every Layer 2/3 tool below can use them.

Tool routing

Which tool to call for a given request:

Record data

User intent

Tool

Simple daily metric (steps, weight, mood, ...)

log_daily_metric

Individual timestamped/sourced measurement

log_measurement

Workout / exercise session

log_workout_session

Read data

User intent

Tool

Broad health data across metrics

read_health_data

Raw individual measurement rows

read_measurements

Workout / exercise sessions

read_workout_sessions

One metric's history/trend over time

get_metric_history

Each of these tools' own MCP description also states this explicitly ("Use this tool when" / "Do not use this tool when", with the alternative named), and the server's top-level MCP instructions repeat the same routing model โ€” so the boundary is visible whether an agent reads one tool's schema or the whole tool list.

Layer 2 โ€” Analytics (statistics computed over one or two metrics; see analytics.py)

Tool

Purpose

get_baseline

Mean/median/stdev for a metric over a window โ€” "what's normal"

detect_metric_anomalies

Flag days that deviate sharply from a metric's own baseline

calculate_metric_trend

Fit a straight-line trend (direction, slope, rยฒ) over a window

compare_metric_periods

Compare a metric's average between two date ranges

find_metric_correlation

Pearson correlation between two metrics, with optional lag

Layer 3 โ€” Personal intelligence (composes Layer 2, returns facts rather than prose โ€” the calling model still does the narration)

Tool

Purpose

get_recent_changes

Scan every metric for notable shifts, anomalies, or trends recently

explain_metric_change

Build an evidence bundle for "why did X look like that on this day?"

The server also exposes read-only MCP resources for health metric schemas and individual days.

All data operations are scoped to the supported health metrics. The server does not expose arbitrary SQL execution to the model. Any metric listed in HEALTH_PRIVATE_FIELDS is refused by every Layer 2/3 tool outright (not just redacted afterward), since a baseline or anomaly computed from a private metric would leak its shape even without ever printing a raw value.


๐Ÿ“š Documentation Source of Truth

The MCP server implementation is the authoritative source for its available tools and schemas.

Because MCP clients and directories such as Glama inspect the running server directly, manually maintained tool lists can become outdated as new tools and metrics are added.

The project therefore treats the registered MCP tools and their schemas as the source of truth for tool documentation.

Tool documentation should be generated from the server's registered tools rather than maintained independently wherever practical.

A documentation check should ensure that:

MCP Server
    โ†“
Registered Tools
    โ†“
Generated Documentation
    โ†“
README / TOOLS.md

remain synchronized.

This prevents discrepancies between:

Actual implementation
        โ‰ 
GitHub documentation
        โ‰ 
MCP directory inspection

and makes the available MCP interface easier for users, contributors, AI agents, and MCP directories to understand.


๐Ÿ“ฅ Import Your Health Data

You can initialize the local database from CSV data.

quantified-self-init-db sample_data/health_sample.csv

The supported health fields include:

date
steps
sleep_hours
resting_heart_rate
heart_rate
hrv_ms
weight_kg
workout_minutes
mood
water_ml

A handful of common alternate header spellings are also recognized automatically, so you don't need to rename columns or know this project's exact names first โ€” e.g. step_count, hr, bpm, weight, sleep, hrv. Anything else can still be mapped with --map COLUMN=HEADER (see init_db.py's COLUMN_ALIASES for the full alias list, and its module docstring for --map).

You can also import an Apple Health export:

quantified-self-init-db export.xml

The importer maps supported Apple Health records into the local database.

Android users: Health Connect doesn't have a built-in export button like Apple Health, so it needs one extra step โ€” see docs/clients/android-health-connect.md.

See exactly what an import found, imported, skipped, and ignored

Add --report to any import to print a full breakdown instead of just a one-line summary:

quantified-self-init-db export.xml --report
IMPORT COMPLETE

Source: apple-health (export.xml)
Date range: 2025-03-01 -> 2026-09-13

Imported:
  Steps            420 day(s)
  Sleep            398 day(s)
  Heart Rate       410 day(s)
  HRV              180 day(s)
  Weight            30 day(s)

Skipped: 42 record(s)
Unsupported: 18 record type(s), 6,204 record(s) total
  HKQuantityTypeIdentifierBloodPressureSystolic: 3,102
  HKCategoryTypeIdentifierMindfulSession: 890
  ...

"Skipped" is records this import tried and failed to parse (bad date/value โ€” see the warnings printed alongside). "Unsupported" is record types the importer doesn't map to any column at all โ€” nothing here is silently lost; it's counted and named so you know what a fuller importer would need to add.


โšก Installation

PyPI

pip install quantified-self-mcp

This installs:

quantified-self-mcp
quantified-self-init-db

From Source

git clone https://github.com/Thecimal/quantified-self-mcp.git
cd quantified-self-mcp

python3 -m venv .venv
source .venv/bin/activate

pip install -r requirements.txt

Docker

docker build -t quantified-self-mcp .

The included Docker configuration can be used for containerized MCP deployments, including Glama.


๐Ÿš€ Quick Start

1. Install

pip install quantified-self-mcp

2. Load your health data

quantified-self-init-db your-health-data.csv

3. Connect the MCP server

Pick your client and follow the tested, step-by-step guide โ€” each one takes you from a fresh clone to an answered question in about 5 minutes:

Client

Guide

Claude Desktop

docs/clients/claude-desktop.md

LM Studio (local models)

docs/clients/lm-studio.md

Open WebUI

docs/clients/open-webui.md

Any other MCP-compatible client works too โ€” point it at server.py the same way, using the .venv Python interpreter.

4. Ask your health data questions

How has my sleep changed over the last 30 days?

The AI agent retrieves the relevant health data through MCP and analyzes it.


๐Ÿ”Œ MCP Client Compatibility

Quantified Self MCP uses the standard Model Context Protocol, so the server is designed to work with MCP-compatible clients and models rather than being tied to a single AI application.

The project includes configuration for clients supported by FastMCP, and standard MCP configuration can be generated for other compatible clients.

For local AI setups, pair the server with an MCP-compatible client and a local LLM runtime.

For example:

Local LLM
   +
MCP-compatible Agent
   +
Quantified Self MCP

This allows the complete AI workflow to remain local.


๐Ÿ—๏ธ Architecture

                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚      AI Agent      โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                   โ”‚
                              MCP Protocol
                                   โ”‚
                                   โ–ผ
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚ Quantified Self    โ”‚
                         โ”‚       MCP          โ”‚
                         โ”‚                    โ”‚
                         โ”‚      FastMCP       โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                   โ”‚
                                   โ–ผ
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚    Local SQLite    โ”‚
                         โ”‚                    โ”‚
                         โ”‚    Health Data     โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The AI model and the MCP server are separate components.

This means you can change the AI model without changing how your health data is stored or exposed.


๐Ÿ› ๏ธ Technology

Component

Technology

Language

Python

Protocol

Model Context Protocol

MCP Framework

FastMCP

Database

SQLite

Containerization

Docker

CI

GitHub Actions

Package

PyPI


๐Ÿงช Development

Clone the repository:

git clone https://github.com/Thecimal/quantified-self-mcp.git
cd quantified-self-mcp

Create a virtual environment:

python3 -m venv .venv
source .venv/bin/activate

Install dependencies:

pip install -r requirements-dev.txt

Run tests:

pytest

Build the package:

python -m build

GitHub Actions validates the project in a clean environment.


๐Ÿ“ Project Structure

quantified-self-mcp/
โ”œโ”€โ”€ .github/
โ”‚   โ””โ”€โ”€ workflows/
โ”œโ”€โ”€ sample_data/
โ”œโ”€โ”€ tests/
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ fastmcp.json
โ”œโ”€โ”€ glama.json
โ”œโ”€โ”€ init_db.py
โ”œโ”€โ”€ logic.py
โ”œโ”€โ”€ import_adapters.py
โ”œโ”€โ”€ server.py
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ requirements.txt
โ”œโ”€โ”€ requirements-dev.txt
โ”œโ”€โ”€ SECURITY.md
โ”œโ”€โ”€ CONTRIBUTING.md
โ”œโ”€โ”€ CODE_OF_CONDUCT.md
โ”œโ”€โ”€ CHANGELOG.md
โ”œโ”€โ”€ llms.txt
โ”œโ”€โ”€ LICENSE
โ””โ”€โ”€ README.md

๐Ÿ›ก๏ธ Security

Health information is sensitive personal data.

Never commit:

  • Personal health records

  • Private SQLite databases

  • API keys

  • Passwords

  • Authentication tokens

  • Other sensitive personal information

For security vulnerabilities, please follow the instructions in SECURITY.md.


โญ Glama

Quantified Self MCP is available through the Glama MCP directory.

Glama Score

A / A / A

Category

Score

License

A

Quality

A

Maintenance

A

The project is listed as a Python / Local MCP server on Glama. Glama performs its own inspection of the MCP server and may expose the current registered tools and schemas directly.

Because the server implementation is the source of truth, the Glama inspection may reflect newly registered tools or metrics before corresponding manually written documentation has been updated.

View Quantified Self MCP on Glama โ†’


๐Ÿค Contributing

Contributions, bug reports, documentation improvements, and ideas are welcome.

Before contributing, please read:

If you find a bug, please open an issue with enough information to reproduce it.


๐Ÿ“„ License

MIT License.



Quantified Self MCP

Your health data. Your AI. Your machine.

Available Tools

18 tools
aggregate_measurementsAggregate measurements into a dayA
Idempotent

Roll up one day's raw measurements into that day's daily_metrics row, so existing analytics tools (which all read daily_metrics) benefit from data logged via log_measurement. Steps/water/workout_minutes sum across the day, resting_heart_rate/mood average, weight_kg takes the latest reading โ€” see logic.MEASUREMENT_AGGREGATION.

If a metric has measurements from more than one source that day (e.g. an Apple Watch and a Garmin both logging resting_heart_rate), use get_metric_provenance first to see whether they actually disagree, then pass source_priority to pick a winner rather than blending two devices' readings into one meaningless average.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYesThe day to aggregate, formatted YYYY-MM-DD.
source_priorityNoOrdered list of source names, e.g. ["Apple Watch", "Garmin"]. For any metric with more than one source that day, the first name in this list that's actually present wins and the other source's readings for that metric are dropped from the aggregate. Omit to fall back to whichever source was imported most recently.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowYes
dateYes
aggregatedYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnlyHint=false, idempotentHint=true), it discloses the per-metric aggregation semantics (sums, averages, latest reading), the fallback to most-recently-imported source when source_priority is omitted, and a privacy caveat about data reaching a cloud model. That is rich behavioral context an agent cannot get from structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and aggregation rules, then the multi-source caveat, then the privacy note. Every section is useful but the privacy paragraph is lengthy relative to the calling decision, making it slightly heavier than needed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be described, and the description covers aggregation logic, the alternative tool, parameter semantics, and the privacy implication. Nothing needed to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds genuine meaning: it explains why source_priority exists ('rather than blending two devices' readings into one meaningless average') and the resolution order, which the schema states tersely as first-present-wins.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Roll up one day's raw measurements into that day's daily_metrics row') and explicitly frames the downstream beneficiary (analytics tools reading daily_metrics). It also distinguishes itself from log_measurement, which is named as the source of the data being aggregated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context: run it to make log_measurement data visible to analytics, and route to get_metric_provenance first when multiple sources disagree, then use source_priority to pick a winner. No explicit 'when not to use' but the multi-source branch is a genuine alternative-selection rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calculate_metric_trendCalculate metric trendA
Read-onlyIdempotent

Fit a simple straight-line trend to one metric over a window and report its direction, slope (change per day), and r_squared (how well a straight line actually fits โ€” low r_squared means "noisy," not "flat").

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
metricYesOne of steps, sleep_hours, resting_heart_rate, weight_kg, workout_minutes, mood, water_ml, heart_rate, hrv_ms.
end_dateNoLast day to include, formatted YYYY-MM-DD. Defaults to today.
start_dateNoFirst day to include, formatted YYYY-MM-DD. Defaults to 30 days before end_date.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rangeYes
trendYes
metricYes
evidenceYesCoverage/quality of the data a single-metric analytical result is based on. See evidence.build_evidence for how each field is computed.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, covering the safety profile. The description adds meaningful context beyond annotations by explaining how to interpret r_squared ('noisy' vs 'flat') and disclosing a privacy consideration about data being sent to a cloud model.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core functionality is front-loaded in one concise sentence, followed by a clearly separated and relevant privacy note. Every sentence earns its place with no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, idempotent tool with an output schema covering return values, the description is nearly complete. It explains output interpretation and privacy implications. The only minor gap is the lack of explicit guidance on when to choose it over sibling analysis tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three parameters. The description does not add extra parameter-level details beyond what the schema provides, so a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Fit a simple straight-line trend to one metric over a window' and lists the exact outputs (direction, slope, r_squared). This clearly distinguishes it from sibling tools like detect_metric_anomalies or compare_metric_periods.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies its usage context: when you want a simple trend line for one metric over a window. It does not explicitly mention alternatives or exclusions, but the purpose is clear enough that an agent can decide when to choose it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

clear_metricClear a single metricA
DestructiveIdempotent

Blank out (set to null) a single metric for a single day, without touching that day's other metrics. The counterpart to log_daily_metric for undoing a bad value โ€” e.g. a mood logged for the wrong day, or a weight entered with the wrong units.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYesThe day to clear a field for, formatted YYYY-MM-DD.
fieldYesWhich metric to blank out. One of: steps, sleep_hours, resting_heart_rate, weight_kg, workout_minutes, mood, water_ml, heart_rate, hrv_ms.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowNo
noteNo
clearedYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is covered. The description adds real value beyond that: it specifies the mutation is field-scoped ('without touching that day's other metrics') and discloses a privacy trait (returned data flows into the model conversation, with cloud-vs-local implications) that no structured field conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action and scope in the first sentence, then a concrete example, then the privacy note. The privacy paragraph is longer than strictly needed for tool selection but is meaningful content rather than filler, so only minor trimming is warranted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described, and annotations carry the safety profile. The description fills the remaining gaps โ€” scope of the mutation, the use case, and the privacy caveat โ€” so an agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents both parameters with the YYYY-MM-DD format and the full field list. The description adds no additional syntax or semantics beyond what the schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and effect ('Blank out (set to null) a single metric for a single day') plus an explicit scope constraint ('without touching that day's other metrics'). It also names the sibling it complements (log_daily_metric), so an agent can distinguish it from the other 15 tools immediately.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear trigger context ('undoing a bad value โ€” e.g. a mood logged for the wrong day, or a weight entered with the wrong units') and names the counterpart tool log_daily_metric. It stops short of stating when NOT to use it (e.g. correcting vs. clearing), so it is clear but not fully exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compare_metric_periodsCompare two periodsB
Read-onlyIdempotent

Compare one metric's average between two date ranges โ€” e.g. "this month vs. last month" or "since starting a new medication vs. before." The two ranges may be any length and need not be adjacent or equal in size; each is summarized with its own baseline first.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
metricYesOne of steps, sleep_hours, resting_heart_rate, weight_kg, workout_minutes, mood, water_ml, heart_rate, hrv_ms.
period_a_endYes
period_b_endYes
period_a_startYes
period_b_startYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
deltaNo
metricYes
period_aYes
period_bYes
pct_changeNo
period_a_statsYes
period_b_statsYes
period_a_evidenceYesCoverage/quality of the data a single-metric analytical result is based on. See evidence.build_evidence for how each field is computed.
period_b_evidenceYesCoverage/quality of the data a single-metric analytical result is based on. See evidence.build_evidence for how each field is computed.

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds meaningful behavioral context beyond the annotations: it states that returned data becomes part of the conversation sent to the model, warns about cloud privacy implications, and explains that each period is summarized with its own baseline. The readOnlyHint and idempotentHint annotations align with the description, and no contradiction is present. It does not fully detail output behavior, but the output schema covers that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is reasonably concise and front-loaded: the first sentence states the core purpose and examples, the second addresses period flexibility, and the privacy note is a separate relevant addition. No filler sentences are present, and every part contributes to correct usage. It could be slightly shorter, but the added context is worthwhile.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The presence of an output schema reduces the need to describe return values, and the description covers the main purpose, period flexibility, and privacy implications. However, the description does not compensate for the poorly documented date parameters nor explicitly guide selection against sibling analytical tools. For a tool with five required parameters and a low schema coverage, this leaves some meaningful gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 20%, with four date-range parameters entirely undocumented. The description adds some meaning by explaining that these are date ranges and that they may have arbitrary lengths, but it fails to specify date formats, inclusivity of endpoints, or the semantics of the start/end relationship. This is a notable gap given the schema's low coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb and resource: 'Compare one metric's average between two date ranges.' It also provides concrete examples that clarify the intended use. However, it does not explicitly differentiate itself from sibling tools like calculate_metric_trend or find_metric_correlation, relying on the phrase 'average between two date ranges' to imply the distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives illustrative use cases ('this month vs. last month') and clarifies that periods need not be adjacent or equal. But it does not explicitly state when to prefer this tool over a sibling, nor does it mention any alternatives or exclusions. Usage guidance is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

detect_metric_anomaliesDetect metric anomaliesA
Read-onlyIdempotent

Flag days where one metric deviated sharply from its own baseline over the window, using a median/MAD-based modified z-score rather than a mean/stdev z-score โ€” more robust for short, noisy personal-health series, where the mean/stdev version is easily dragged around by the very outliers it's supposed to catch.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
metricYesOne of steps, sleep_hours, resting_heart_rate, weight_kg, workout_minutes, mood, water_ml, heart_rate, hrv_ms.
end_dateNoLast day to include, formatted YYYY-MM-DD. Defaults to today.
thresholdNoModified z-score cutoff. 3.5 (the default, Iglewicz & Hoaglin's standard value) flags only clear outliers; lower it (e.g. 2.5) to see more borderline days.
start_dateNoFirst day to include, formatted YYYY-MM-DD. Defaults to 90 days before end_date.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rangeYes
metricYes
evidenceYesCoverage/quality of the data a single-metric analytical result is based on. See evidence.build_evidence for how each field is computed.
anomaliesYes
thresholdYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true, so the safety profile is covered. The description adds valuable behavioral context: the statistical method (median/MAD modified z-score), the robustness rationale, and a privacy note about data being sent to the model. The privacy note is especially useful because it warns the agent that returned data may leave the local server, which is a behavioral trait not captured by annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured: the core purpose is front-loaded in the first sentence, followed by the statistical rationale and a privacy note. The privacy note is somewhat long but earns its place because it discloses a significant behavioral trait. No wasted words, though the statistical explanation could be slightly tighter.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has an output schema, so return values are already documented. The description covers the method, the rationale, and the privacy implication. It doesn't mention edge cases like what happens when there's insufficient data, but for a read-only anomaly detection tool with full schema coverage, this is a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all four parameters. The description adds context about the threshold (Iglewicz & Hoaglin's standard value) and the default window (90 days), but these are also partially in the schema. The description doesn't add much beyond what the schema provides, so a baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Flag'), a specific resource ('days where one metric deviated sharply from its own baseline'), and a precise method (median/MAD-based modified z-score). It clearly distinguishes itself from sibling tools like get_baseline or calculate_metric_trend by focusing on anomaly detection rather than summary statistics or trend calculation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains why this tool exists (robust for short, noisy personal-health series) and why the mean/stdev version is inferior, giving an agent a clear sense of when to use it. It doesn't explicitly name sibling alternatives or state when not to use it, but the context is strong enough that an agent can infer it's for anomaly detection rather than general queries.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

explain_metric_changeExplain a metric changeA
Read-onlyIdempotent

Build an evidence bundle for "why did my look like that on ?": that day's value against a 90-day baseline, whether it qualifies as an anomaly, the trend leading into it, and any other metric that correlates with it strongly enough to be worth mentioning. Returns facts, not an explanation โ€” turning "sleep was 2.6 stdev below baseline and resting heart rate correlates at r=0.71" into an actual answer for the person is what the calling model should do with these facts, not something this tool guesses at itself.

Do not use this tool when:

  • scanning across many metrics for what changed lately, without a specific metric/date in mind -> use get_recent_changes instead.

  • you only need one piece of this bundle (just the baseline, just the trend, just anomalies, or just a correlation) rather than the full why-explanation -> use get_baseline, calculate_metric_trend, detect_metric_anomalies, or find_metric_correlation directly instead.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYesThe day to explain, formatted YYYY-MM-DD.
metricYesOne of steps, sleep_hours, resting_heart_rate, weight_kg, workout_minutes, mood, water_ml, heart_rate, hrv_ms.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dateYes
trendYes
valueNo
metricYes
baselineYes
sessionsNo
is_anomalyYes
baseline_rangeYes
trend_evidenceYesCoverage/quality of the data a single-metric analytical result is based on. See evidence.build_evidence for how each field is computed.
narrative_factsYes
modified_z_scoreNo
baseline_evidenceYesCoverage/quality of the data a single-metric analytical result is based on. See evidence.build_evidence for how each field is computed.
correlated_metricsYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and openWorldHint=false, and the description does not contradict them. It adds valuable behavioral context: the tool intentionally returns facts and not explanations, delegates the interpretive step to the calling model, and includes a privacy note that returned data becomes part of the conversation sent to the configured model.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average, but every sentence earns its place: the core purpose is front-loaded, the returns-facts-not-explanation distinction is critical, the usage exclusions are concrete, and the privacy note is operationally relevant. There is no filler or repetition of schema fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the rich output schema, the two parameters with full schema coverage, and annotations that already convey safety/idempotency, the description covers all remaining context an agent needs: when to use the tool, what it will and won't do, what data feeds into it, and privacy implications. Nothing important is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds semantic meaning beyond the schema: it clarifies that 'date' anchors the 90-day baseline comparison and 'metric' is the subject of anomaly, trend, and correlation analysis. The example ('sleep was 2.6 stdev below baseline...') further illustrates how the two parameters are interpreted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ('Build an evidence bundle' for a metric/date), then enumerates exactly what the bundle contains: value vs 90-day baseline, anomaly status, trend, and correlated metrics. It also distinguishes itself from sibling tools by stating it returns facts rather than a synthesized explanation, so an agent can tell it apart from get_recent_changes and the individual metric tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit 'Do not use this tool when' conditions and names the correct alternatives for each case (get_recent_changes for scanning, and get_baseline/calculate_metric_trend/detect_metric_anomalies/find_metric_correlation for single-piece needs). This leaves no ambiguity about when to invoke this tool versus its siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_health_data_csvExport health data to CSVA
Read-only

Write daily health metrics for a date range to a CSV file on disk, next to the database, instead of returning every row through this tool's own result.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

Unlike read_health_data, this is not capped at MAX_ROWS_RETURNED and the row values themselves are not included in this tool's response โ€” only the resulting file's path and a row count are. That means a long-range export doesn't have to pass through a cloud LLM's context just to produce a file you can open yourself (in a spreadsheet, a notebook, another tool, etc.). Any metric listed in HEALTH_PRIVATE_FIELDS is still written as an empty cell in the file, since those fields shouldn't leave the database at all, not just stay out of the model's context.

ParametersJSON Schema
NameRequiredDescriptionDefault
end_dateNoLast day to include, formatted YYYY-MM-DD. Defaults to today.
start_dateNoFirst day to include, formatted YYYY-MM-DD. Defaults to 30 days before end_date. Ranges over ~10 years are rejected.

Output Schema

ParametersJSON Schema
NameRequiredDescription
pathYes
rangeYes
rows_exportedYes

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it discloses that returned data enters the conversation/cloud-model context, that HEALTH_PRIVATE_FIELDS are written as empty cells, and that the response contains only a path and row count rather than row values. These are non-obvious behavioral traits an agent cannot infer from readOnlyHint/openWorldHint alone. Note the tension with readOnlyHint=true for a tool that writes a file to disk, but the write is to the filesystem, not the source data, and the description is transparent rather than misleading.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence, followed by rationale and privacy caveats. It runs long for a two-parameter export tool, and minor details like 'next to the database' add little, but nearly every sentence carries real information (privacy, private-field handling, response shape).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists, so return values needn't be explained, yet the description still clarifies the response shape (path + row count). Combined with the privacy note and private-field handling, an agent has everything needed to call it and interpret the result correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% (both date params documented with format and defaults), so the schema carries the parameter burden. The description only references 'a date range' generically and adds no format or constraint detail beyond the schema's own ~10-year rejection note. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource+output: 'Write daily health metrics for a date range to a CSV file on disk... instead of returning every row through this tool's own result.' It directly contrasts with read_health_data, so an agent can tell it apart from the read tools without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the sibling alternative (read_health_data) and the condition that differentiates it: not capped at MAX_ROWS_RETURNED, and a long-range export needn't pass through the LLM's context. It stops short of an explicit routing rule ('use this instead when...'), but the context is clear enough to choose correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_metric_correlationFind correlation between two metricsA
Read-onlyIdempotent

Compute the Pearson correlation between two metrics over the same window, joined by date. Correlation, not causation: a strong r just means the two moved together, not that one caused the other.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
end_dateNoLast day to include, formatted YYYY-MM-DD. Defaults to today.
lag_daysNoShift metric_b this many days later before joining โ€” 1 tests whether metric_a today predicts metric_b tomorrow (e.g. "does poor sleep tonight predict lower steps tomorrow?"). 0 (default) compares same-day values.
metric_aYes
metric_bYes
start_dateNoFirst day to include, formatted YYYY-MM-DD. Defaults to 90 days before end_date.

Output Schema

ParametersJSON Schema
NameRequiredDescription
nYes
rNo
noteNo
lag_daysYes
metric_aYes
metric_bYes
evidence_aNo
evidence_bNo

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint=false. The description adds useful behavioral context: the caveat that correlation does not imply causation, the fact that metrics are joined by date, and a privacy warning about data becoming part of the conversation sent to the model. These go beyond the annotations without contradicting them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The main purpose is front-loaded in the first sentence, followed by a brief interpretation caveat and a privacy note. Both additions are relevant and concise, though the privacy note is somewhat longer than typical tool descriptions.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and annotations covering read-only/idempotent behavior, the description does not need to explain return formats. It covers interpretation, data handling, and the join behavior. It could be more complete by explicitly naming sibling alternatives, but for a unique correlation tool this is a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents start_date, end_date, and lag_days with formats, defaults, and a worked example. The description adds the general idea of joining two metrics by date, but does not add meaning to metric_a or metric_b beyond their self-evident roles. Schema coverage is 60%, and the missing parameter descriptions are not critical.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Compute') and resource ('Pearson correlation between two metrics'), and specifies the behavior: 'over the same window, joined by date'. This clearly distinguishes it from sibling tools that analyze single metrics, compare periods, or detect anomalies.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: use this tool when the goal is to compute the Pearson correlation between two metrics over a shared time window. It does not explicitly name alternatives or state when not to use it, but the purpose is specific enough that an agent can route correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_baselineGet metric baselineA
Read-onlyIdempotent

Compute "what's normal" for one metric over a window: mean, median, and standard deviation. This is the number every other analytics tool below measures against, so a wider window (60-90+ days) gives a more stable baseline than the 30-day default read_health_data uses.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
metricYesOne of steps, sleep_hours, resting_heart_rate, weight_kg, workout_minutes, mood, water_ml, heart_rate, hrv_ms.
end_dateNoLast day to include, formatted YYYY-MM-DD. Defaults to today.
start_dateNoFirst day to include, formatted YYYY-MM-DD. Defaults to 90 days before end_date.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rangeYes
metricYes
baselineYes
evidenceYesCoverage/quality of the data a single-metric analytical result is based on. See evidence.build_evidence for how each field is computed.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, and the description adds meaningful behavioral context beyond those: a privacy note explaining that returned data becomes part of the conversation and may reach a cloud model. This is valuable, non-obvious behavior that an agent should know before invoking the tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core computation, then gives window-selection guidance, then closes with an important privacy disclosure. It is slightly longer than minimal, but the privacy note earns its place given the sensitivity of the data, and no sentence is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only tool with full schema coverage, an output schema, and clear annotations, the description covers what it computes, how to choose a useful window, and the critical privacy caveat. Nothing an agent needs in order to call it correctly or decide whether to use it is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description goes further by advising that a wider window (60-90+ days) yields a more stable baseline. That adds practical meaning for setting start_date/end_date beyond the schema's structural defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Compute') and names exactly what the tool returns: a baseline for one metric over a window, with mean, median, and standard deviation. It also distinguishes the tool from siblings by calling it the number every other analytics tool measures against.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use this tool, especially the note that a wider 60-90+ day window produces a more stable baseline than read_health_data's 30-day default. It does not explicitly list when-not-to-use cases or detailed exclusions, but the alternative is named and contrasted.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_metric_historyGet metric historyA
Read-onlyIdempotent

Read one metric's day-by-day values, without the other six metrics read_health_data always includes. Use this when you only care about a single metric (e.g. before calling get_baseline or calculate_metric_trend yourself) and don't need the full multi-metric payload.

Use this tool when:

  • the user wants one specific metric's history/trend over time (e.g. "show my weight over the last 30 days", "how has resting heart rate changed this month").

Do not use this tool when:

  • the request is broad/general, across multiple metrics at once -> use read_health_data instead.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
metricYesOne of steps, sleep_hours, resting_heart_rate, weight_kg, workout_minutes, mood, water_ml, heart_rate, hrv_ms. Rejected if configured as private via HEALTH_PRIVATE_FIELDS.
end_dateNoLast day to include, formatted YYYY-MM-DD. Defaults to today.
start_dateNoFirst day to include, formatted YYYY-MM-DD. Defaults to 30 days before end_date.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rangeYes
metricYes
pointsYes
evidenceYesCoverage/quality of the data a single-metric analytical result is based on. See evidence.build_evidence for how each field is computed.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the operation readOnlyHint and idempotentHint, and the description adds a useful privacy/data-sharing caveat plus the fact that the result is single-metric and day-by-day. This goes beyond annotations without contradicting them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is organized into clear sections: purpose, when/not-to-use, and privacy, with the most important information front-loaded. It is slightly longer than necessary for a simple read tool, but every section earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, idempotent tool with one required parameter and an output schema, the description covers behavior, selection criteria, alternatives, and privacy implications. There are no major gaps an agent would need to resolve.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

All parameters are documented in the schema (100% coverage), including formats and defaults, so the description does not need to repeat them. It adds context about selecting a single metric but does not materially improve on the schema's parameter documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Read one metric's day-by-day values', naming a specific verb, resource, and temporal granularity, and immediately distinguishes itself from read_health_data by noting it omits the other six metrics. This makes the tool's scope unmistakable for an agent.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit 'Use this tool when' and 'Do not use this tool when' guidance, includes concrete user-phrase examples, and names read_health_data as the alternative for broad multi-metric requests. No inference is required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_metric_provenanceBreak a metric down by sourceA
Read-onlyIdempotent

Show one metric's raw measurements for one day, broken down by which source reported them โ€” answers "which one is correct?" when e.g. an Apple Watch and a Garmin disagree on resting heart rate, instead of silently averaging two different devices into one number.

Do not use this tool when:

  • the user just wants a plain day-by-day history for the metric, with no need to see the per-source breakdown -> use get_metric_history instead.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYesThe day to inspect, formatted YYYY-MM-DD.
metricYesName of the metric to inspect, e.g. "resting_heart_rate".

Output Schema

ParametersJSON Schema
NameRequiredDescription
dateYes
metricYes
sourcesYes
conflictYes

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive behavior, and the description adds meaningful context beyond that: it explains the data becomes part of the conversation and may be sent to a cloud model. This is a real behavioral disclosure about data flow and privacy that an agent could not infer from the schema or annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well structured: purpose leads, a do-not-use block clearly distinguishes the sibling tool, and the privacy note is placed at the end. It is longer than strictly necessary because of the privacy explanation, but each paragraph earns its place and the key information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple two-parameter input, full schema coverage, output schema presence, and complete annotations, the description covers what an agent needs to call this tool correctly. The only minor gap is that it does not spell out the exact return shape or whether source values are normalized, but the output schema covers that burden.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers 100% of the two parameters, including formats and examples for `date` and `metric`. The description does not add much beyond the schema, but the terms 'one day' and 'metric' reinforce the single-day, single-metric scope. The schema does the heavy lifting, so a baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a concrete action and resource: 'Show one metric's raw measurements for one day, broken down by which source reported them.' It directly distinguishes the tool from the sibling `get_metric_history` by emphasizing the per-source breakdown and the 'which one is correct?' use case. The verb and scope are specific enough that an agent can tell what it is for.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly names the alternative: 'Do not use this tool when... use `get_metric_history` instead.' It also gives a concrete triggering scenario (e.g., Apple Watch and Garmin disagreeing on resting heart rate), making both when-to-use and when-not-to-use clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_recent_changesGet recent changesA
Read-onlyIdempotent

Scan every (non-private) metric for what's changed lately: a recent period vs. the four-times-as-long period before it (period-over-period shift), any anomalies inside the recent period, and a trend over it. The single best tool to start a "how have I been doing?" conversation with โ€” it does the scanning across all metrics that would otherwise take one get_baseline/detect_metric_anomalies/calculate_metric_trend call per metric.

Do not use this tool when:

  • the user already named a specific metric and wants the full why-bundle for it (value, baseline, anomaly flag, trend, correlated metrics) -> use explain_metric_change instead.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNoLength of the "recent" window in days (default 7). The comparison baseline is the 4x-as-long period immediately before it, so a 7-day recent window compares against the preceding 28 days.

Output Schema

ParametersJSON Schema
NameRequiredDescription
changesYes
recent_rangeYes
baseline_rangeYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint=true and idempotentHint=true, so the safety profile is covered. The description adds valuable context beyond those: it scans all non-private metrics, and it includes a privacy note that returned data becomes part of the model conversation. It doesn't cover every possible behavioral trait, but it goes well beyond the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and never repeats the title. Every section earns its place: purpose, when-to-use, when-not-to-use with a named alternative, and a meaningful privacy caveat. It is longer than average, but the length is justified by actionable content rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only scanning tool with a single optional parameter and an output schema, the description covers everything needed for correct selection and invocation: what it scans, how windows are defined, when to prefer it, when to avoid it, and a privacy consideration. The output schema can carry return-format details, so their absence here is not a gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already fully documents the days parameter and the 4x comparison window. The description reinforces the same semantics without adding new parameter-level meaning. Baseline 3 is appropriate here because the structured schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb ('scan'), the resource ('every non-private metric'), and the exact analysis performed (period-over-period shift, anomalies, trend). It also explicitly differentiates itself from sibling per-metric tools like explain_metric_change, so an agent can tell when this is the cross-metric overview versus a targeted analysis.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states the ideal use case: starting a 'how have I been doing?' conversation across all metrics. It also gives an explicit exclusion: if the user named a specific metric and wants the full why-bundle, use explain_metric_change instead. This gives clear routing guidance beyond what the schema or annotations provide.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

log_daily_metricLog a daily metricA
Idempotent

Record one or more health metrics for a single day, creating that day's row if it doesn't already have one.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

Only the metrics you pass are written โ€” anything left as null is not touched, so logging just today's mood doesn't erase today's steps if they were set earlier. To undo a value logged by mistake, use clear_metric rather than trying to overwrite it with a placeholder.

Use this tool when:

  • the user is recording a simple day-level value for one of the nine fixed metrics below (e.g. "log my weight as 82 kg", "I walked 8,000 steps today").

Do not use this tool when:

  • the observation needs its own timestamp/source, or the day may have more than one reading of the same metric -> use log_measurement instead.

  • it's a workout/exercise session -> use log_workout_session instead (workout_minutes here is just the daily total, not the session itself).

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYesThe day to log, formatted YYYY-MM-DD.
moodNoMood rating on a 1-10 scale.
stepsNoStep count for the day. 0-200,000.
hrv_msNoHeart rate variability in milliseconds. 0-300.
water_mlNoWater intake in millilitres. 0-10,000.
weight_kgNoBody weight in kilograms. 1-500.
heart_rateNoNon-resting heart rate reading in bpm. 20-250.
sleep_hoursNoHours of sleep. 0-24.
workout_minutesNoMinutes of exercise. 0-1,440.
resting_heart_rateNoResting heart rate in bpm. 20-250.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowYes
loggedYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already provide idempotentHint=true, destructiveHint=false, and readOnlyHint=false, and the description extends these with detailed behavioral context: writes are partial-upsert, nulls are not touched, day rows are created when absent, and returned data becomes part of the conversation sent to the model. It also adds a privacy disclosure about local SQLite and cloud models. This goes well beyond what the annotations disclose.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is more verbose than average but every sentence earns its place: the opening purpose statement is front-loaded, then the rationale behind the partial-update behavior, followed by a clear when/when-not block. The privacy note is arguably tangential to successful tool invocation, but it is valuable context that an agent collecting data should know.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 10 parameters, a shared data domain, and several near-sibling tools, the description covers all the essential context: scope, alternatives, parameter semantics, privacy exposure, and the undo path. It does this while an output schema exists, so return values are appropriately left outside the description. Nothing an agent needs to decide or invoke correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite 100% schema description coverage, the description adds meaning the schema alone does not convey: 'anything left as null is not touched' explains the behavioral effect of passing incomplete parameters, and 'workout_minutes here is just the daily total, not the session itself' disambiguates a parameter that could be confused with log_workout_session. The schema contains type/range descriptions for every parameter, so this added guidance elevates the definition well above the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Record one or more health metrics for a single day, creating that day's row if it doesn't already have one.' It distinguishes the tool from similar siblings by explicitly scoping to day-level values and contrasting with log_measurement and log_workout_session. This is unambiguous even before reading any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description contains explicit 'Use this tool when' and 'Do not use this tool when' sections, naming the specific alternatives (log_measurement, log_workout_session) and the exact conditions under which they should be chosen. It also guides cleanup for mistaken logs to clear_metric, leaving no ambiguity about when this tool is appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

log_measurementLog a raw measurementA

Record a single raw observation โ€” one metric, one value, one point in time โ€” rather than a whole day's summary. Use this instead of log_daily_metric when the source, exact time, or the fact that there were multiple readings that day matters (e.g. three separate workouts, or a wearable's periodic heart-rate samples).

Use this tool when:

  • recording one timestamped observation where the exact time, source, or possibility of multiple same-day readings matters (e.g. "record my blood pressure reading from my cuff at 7am").

Do not use this tool when:

  • it's just a single end-of-day value for a fixed metric -> use log_daily_metric instead.

  • it's a workout/exercise session -> use log_workout_session instead.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
unitNoUnit the value is in, e.g. "bpm", "kg". Optional.
valueYesThe numeric reading.
metricYesName of the metric, e.g. "resting_heart_rate", "steps". Free-form โ€” not limited to daily_metrics' fixed columns.
sourceNoWhere this came from, e.g. "Apple Watch", "manual". Optional.
timestampYesWhen the observation was taken, YYYY-MM-DD or a full ISO 8601 timestamp (YYYY-MM-DDTHH:MM:SS).
source_typeNoCategory of source, e.g. "wearable", "manual", "app". Optional.

Output Schema

ParametersJSON Schema
NameRequiredDescription
measurementYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply basic flags (readOnly=false, destructive=false, idempotent=false), so the description adds value by disclosing that data becomes part of the conversation sent to the client's model and noting the local SQLite context. It could add more about duplicate handling or write confirmation, but the output schema and basic annotation profile cover the rest.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core definition, followed by tight bulleted usage rules and a relevant privacy note. Every sentence earns its place; there is no filler or repetition of schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter tool with a full input schema and an output schema, the description covers granularity, sibling routing, and a meaningful privacy behavior. Nothing essential is missing for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds semantic meaning beyond the schema: it frames the event as a raw point-in-time observation versus a daily summary, explains that source/exact-time/multiple-same-day-readings are the deciding factors, and gives a concrete example that maps metric, source, and timestamp to a real use case.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the specific verb 'record' with a clear object ('a single raw observation') and defines the exact scope as one metric, one value, one point in time. It explicitly contrasts itself with log_daily_metric and log_workout_session, so an agent can distinguish it from siblings without inspecting schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit 'Use this tool when' and 'Do not use this tool when' sections, naming the exact alternative tools (log_daily_metric, log_workout_session) and the conditions that route to each. It even includes a concrete example, leaving little to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

log_workout_sessionLog a workout sessionA

Record one workout as a structured event โ€” activity, timing, intensity, and heart-rate response โ€” rather than folding it into the day's workout_minutes total. Use this alongside (not instead of) log_daily_metric/log_measurement for workout_minutes: this is what lets explain_metric_change say what the workout was, not just how long it ran. A day can have more than one session; each call adds a new row.

Use this tool when:

  • the user describes an actual workout/exercise session (e.g. "I went running for 40 minutes", "log today's strength workout").

Do not use this tool when:

  • the user only wants to record the day's total exercise minutes as a single number, with no activity type/timing/intensity -> use log_daily_metric (workout_minutes) or log_measurement instead.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYesThe day the workout happened, YYYY-MM-DD.
notesNoFree-text notes, e.g. route or how it felt. Optional.
sourceNoWhere this came from, e.g. "Apple Watch", "manual". Optional.
intensityNoOne of "low", "moderate", "high". Optional.
start_timeNoWhen it started, HH:MM (24-hour) or a full ISO timestamp. Optional.
activity_typeYesWhat kind of workout, e.g. "running", "cycling", "strength". Free-form.
avg_heart_rateNoAverage heart rate during the workout, bpm. Optional.
max_heart_rateNoPeak heart rate during the workout, bpm. Optional.
duration_minutesYesHow long it lasted, in minutes.

Output Schema

ParametersJSON Schema
NameRequiredDescription
sessionYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint=false, idempotentHint=false, etc., but the description adds important behavior: 'each call adds a new row' clarifies non-idempotence specifics, and the privacy note about data becoming part of the conversation sent to the model is unique contextual disclosure. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with a strong first sentence, followed by structured usage guidance and a privacy note. It is longer than the minimal two-sentence example, but every section contributes value given the tool's complexity and need to disambiguate from siblings. The explicitly labeled sections compensate for length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is complete enough for a 9-parameter tool with 100% schema coverage and an output schema. It covers when to use, when not, privacy implications, and multi-session behavior. No significant context is missing for an agent to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema coverage is 100%, so the schema fully documents each of the 9 parameters. The description adds a high-level grouping ('activity, timing, intensity, heart-rate response') but does not provide parameter-level semantics beyond the schema. Baseline of 3 applies since schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action and resource: 'Record one workout as a structured event โ€” activity, timing, intensity, and heart-rate response.' It explicitly contrasts with log_daily_metric/log_measurement for workout_minutes and explains the relationship to explain_metric_change, distinguishing it from siblings without the need to open schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit 'Use this tool when' and 'Do not use this tool when' sections with concrete examples ('I went running for 40 minutes') and names the exact alternatives (log_daily_metric / log_measurement) for the excluded cases. This goes beyond mere context to actionable selection criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_health_dataRead health dataA
Read-onlyIdempotent

Read daily health metrics from the local database: steps, sleep hours, resting heart rate, weight (kg), workout minutes, mood, and water intake (ml).

Use this tool when:

  • the request is broad/general, across multiple metrics at once (e.g. "what health data do I have?", "overview of this week").

Do not use this tool when:

  • the user wants one specific metric's history/trend over time -> use get_metric_history instead.

  • the user wants raw/individual measurement rows (timestamp, source) -> use read_measurements instead.

  • the user wants workout sessions specifically -> use read_workout_sessions instead.

  • the user is asking why something changed, or wants a trend, anomaly, comparison, or correlation -> use explain_metric_change (one metric, one date) or get_recent_changes (scan across all metrics) instead.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
end_dateNoLast day to include, formatted YYYY-MM-DD. Defaults to today.
start_dateNoFirst day to include, formatted YYYY-MM-DD. Defaults to 30 days before end_date. Ranges over ~10 years are rejected.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsYes
rangeYes
summaryYes
truncatedYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, so the safety profile is covered. The description adds valuable context beyond annotations with the privacy note about data becoming part of the conversation sent to the client's model, and clarifies that the underlying storage is a local SQLite file. Minor missing details like return shape are handled by the output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core behavior, then uses clear use/do-not-use sections, then a privacy caveat. Every sentence earns its place, and the routing content is dense but scannable. The length is justified given the large sibling set.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with an output schema, the description covers purpose, metric scope, parameter behavior via schema, sibling routing, and the privacy implications of the returned data. There are no significant gaps an agent would need to fill before calling it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and both start_date and end_date already have clear format, default, and range-rejection documentation. The description does not add parameter-level detail, but it also does not need to since the schema fully explains them. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb-resource pairing: 'Read daily health metrics from the local database,' and enumerates the exact metrics included. It also distinguishes itself from siblings by emphasizing broad/general access, and the do-not-use list names the precise alternatives. This leaves no ambiguity about what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit use-when criteria ('broad/general, across multiple metrics at once') and a thorough do-not-use section routing to specific sibling tools like get_metric_history, read_measurements, and explain_metric_change. This is model-actionable guidance that prevents selecting the wrong tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_measurementsRead raw measurementsA
Read-onlyIdempotent

Read individual measurement rows (not the daily_metrics aggregate), most recent first. Use this to see exactly when and where each reading came from, rather than just a day's summarized value.

Use this tool when:

  • the user wants raw/individual observations (e.g. "what measurements have I recorded?"), including their timestamp or source.

Do not use this tool when:

  • the user wants a broad, multi-metric overview -> use read_health_data instead.

  • the user wants one metric's day-by-day history -> use get_metric_history instead.

  • the user wants workout sessions -> use read_workout_sessions instead.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum rows to return (default 200).
metricNoOnly return this metric. Omit for all metrics.
sourceNoOnly return rows from this source, e.g. "Apple Watch". Omit for all sources.
end_dateNoOnly return rows on/before this date (YYYY-MM-DD). Omit for no upper bound.
start_dateNoOnly return rows on/after this date (YYYY-MM-DD). Omit for no lower bound.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
measurementsYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool readOnlyHint=true, idempotentHint=true, and destructiveHint=false, and the description adds meaningful behavioral context beyond that: results are ordered most recent first, the tool returns raw rows rather than aggregates, and the privacy note discloses that returned data becomes part of the conversation sent to the model. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, then structured into clear usage and exclusions lists, followed by a well-scoped privacy note. Every sentence earns its place; the formatting makes it easy for an agent to scan for the decision-relevant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, optional-parameter tool with a rich output schema and full schema coverage, the description provides everything an agent needs: what the tool returns, ordering behavior, when to prefer alternatives, and privacy implications. There is no meaningful gap in operational or decision context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema fully documents all five optional parameters. The description adds only indirect context (e.g., that results include timestamps and sources) but does not need to explain parameter syntax or semantics since the schema already handles that burden. Baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Read') with a precise resource ('individual measurement rows'), and immediately distinguishes the tool from the daily_metrics aggregate. It also names the data orientation (most recent first) and what kind of detail it exposes (timestamp/source), making its purpose unambiguous and distinct from sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use the tool with a concrete user-intent example, and provides a dedicated 'Do not use this tool when' section that names three sibling alternatives (read_health_data, get_metric_history, read_workout_sessions). This gives an agent clear routing guidance with no inference required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_workout_sessionsRead workout sessionsA
Read-onlyIdempotent

Read individual workout sessions (not the daily_metrics workout_minutes total), most recent day first. Use this to see what each workout actually was โ€” activity, timing, intensity, heart rate โ€” rather than just a day's summed minutes.

Use this tool when:

  • the user asks about workouts/exercise sessions specifically (e.g. "what workouts did I do this week?", "show my recent gym sessions").

Do not use this tool when:

  • the user just wants the daily workout_minutes total, not individual sessions -> use read_health_data or get_metric_history instead.

Privacy note: this server and its SQLite file are entirely local, but the data returned by this tool becomes part of the conversation sent to whatever model the calling client is configured with. If that model runs in the cloud rather than on your machine, treat this the same as pasting the data into a chat with that provider.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum rows to return (default 200).
end_dateNoOnly return sessions on/before this date (YYYY-MM-DD). Omit for no upper bound.
start_dateNoOnly return sessions on/after this date (YYYY-MM-DD). Omit for no lower bound.
activity_typeNoOnly return sessions of this activity type. Omit for all types.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
sessionsYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnly, idempotent, non-destructive), the description adds genuinely useful behavioral context: ordering is 'most recent day first,' the tool returns session-level detail rather than daily totals, and it discloses a privacy implication about data becoming part of the conversation. These are meaningful traits not captured by the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core definition, followed by structured usage guidance and a relevant privacy note. Every section earns its place: the first sentence states the tool's scope, the bullets give actionable routing rules, and the privacy note is important for local-vs-cloud model contexts. No filler is present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the rich annotations, full parameter schema coverage, and presence of an output schema, the description supplies all remaining context an agent needs: when to use it, when not to, how results are ordered, and what data is returned. The alternative tools are explicitly named, so the surrounding tool ecosystem is adequately addressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents limit, start_date, end_date, and activity_type fully. The description reinforces the overall intent but does not add parameter-specific detail beyond what the input schema provides, matching the baseline for full schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise verb and resource: 'Read individual workout sessions,' and immediately disambiguates from the daily_metrics workout_minutes total. It also enumerates the meaningful fields returned (activity, timing, intensity, heart rate) and contrast with daily aggregates, making the tool's purpose unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit 'Use this tool when' and 'Do not use this tool when' sections with concrete example queries and names the alternatives (read_health_data, get_metric_history). An agent can confidently route between this tool and its siblings without further inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 7 tool updates
    • Changedcalculate_metric_trend2 fields changed
      • addedOutput schema / properties / evidence
        Added value: +{
        +  "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +  "properties": {
        +    "confidence": {
        +      "type": "string"
        +    },
        +    "coverage_ratio": {
        +      "type": "number"
        +    },
        +    "expected_days": {
        +      "type": "integer"
        +    },
        +    "freshness_days": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "gaps": {
        +      "items": {
        +        "properties": {
        +          "days": {
        +            "type": "integer"
        +          },
        +          "end": {
        +            "type": "string"
        +          },
        +          "start": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "start",
        +          "end",
        +          "days"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "measurement_count": {
        +      "type": "integer"
        +    },
        +    "missing_days": {
        +      "type": "integer"
        +    },
        +    "observed_days": {
        +      "type": "integer"
        +    },
        +    "observed_end": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "observed_start": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "recent_gap_days": {
        +      "type": "integer"
        +    },
        +    "requested_end": {
        +      "type": "string"
        +    },
        +    "requested_start": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "requested_start",
        +    "requested_end",
        +    "expected_days",
        +    "observed_days",
        +    "coverage_ratio",
        +    "missing_days",
        +    "measurement_count",
        +    "gaps",
        +    "recent_gap_days",
        +    "confidence"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "metric",
        -  "range",
        -  "trend"
        -]New value: +[
        +  "metric",
        +  "range",
        +  "trend",
        +  "evidence"
        +]
    • Changedcompare_metric_periods3 fields changed
      • addedOutput schema / properties / period_a_evidence
        Added value: +{
        +  "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +  "properties": {
        +    "confidence": {
        +      "type": "string"
        +    },
        +    "coverage_ratio": {
        +      "type": "number"
        +    },
        +    "expected_days": {
        +      "type": "integer"
        +    },
        +    "freshness_days": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "gaps": {
        +      "items": {
        +        "properties": {
        +          "days": {
        +            "type": "integer"
        +          },
        +          "end": {
        +            "type": "string"
        +          },
        +          "start": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "start",
        +          "end",
        +          "days"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "measurement_count": {
        +      "type": "integer"
        +    },
        +    "missing_days": {
        +      "type": "integer"
        +    },
        +    "observed_days": {
        +      "type": "integer"
        +    },
        +    "observed_end": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "observed_start": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "recent_gap_days": {
        +      "type": "integer"
        +    },
        +    "requested_end": {
        +      "type": "string"
        +    },
        +    "requested_start": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "requested_start",
        +    "requested_end",
        +    "expected_days",
        +    "observed_days",
        +    "coverage_ratio",
        +    "missing_days",
        +    "measurement_count",
        +    "gaps",
        +    "recent_gap_days",
        +    "confidence"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / period_b_evidence
        Added value: +{
        +  "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +  "properties": {
        +    "confidence": {
        +      "type": "string"
        +    },
        +    "coverage_ratio": {
        +      "type": "number"
        +    },
        +    "expected_days": {
        +      "type": "integer"
        +    },
        +    "freshness_days": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "gaps": {
        +      "items": {
        +        "properties": {
        +          "days": {
        +            "type": "integer"
        +          },
        +          "end": {
        +            "type": "string"
        +          },
        +          "start": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "start",
        +          "end",
        +          "days"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "measurement_count": {
        +      "type": "integer"
        +    },
        +    "missing_days": {
        +      "type": "integer"
        +    },
        +    "observed_days": {
        +      "type": "integer"
        +    },
        +    "observed_end": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "observed_start": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "recent_gap_days": {
        +      "type": "integer"
        +    },
        +    "requested_end": {
        +      "type": "string"
        +    },
        +    "requested_start": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "requested_start",
        +    "requested_end",
        +    "expected_days",
        +    "observed_days",
        +    "coverage_ratio",
        +    "missing_days",
        +    "measurement_count",
        +    "gaps",
        +    "recent_gap_days",
        +    "confidence"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "metric",
        -  "period_a",
        -  "period_b",
        -  "period_a_stats",
        -  "period_b_stats"
        -]New value: +[
        +  "metric",
        +  "period_a",
        +  "period_b",
        +  "period_a_stats",
        +  "period_b_stats",
        +  "period_a_evidence",
        +  "period_b_evidence"
        +]
    • Changeddetect_metric_anomalies2 fields changed
      • addedOutput schema / properties / evidence
        Added value: +{
        +  "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +  "properties": {
        +    "confidence": {
        +      "type": "string"
        +    },
        +    "coverage_ratio": {
        +      "type": "number"
        +    },
        +    "expected_days": {
        +      "type": "integer"
        +    },
        +    "freshness_days": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "gaps": {
        +      "items": {
        +        "properties": {
        +          "days": {
        +            "type": "integer"
        +          },
        +          "end": {
        +            "type": "string"
        +          },
        +          "start": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "start",
        +          "end",
        +          "days"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "measurement_count": {
        +      "type": "integer"
        +    },
        +    "missing_days": {
        +      "type": "integer"
        +    },
        +    "observed_days": {
        +      "type": "integer"
        +    },
        +    "observed_end": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "observed_start": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "recent_gap_days": {
        +      "type": "integer"
        +    },
        +    "requested_end": {
        +      "type": "string"
        +    },
        +    "requested_start": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "requested_start",
        +    "requested_end",
        +    "expected_days",
        +    "observed_days",
        +    "coverage_ratio",
        +    "missing_days",
        +    "measurement_count",
        +    "gaps",
        +    "recent_gap_days",
        +    "confidence"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "metric",
        -  "range",
        -  "threshold",
        -  "anomalies"
        -]New value: +[
        +  "metric",
        +  "range",
        +  "threshold",
        +  "anomalies",
        +  "evidence"
        +]
    • Changedexplain_metric_change5 fields changed
      • addedOutput schema / properties / baseline_evidence
        Added value: +{
        +  "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +  "properties": {
        +    "confidence": {
        +      "type": "string"
        +    },
        +    "coverage_ratio": {
        +      "type": "number"
        +    },
        +    "expected_days": {
        +      "type": "integer"
        +    },
        +    "freshness_days": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "gaps": {
        +      "items": {
        +        "properties": {
        +          "days": {
        +            "type": "integer"
        +          },
        +          "end": {
        +            "type": "string"
        +          },
        +          "start": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "start",
        +          "end",
        +          "days"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "measurement_count": {
        +      "type": "integer"
        +    },
        +    "missing_days": {
        +      "type": "integer"
        +    },
        +    "observed_days": {
        +      "type": "integer"
        +    },
        +    "observed_end": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "observed_start": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "recent_gap_days": {
        +      "type": "integer"
        +    },
        +    "requested_end": {
        +      "type": "string"
        +    },
        +    "requested_start": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "requested_start",
        +    "requested_end",
        +    "expected_days",
        +    "observed_days",
        +    "coverage_ratio",
        +    "missing_days",
        +    "measurement_count",
        +    "gaps",
        +    "recent_gap_days",
        +    "confidence"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / correlated_metrics / items / properties / evidence_a
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +      "properties": {
        +        "confidence": {
        +          "type": "string"
        +        },
        +        "coverage_ratio": {
        +          "type": "number"
        +        },
        +        "expected_days": {
        +          "type": "integer"
        +        },
        +        "freshness_days": {
        +          "anyOf": [
        +            {
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "gaps": {
        +          "items": {
        +            "properties": {
        +              "days": {
        +                "type": "integer"
        +              },
        +              "end": {
        +                "type": "string"
        +              },
        +              "start": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "start",
        +              "end",
        +              "days"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "measurement_count": {
        +          "type": "integer"
        +        },
        +        "missing_days": {
        +          "type": "integer"
        +        },
        +        "observed_days": {
        +          "type": "integer"
        +        },
        +        "observed_end": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "observed_start": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "recent_gap_days": {
        +          "type": "integer"
        +        },
        +        "requested_end": {
        +          "type": "string"
        +        },
        +        "requested_start": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "requested_start",
        +        "requested_end",
        +        "expected_days",
        +        "observed_days",
        +        "coverage_ratio",
        +        "missing_days",
        +        "measurement_count",
        +        "gaps",
        +        "recent_gap_days",
        +        "confidence"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / correlated_metrics / items / properties / evidence_b
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +      "properties": {
        +        "confidence": {
        +          "type": "string"
        +        },
        +        "coverage_ratio": {
        +          "type": "number"
        +        },
        +        "expected_days": {
        +          "type": "integer"
        +        },
        +        "freshness_days": {
        +          "anyOf": [
        +            {
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "gaps": {
        +          "items": {
        +            "properties": {
        +              "days": {
        +                "type": "integer"
        +              },
        +              "end": {
        +                "type": "string"
        +              },
        +              "start": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "start",
        +              "end",
        +              "days"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "measurement_count": {
        +          "type": "integer"
        +        },
        +        "missing_days": {
        +          "type": "integer"
        +        },
        +        "observed_days": {
        +          "type": "integer"
        +        },
        +        "observed_end": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "observed_start": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "recent_gap_days": {
        +          "type": "integer"
        +        },
        +        "requested_end": {
        +          "type": "string"
        +        },
        +        "requested_start": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "requested_start",
        +        "requested_end",
        +        "expected_days",
        +        "observed_days",
        +        "coverage_ratio",
        +        "missing_days",
        +        "measurement_count",
        +        "gaps",
        +        "recent_gap_days",
        +        "confidence"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / trend_evidence
        Added value: +{
        +  "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +  "properties": {
        +    "confidence": {
        +      "type": "string"
        +    },
        +    "coverage_ratio": {
        +      "type": "number"
        +    },
        +    "expected_days": {
        +      "type": "integer"
        +    },
        +    "freshness_days": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "gaps": {
        +      "items": {
        +        "properties": {
        +          "days": {
        +            "type": "integer"
        +          },
        +          "end": {
        +            "type": "string"
        +          },
        +          "start": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "start",
        +          "end",
        +          "days"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "measurement_count": {
        +      "type": "integer"
        +    },
        +    "missing_days": {
        +      "type": "integer"
        +    },
        +    "observed_days": {
        +      "type": "integer"
        +    },
        +    "observed_end": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "observed_start": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "recent_gap_days": {
        +      "type": "integer"
        +    },
        +    "requested_end": {
        +      "type": "string"
        +    },
        +    "requested_start": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "requested_start",
        +    "requested_end",
        +    "expected_days",
        +    "observed_days",
        +    "coverage_ratio",
        +    "missing_days",
        +    "measurement_count",
        +    "gaps",
        +    "recent_gap_days",
        +    "confidence"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "metric",
        -  "date",
        -  "baseline_range",
        -  "baseline",
        -  "is_anomaly",
        -  "trend",
        -  "correlated_metrics",
        -  "narrative_facts"
        -]New value: +[
        +  "metric",
        +  "date",
        +  "baseline_range",
        +  "baseline",
        +  "is_anomaly",
        +  "trend",
        +  "correlated_metrics",
        +  "narrative_facts",
        +  "baseline_evidence",
        +  "trend_evidence"
        +]
    • Changedfind_metric_correlation2 fields changed
      • addedOutput schema / properties / evidence_a
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +      "properties": {
        +        "confidence": {
        +          "type": "string"
        +        },
        +        "coverage_ratio": {
        +          "type": "number"
        +        },
        +        "expected_days": {
        +          "type": "integer"
        +        },
        +        "freshness_days": {
        +          "anyOf": [
        +            {
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "gaps": {
        +          "items": {
        +            "properties": {
        +              "days": {
        +                "type": "integer"
        +              },
        +              "end": {
        +                "type": "string"
        +              },
        +              "start": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "start",
        +              "end",
        +              "days"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "measurement_count": {
        +          "type": "integer"
        +        },
        +        "missing_days": {
        +          "type": "integer"
        +        },
        +        "observed_days": {
        +          "type": "integer"
        +        },
        +        "observed_end": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "observed_start": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "recent_gap_days": {
        +          "type": "integer"
        +        },
        +        "requested_end": {
        +          "type": "string"
        +        },
        +        "requested_start": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "requested_start",
        +        "requested_end",
        +        "expected_days",
        +        "observed_days",
        +        "coverage_ratio",
        +        "missing_days",
        +        "measurement_count",
        +        "gaps",
        +        "recent_gap_days",
        +        "confidence"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / evidence_b
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +      "properties": {
        +        "confidence": {
        +          "type": "string"
        +        },
        +        "coverage_ratio": {
        +          "type": "number"
        +        },
        +        "expected_days": {
        +          "type": "integer"
        +        },
        +        "freshness_days": {
        +          "anyOf": [
        +            {
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "gaps": {
        +          "items": {
        +            "properties": {
        +              "days": {
        +                "type": "integer"
        +              },
        +              "end": {
        +                "type": "string"
        +              },
        +              "start": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "start",
        +              "end",
        +              "days"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "measurement_count": {
        +          "type": "integer"
        +        },
        +        "missing_days": {
        +          "type": "integer"
        +        },
        +        "observed_days": {
        +          "type": "integer"
        +        },
        +        "observed_end": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "observed_start": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "recent_gap_days": {
        +          "type": "integer"
        +        },
        +        "requested_end": {
        +          "type": "string"
        +        },
        +        "requested_start": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "requested_start",
        +        "requested_end",
        +        "expected_days",
        +        "observed_days",
        +        "coverage_ratio",
        +        "missing_days",
        +        "measurement_count",
        +        "gaps",
        +        "recent_gap_days",
        +        "confidence"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
    • Changedget_baseline2 fields changed
      • addedOutput schema / properties / evidence
        Added value: +{
        +  "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +  "properties": {
        +    "confidence": {
        +      "type": "string"
        +    },
        +    "coverage_ratio": {
        +      "type": "number"
        +    },
        +    "expected_days": {
        +      "type": "integer"
        +    },
        +    "freshness_days": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "gaps": {
        +      "items": {
        +        "properties": {
        +          "days": {
        +            "type": "integer"
        +          },
        +          "end": {
        +            "type": "string"
        +          },
        +          "start": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "start",
        +          "end",
        +          "days"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "measurement_count": {
        +      "type": "integer"
        +    },
        +    "missing_days": {
        +      "type": "integer"
        +    },
        +    "observed_days": {
        +      "type": "integer"
        +    },
        +    "observed_end": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "observed_start": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "recent_gap_days": {
        +      "type": "integer"
        +    },
        +    "requested_end": {
        +      "type": "string"
        +    },
        +    "requested_start": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "requested_start",
        +    "requested_end",
        +    "expected_days",
        +    "observed_days",
        +    "coverage_ratio",
        +    "missing_days",
        +    "measurement_count",
        +    "gaps",
        +    "recent_gap_days",
        +    "confidence"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "metric",
        -  "range",
        -  "baseline"
        -]New value: +[
        +  "metric",
        +  "range",
        +  "baseline",
        +  "evidence"
        +]
    • Changedget_metric_history2 fields changed
      • addedOutput schema / properties / evidence
        Added value: +{
        +  "description": "Coverage/quality of the data a single-metric analytical result is\nbased on. See evidence.build_evidence for how each field is computed.",
        +  "properties": {
        +    "confidence": {
        +      "type": "string"
        +    },
        +    "coverage_ratio": {
        +      "type": "number"
        +    },
        +    "expected_days": {
        +      "type": "integer"
        +    },
        +    "freshness_days": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "gaps": {
        +      "items": {
        +        "properties": {
        +          "days": {
        +            "type": "integer"
        +          },
        +          "end": {
        +            "type": "string"
        +          },
        +          "start": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "start",
        +          "end",
        +          "days"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "measurement_count": {
        +      "type": "integer"
        +    },
        +    "missing_days": {
        +      "type": "integer"
        +    },
        +    "observed_days": {
        +      "type": "integer"
        +    },
        +    "observed_end": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "observed_start": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "recent_gap_days": {
        +      "type": "integer"
        +    },
        +    "requested_end": {
        +      "type": "string"
        +    },
        +    "requested_start": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "requested_start",
        +    "requested_end",
        +    "expected_days",
        +    "observed_days",
        +    "coverage_ratio",
        +    "missing_days",
        +    "measurement_count",
        +    "gaps",
        +    "recent_gap_days",
        +    "confidence"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "metric",
        -  "range",
        -  "points"
        -]New value: +[
        +  "metric",
        +  "range",
        +  "points",
        +  "evidence"
        +]
  2. 27 tool updatesv1.0.16
    • Addedaggregate_measurements
    • Addedcalculate_metric_trend
    • Removedclear_daily_metric
    • Removedclear_daily_metrics_range
    • Addedclear_metric
    • Addedcompare_metric_periods
    • Removeddelete_measurement
    • Removeddelete_workout
    • Addeddetect_metric_anomalies
    • Addedexplain_metric_change
    • Addedexport_health_data_csv
    • Addedfind_metric_correlation
    • Addedget_baseline
    • Addedget_metric_history
    • Addedget_metric_provenance
    • Addedget_recent_changes
    • Changedlog_daily_metric15 fields changed
      • addedInput schema / properties / date / description
        Added value: +"The day to log, formatted YYYY-MM-DD."
      • addedInput schema / properties / heart_rate
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Non-resting heart rate reading in bpm. 20-250."
        +}
      • addedInput schema / properties / hrv_ms
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Heart rate variability in milliseconds. 0-300."
        +}
      • addedInput schema / properties / mood
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Mood rating on a 1-10 scale."
        +}
      • addedInput schema / properties / resting_heart_rate / description
        Added value: +"Resting heart rate in bpm. 20-250."
      • addedInput schema / properties / sleep_hours / description
        Added value: +"Hours of sleep. 0-24."
      • addedInput schema / properties / steps / description
        Added value: +"Step count for the day. 0-200,000."
      • addedInput schema / properties / water_ml
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Water intake in millilitres. 0-10,000."
        +}
      • addedInput schema / properties / weight_kg
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Body weight in kilograms. 1-500."
        +}
      • addedInput schema / properties / workout_minutes
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Minutes of exercise. 0-1,440."
        +}
      • addedOutput schema / properties / logged
        Added value: +{
        +  "additionalProperties": {
        +    "anyOf": [
        +      {
        +        "type": "integer"
        +      },
        +      {
        +        "type": "number"
        +      }
        +    ]
        +  },
        +  "type": "object"
        +}
      • removedOutput schema / properties / result
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / row
        Added value: +{
        +  "properties": {
        +    "date": {
        +      "type": "string"
        +    },
        +    "heart_rate": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "hrv_ms": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "mood": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "resting_heart_rate": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "sleep_hours": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "steps": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "water_ml": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "weight_kg": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "workout_minutes": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    }
        +  },
        +  "required": [
        +    "date"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "result"
        -]New value: +[
        +  "logged",
        +  "row"
        +]
      • removedOutput schema / x-fastmcp-wrap-result
        Removed value: -true
    • Changedlog_measurement14 fields changed
      • removedInput schema / properties / date
        Removed value: -{
        -  "type": "string"
        -}
      • addedInput schema / properties / metric
        Added value: +{
        +  "description": "Name of the metric, e.g. \"resting_heart_rate\", \"steps\".\nFree-form โ€” not limited to daily_metrics' fixed columns.",
        +  "type": "string"
        +}
      • removedInput schema / properties / metric_name
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / notes
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null
        -}
      • addedInput schema / properties / source
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Where this came from, e.g. \"Apple Watch\", \"manual\". Optional."
        +}
      • addedInput schema / properties / source_type
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Category of source, e.g. \"wearable\", \"manual\", \"app\". Optional."
        +}
      • addedInput schema / properties / timestamp
        Added value: +{
        +  "description": "When the observation was taken, YYYY-MM-DD or a full\nISO 8601 timestamp (YYYY-MM-DDTHH:MM:SS).",
        +  "type": "string"
        +}
      • addedInput schema / properties / unit / description
        Added value: +"Unit the value is in, e.g. \"bpm\", \"kg\". Optional."
      • addedInput schema / properties / value / description
        Added value: +"The numeric reading."
      • changedInput schema / required
        Previous value: -[
        -  "date",
        -  "metric_name",
        -  "value"
        -]New value: +[
        +  "timestamp",
        +  "metric",
        +  "value"
        +]
      • addedOutput schema / properties / measurement
        Added value: +{
        +  "properties": {
        +    "created_at": {
        +      "type": "string"
        +    },
        +    "id": {
        +      "type": "integer"
        +    },
        +    "metric": {
        +      "type": "string"
        +    },
        +    "source": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "source_type": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "timestamp": {
        +      "type": "string"
        +    },
        +    "unit": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "value": {
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "timestamp",
        +    "metric",
        +    "value",
        +    "created_at"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / result
        Removed value: -{
        -  "type": "string"
        -}
      • changedOutput schema / required
        Previous value: -[
        -  "result"
        -]New value: +[
        +  "measurement"
        +]
      • removedOutput schema / x-fastmcp-wrap-result
        Removed value: -true
    • Removedlog_workout
    • Addedlog_workout_session
    • Removedread_finance_data
    • Changedread_health_data9 fields changed
      • addedInput schema / properties / end_date / description
        Added value: +"Last day to include, formatted YYYY-MM-DD. Defaults to today."
      • addedInput schema / properties / start_date / description
        Added value: +"First day to include, formatted YYYY-MM-DD.\nDefaults to 30 days before end_date. Ranges over ~10 years are rejected."
      • addedOutput schema / properties / range
        Added value: +{
        +  "properties": {
        +    "end_date": {
        +      "type": "string"
        +    },
        +    "start_date": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "start_date",
        +    "end_date"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / result
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / rows
        Added value: +{
        +  "items": {
        +    "properties": {
        +      "date": {
        +        "type": "string"
        +      },
        +      "heart_rate": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "hrv_ms": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "mood": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "resting_heart_rate": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "sleep_hours": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "steps": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "water_ml": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "weight_kg": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "workout_minutes": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      }
        +    },
        +    "required": [
        +      "date"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / summary
        Added value: +{
        +  "properties": {
        +    "days_with_data": {
        +      "type": "integer"
        +    },
        +    "heart_rate": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "hrv_ms": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "mood": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "resting_heart_rate": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "sleep_hours": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "steps": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "water_ml": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "weight_kg": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "workout_minutes": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "days_with_data",
        +    "steps",
        +    "sleep_hours",
        +    "resting_heart_rate",
        +    "weight_kg",
        +    "workout_minutes",
        +    "mood",
        +    "water_ml",
        +    "heart_rate",
        +    "hrv_ms"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "result"
        -]New value: +[
        +  "range",
        +  "rows",
        +  "truncated",
        +  "summary"
        +]
      • removedOutput schema / x-fastmcp-wrap-result
        Removed value: -true
    • Addedread_measurements
    • Addedread_workout_sessions
    • Removedupdate_daily_metric
    • Removedupdate_measurement
    • Removedupdate_workout
  3. 27 tool updatesv1.0.15
    • Removedaggregate_measurements
    • Removedcalculate_metric_trend
    • Addedclear_daily_metric
    • Addedclear_daily_metrics_range
    • Removedclear_metric
    • Removedcompare_metric_periods
    • Addeddelete_measurement
    • Addeddelete_workout
    • Removeddetect_metric_anomalies
    • Removedexplain_metric_change
    • Removedexport_health_data_csv
    • Removedfind_metric_correlation
    • Removedget_baseline
    • Removedget_metric_history
    • Removedget_metric_provenance
    • Removedget_recent_changes
    • Changedlog_daily_metric15 fields changed
      • removedInput schema / properties / date / description
        Removed value: -"The day to log, formatted YYYY-MM-DD."
      • removedInput schema / properties / heart_rate
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "integer"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "description": "Non-resting heart rate reading in bpm. 20-250."
        -}
      • removedInput schema / properties / hrv_ms
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "description": "Heart rate variability in milliseconds. 0-300."
        -}
      • removedInput schema / properties / mood
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "integer"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "description": "Mood rating on a 1-10 scale."
        -}
      • removedInput schema / properties / resting_heart_rate / description
        Removed value: -"Resting heart rate in bpm. 20-250."
      • removedInput schema / properties / sleep_hours / description
        Removed value: -"Hours of sleep. 0-24."
      • removedInput schema / properties / steps / description
        Removed value: -"Step count for the day. 0-200,000."
      • removedInput schema / properties / water_ml
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "integer"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "description": "Water intake in millilitres. 0-10,000."
        -}
      • removedInput schema / properties / weight_kg
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "description": "Body weight in kilograms. 1-500."
        -}
      • removedInput schema / properties / workout_minutes
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "integer"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "description": "Minutes of exercise. 0-1,440."
        -}
      • removedOutput schema / properties / logged
        Removed value: -{
        -  "additionalProperties": {
        -    "anyOf": [
        -      {
        -        "type": "integer"
        -      },
        -      {
        -        "type": "number"
        -      }
        -    ]
        -  },
        -  "type": "object"
        -}
      • addedOutput schema / properties / result
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / row
        Removed value: -{
        -  "properties": {
        -    "date": {
        -      "type": "string"
        -    },
        -    "heart_rate": {
        -      "anyOf": [
        -        {
        -          "type": "integer"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "hrv_ms": {
        -      "anyOf": [
        -        {
        -          "type": "number"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "mood": {
        -      "anyOf": [
        -        {
        -          "type": "integer"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "resting_heart_rate": {
        -      "anyOf": [
        -        {
        -          "type": "integer"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "sleep_hours": {
        -      "anyOf": [
        -        {
        -          "type": "number"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "steps": {
        -      "anyOf": [
        -        {
        -          "type": "integer"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "water_ml": {
        -      "anyOf": [
        -        {
        -          "type": "integer"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "weight_kg": {
        -      "anyOf": [
        -        {
        -          "type": "number"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "workout_minutes": {
        -      "anyOf": [
        -        {
        -          "type": "integer"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    }
        -  },
        -  "required": [
        -    "date"
        -  ],
        -  "type": "object"
        -}
      • changedOutput schema / required
        Previous value: -[
        -  "logged",
        -  "row"
        -]New value: +[
        +  "result"
        +]
      • addedOutput schema / x-fastmcp-wrap-result
        Added value: +true
    • Changedlog_measurement14 fields changed
      • addedInput schema / properties / date
        Added value: +{
        +  "type": "string"
        +}
      • removedInput schema / properties / metric
        Removed value: -{
        -  "description": "Name of the metric, e.g. \"resting_heart_rate\", \"steps\".\nFree-form โ€” not limited to daily_metrics' fixed columns.",
        -  "type": "string"
        -}
      • addedInput schema / properties / metric_name
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / notes
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • removedInput schema / properties / source
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "description": "Where this came from, e.g. \"Apple Watch\", \"manual\". Optional."
        -}
      • removedInput schema / properties / source_type
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "description": "Category of source, e.g. \"wearable\", \"manual\", \"app\". Optional."
        -}
      • removedInput schema / properties / timestamp
        Removed value: -{
        -  "description": "When the observation was taken, YYYY-MM-DD or a full\nISO 8601 timestamp (YYYY-MM-DDTHH:MM:SS).",
        -  "type": "string"
        -}
      • removedInput schema / properties / unit / description
        Removed value: -"Unit the value is in, e.g. \"bpm\", \"kg\". Optional."
      • removedInput schema / properties / value / description
        Removed value: -"The numeric reading."
      • changedInput schema / required
        Previous value: -[
        -  "timestamp",
        -  "metric",
        -  "value"
        -]New value: +[
        +  "date",
        +  "metric_name",
        +  "value"
        +]
      • removedOutput schema / properties / measurement
        Removed value: -{
        -  "properties": {
        -    "created_at": {
        -      "type": "string"
        -    },
        -    "id": {
        -      "type": "integer"
        -    },
        -    "metric": {
        -      "type": "string"
        -    },
        -    "source": {
        -      "anyOf": [
        -        {
        -          "type": "string"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "source_type": {
        -      "anyOf": [
        -        {
        -          "type": "string"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "timestamp": {
        -      "type": "string"
        -    },
        -    "unit": {
        -      "anyOf": [
        -        {
        -          "type": "string"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ],
        -      "default": null
        -    },
        -    "value": {
        -      "type": "number"
        -    }
        -  },
        -  "required": [
        -    "id",
        -    "timestamp",
        -    "metric",
        -    "value",
        -    "created_at"
        -  ],
        -  "type": "object"
        -}
      • addedOutput schema / properties / result
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "measurement"
        -]New value: +[
        +  "result"
        +]
      • addedOutput schema / x-fastmcp-wrap-result
        Added value: +true
    • Addedlog_workout
    • Removedlog_workout_session
    • Addedread_finance_data
    • Changedread_health_data9 fields changed
      • removedInput schema / properties / end_date / description
        Removed value: -"Last day to include, formatted YYYY-MM-DD. Defaults to today."
      • removedInput schema / properties / start_date / description
        Removed value: -"First day to include, formatted YYYY-MM-DD.\nDefaults to 30 days before end_date. Ranges over ~10 years are rejected."
      • removedOutput schema / properties / range
        Removed value: -{
        -  "properties": {
        -    "end_date": {
        -      "type": "string"
        -    },
        -    "start_date": {
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "start_date",
        -    "end_date"
        -  ],
        -  "type": "object"
        -}
      • addedOutput schema / properties / result
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / rows
        Removed value: -{
        -  "items": {
        -    "properties": {
        -      "date": {
        -        "type": "string"
        -      },
        -      "heart_rate": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "hrv_ms": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "mood": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "resting_heart_rate": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "sleep_hours": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "steps": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "water_ml": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "weight_kg": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "workout_minutes": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      }
        -    },
        -    "required": [
        -      "date"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / summary
        Removed value: -{
        -  "properties": {
        -    "days_with_data": {
        -      "type": "integer"
        -    },
        -    "heart_rate": {
        -      "properties": {
        -        "avg": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "max": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "min": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "hrv_ms": {
        -      "properties": {
        -        "avg": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "max": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "min": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "mood": {
        -      "properties": {
        -        "avg": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "max": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "min": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "resting_heart_rate": {
        -      "properties": {
        -        "avg": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "max": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "min": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "sleep_hours": {
        -      "properties": {
        -        "avg": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "max": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "min": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "steps": {
        -      "properties": {
        -        "avg": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "max": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "min": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "water_ml": {
        -      "properties": {
        -        "avg": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "max": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "min": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "weight_kg": {
        -      "properties": {
        -        "avg": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "max": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "min": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "workout_minutes": {
        -      "properties": {
        -        "avg": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "max": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "min": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        }
        -      },
        -      "type": "object"
        -    }
        -  },
        -  "required": [
        -    "days_with_data",
        -    "steps",
        -    "sleep_hours",
        -    "resting_heart_rate",
        -    "weight_kg",
        -    "workout_minutes",
        -    "mood",
        -    "water_ml",
        -    "heart_rate",
        -    "hrv_ms"
        -  ],
        -  "type": "object"
        -}
      • removedOutput schema / properties / truncated
        Removed value: -{
        -  "type": "boolean"
        -}
      • changedOutput schema / required
        Previous value: -[
        -  "range",
        -  "rows",
        -  "truncated",
        -  "summary"
        -]New value: +[
        +  "result"
        +]
      • addedOutput schema / x-fastmcp-wrap-result
        Added value: +true
    • Removedread_measurements
    • Removedread_workout_sessions
    • Addedupdate_daily_metric
    • Addedupdate_measurement
    • Addedupdate_workout
  4. 3 tool updatesv0.3.0
    • Changedexplain_metric_change1 field changed
      • addedOutput schema / properties / sessions
        Added value: +{
        +  "default": [],
        +  "items": {
        +    "properties": {
        +      "activity_type": {
        +        "type": "string"
        +      },
        +      "avg_heart_rate": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "created_at": {
        +        "type": "string"
        +      },
        +      "date": {
        +        "type": "string"
        +      },
        +      "duration_minutes": {
        +        "type": "integer"
        +      },
        +      "id": {
        +        "type": "integer"
        +      },
        +      "intensity": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "max_heart_rate": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "notes": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "source": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "start_time": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "date",
        +      "activity_type",
        +      "duration_minutes",
        +      "created_at"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
    • Addedlog_workout_session
    • Addedread_workout_sessions
  5. 16 tool updatesv1.0.11
    • Addedaggregate_measurements
    • Addedcalculate_metric_trend
    • Changedclear_metric2 fields changed
      • changedInput schema / properties / field / description
        Previous value: -"Which metric to blank out. One of: steps, sleep_hours,\nresting_heart_rate, weight_kg, workout_minutes, mood, water_ml."New value: +"Which metric to blank out. One of: steps, sleep_hours,\nresting_heart_rate, weight_kg, workout_minutes, mood, water_ml, heart_rate, hrv_ms."
      • changedOutput schema / properties / row / anyOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "date": {
        -        "type": "string"
        -      },
        -      "mood": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "resting_heart_rate": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "sleep_hours": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "steps": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "water_ml": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "weight_kg": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      },
        -      "workout_minutes": {
        -        "anyOf": [
        -          {
        -            "type": "integer"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "default": null
        -      }
        -    },
        -    "required": [
        -      "date"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "date": {
        +        "type": "string"
        +      },
        +      "heart_rate": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "hrv_ms": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "mood": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "resting_heart_rate": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "sleep_hours": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "steps": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "water_ml": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "weight_kg": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "workout_minutes": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      }
        +    },
        +    "required": [
        +      "date"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Addedcompare_metric_periods
    • Addeddetect_metric_anomalies
    • Addedexplain_metric_change
    • Addedexport_health_data_csv
    • Addedfind_metric_correlation
    • Addedget_baseline
    • Addedget_metric_history
    • Addedget_metric_provenance
    • Addedget_recent_changes
    • Changedlog_daily_metric4 fields changed
      • addedInput schema / properties / heart_rate
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Non-resting heart rate reading in bpm. 20-250."
        +}
      • addedInput schema / properties / hrv_ms
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Heart rate variability in milliseconds. 0-300."
        +}
      • addedOutput schema / properties / row / properties / heart_rate
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / row / properties / hrv_ms
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
    • Addedlog_measurement
    • Changedread_health_data5 fields changed
      • addedOutput schema / properties / rows / items / properties / heart_rate
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / rows / items / properties / hrv_ms
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / summary / properties / heart_rate
        Added value: +{
        +  "properties": {
        +    "avg": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "max": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "min": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    }
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / summary / properties / hrv_ms
        Added value: +{
        +  "properties": {
        +    "avg": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "max": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "min": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    }
        +  },
        +  "type": "object"
        +}
      • changedOutput schema / properties / summary / required
        Previous value: -[
        -  "days_with_data",
        -  "steps",
        -  "sleep_hours",
        -  "resting_heart_rate",
        -  "weight_kg",
        -  "workout_minutes",
        -  "mood",
        -  "water_ml"
        -]New value: +[
        +  "days_with_data",
        +  "steps",
        +  "sleep_hours",
        +  "resting_heart_rate",
        +  "weight_kg",
        +  "workout_minutes",
        +  "mood",
        +  "water_ml",
        +  "heart_rate",
        +  "hrv_ms"
        +]
    • Addedread_measurements
  6. 3 tool updatesv1.0.8
    • Changedclear_metric6 fields changed
      • addedOutput schema / properties / cleared
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / note
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • removedOutput schema / properties / result
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / row
        Added value: +{
        +  "anyOf": [
        +    {
        +      "properties": {
        +        "date": {
        +          "type": "string"
        +        },
        +        "mood": {
        +          "anyOf": [
        +            {
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "resting_heart_rate": {
        +          "anyOf": [
        +            {
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "sleep_hours": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "steps": {
        +          "anyOf": [
        +            {
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "water_ml": {
        +          "anyOf": [
        +            {
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "weight_kg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "workout_minutes": {
        +          "anyOf": [
        +            {
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "required": [
        +        "date"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "result"
        -]New value: +[
        +  "cleared"
        +]
      • removedOutput schema / x-fastmcp-wrap-result
        Removed value: -true
    • Changedlog_daily_metric5 fields changed
      • addedOutput schema / properties / logged
        Added value: +{
        +  "additionalProperties": {
        +    "anyOf": [
        +      {
        +        "type": "integer"
        +      },
        +      {
        +        "type": "number"
        +      }
        +    ]
        +  },
        +  "type": "object"
        +}
      • removedOutput schema / properties / result
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / row
        Added value: +{
        +  "properties": {
        +    "date": {
        +      "type": "string"
        +    },
        +    "mood": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "resting_heart_rate": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "sleep_hours": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "steps": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "water_ml": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "weight_kg": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    },
        +    "workout_minutes": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null
        +    }
        +  },
        +  "required": [
        +    "date"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "result"
        -]New value: +[
        +  "logged",
        +  "row"
        +]
      • removedOutput schema / x-fastmcp-wrap-result
        Removed value: -true
    • Changedread_health_data7 fields changed
      • addedOutput schema / properties / range
        Added value: +{
        +  "properties": {
        +    "end_date": {
        +      "type": "string"
        +    },
        +    "start_date": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "start_date",
        +    "end_date"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / result
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / rows
        Added value: +{
        +  "items": {
        +    "properties": {
        +      "date": {
        +        "type": "string"
        +      },
        +      "mood": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "resting_heart_rate": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "sleep_hours": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "steps": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "water_ml": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "weight_kg": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "workout_minutes": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      }
        +    },
        +    "required": [
        +      "date"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / summary
        Added value: +{
        +  "properties": {
        +    "days_with_data": {
        +      "type": "integer"
        +    },
        +    "mood": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "resting_heart_rate": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "sleep_hours": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "steps": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "water_ml": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "weight_kg": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "workout_minutes": {
        +      "properties": {
        +        "avg": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "max": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        },
        +        "min": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ],
        +          "default": null
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "days_with_data",
        +    "steps",
        +    "sleep_hours",
        +    "resting_heart_rate",
        +    "weight_kg",
        +    "workout_minutes",
        +    "mood",
        +    "water_ml"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "result"
        -]New value: +[
        +  "range",
        +  "rows",
        +  "truncated",
        +  "summary"
        +]
      • removedOutput schema / x-fastmcp-wrap-result
        Removed value: -true
  7. 2 tool updatesv1.0.4
    • Addedclear_metric
    • Addedlog_daily_metric
  8. 2 tool updatesv1.0.3
    • Removedread_finance_data
    • Changedread_health_data1 field changed
      • changedInput schema / properties / start_date / description
        Previous value: -"First day to include, formatted YYYY-MM-DD.\n        Defaults to 30 days before end_date."New value: +"First day to include, formatted YYYY-MM-DD.\nDefaults to 30 days before end_date. Ranges over ~10 years are rejected."
  9. 1 tool updatev1.0.1
    • Changedread_finance_data1 field changed
      • changedInput schema / properties / category / description
        Previous value: -"Optional category name to filter to (case-insensitive,\n      exact match โ€” e.g. \"Groceries\"). Omit to include all categories."New value: +"Optional category name to filter to (case-insensitive,\n      exact match โ€” e.g. \"Groceries\"). A category with no matching\n      rows returns an empty \"transactions\" list, not an error โ€” this\n      usually means a typo or a category that isn't in the ledger.\n      Omit to include all categories."
  10. 2 tool updatesv1.0.0
    • First observedread_finance_data
    • First observedread_health_data

TDQS

A4/5.0

Scored across 18 tools

Disambiguation4/5

Each tool has a distinct purpose, and the 'Do not use this tool when' cross-references make boundaries unusually explicit. The analytics cluster (get_baseline, detect_metric_anomalies, calculate_metric_trend, compare_metric_periods, find_metric_correlation, get_recent_changes, explain_metric_change) still requires careful reading to select correctly.

Naming Consistency4/5

All names follow a readable snake_case verb_noun pattern and clearly describe their action. The main inconsistency is using read_* for some retrieval tools and get_* for others, but there is no chaotic mixing of styles.

Tool Count4/5

18 tools is slightly above the ideal 3-15 range, but the count is justified by the server's scope: day-level metrics, raw measurements, workout sessions, analytics, and export. No tool feels redundant or like filler.

Completeness4/5

The surface covers logging, clearing, reading, aggregation, analytics, and export for daily metrics, raw measurements, and workout sessions. The main gap is the absence of delete/update operations for raw measurements and workout sessions, since clear_metric only removes day-level metric values.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables querying personal data synced from services like Lunch Money and Strava using SQL via Claude.
    6 npm
    1
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables AI agents to interact with local SQLite databases with full CRUD, schema introspection, foreign key relations, generated columns, and multi-format import/export (CSV, JSON, XLSX) through natural language.
    26
    9 npm
    MIT