Skip to main content
Glama
durely
by durely

Query the Garmin cache with SQL

garmin_query
Read-onlyIdempotent

Run read-only SQL against your local Garmin cache to build custom aggregations, correlations, records, and cross-year comparisons that standard analysis tools miss.

Instructions

Run one read-only SQLite query against the local Garmin cache, for analyses the other tools don't cover (custom aggregations, correlations, records, comparisons across years).

Views (one row per item; use these first):

  • activities(id, parent_id, is_multisport_parent, type_key, sport, name, start_local, start_date, duration_s, moving_s, distance_m, elevation_gain_m, avg_speed_mps, avg_hr, max_hr, avg_power_w, norm_power_w, calories, aerobic_te, anaerobic_te, training_load, tss, vo2max) sport = Garmin parent type (running, cycling, swimming, walking, ...); type_key = exact type (road_biking, virtual_ride, lap_swimming, ...). Multisport: parent rows have is_multisport_parent=1, legs have parent_id; to count volume use is_multisport_parent = 0.

  • daily(date, steps, step_goal, walk_distance_m, floors_up, resting_hr, min_hr, max_hr, stress_avg, stress_max, stress_rest_pct, stress_low_pct, stress_medium_pct, stress_high_pct, body_battery_min, body_battery_max, body_battery_charged, body_battery_drained, intensity_moderate_min, intensity_vigorous_min, calories_total, calories_active, respiration_avg, hydration_ml)

  • sleep(date, start_local, end_local, sleep_s, deep_s, light_s, rem_s, awake_s, nap_s, score, quality, feedback, awake_count, respiration_avg, sleep_stress_avg) -- date = the morning you woke up

  • hrv(date, last_night_avg, last_night_5min_high, weekly_avg, baseline_low, baseline_high, status)

  • weight(date, weight_kg, bmi, body_fat_pct, body_water_pct, muscle_mass_kg, bone_mass_kg, visceral_fat, source, entries) Raw JSON (for fields not in the views, via json_extract):

  • activity(id, ..., raw_json) -- Garmin's full activity summary, e.g. json_extract(raw_json, '$.maxAvgPower_1200'), '$.hrTimeInZone_2', '$.fastestSplit_5000', '$.avgStrideLength'

  • daily_raw(domain, date, json) -- domains: daily_summaries, sleep, hrv, weight, body_battery, hrv_readings, heart_rate, spo2, food_logs Dates are 'yyyy-MM-dd' text in the user's local calendar; durations in seconds, distances in meters, speeds in m/s. SQLite dialect: strftime('%Y-%W', date) for weeks, date(date, '-7 days'), window functions (AVG(x) OVER (ORDER BY date ROWS 6 PRECEDING)) are supported.

Rules: one SELECT or WITH statement; at most max_rows rows returned (default 200); 10-second timeout. Prefer aggregating in SQL over returning many rows. Example: SELECT strftime('%Y', start_date) AS year, sport, ROUND(SUM(distance_m)/1000) AS km FROM activities WHERE is_multisport_parent = 0 GROUP BY 1, 2 ORDER BY 1, 3 DESC

Input Schema

NameRequiredDescriptionDefault
sqlYesA single SELECT or WITH query
max_rowsNo
response_formatNomarkdown

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv0.5.0

TDQS

A4.7/5.0
Behavior5/5

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

The annotations already declare readOnlyHint, idempotentHint, closed-world, and non-destructive behavior, and the description adds important operational constraints: a single SELECT/WITH statement, max_rows default 200, and a 10-second timeout. It also explains date formats, units, SQLite dialect support, and how multisport records are structured, which materially helps correct invocation.

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?

Despite its length, the description is front-loaded and well-structured: purpose first, then view definitions, raw JSON access, date/unit conventions, SQL dialect notes, rules, and an example. The column lists and example earn their place because they directly enable correct query construction.

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?

This is a complex SQL-query tool with no output schema and low schema description coverage, so the description must carry substantial context. It does so by documenting available views and columns, raw JSON escape hatches, date and unit semantics, SQL dialect features, execution limits, and an example query, leaving little ambiguity for an agent to call it 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 description coverage is only 33%, so the description carries most of the parameter burden. It explains the SQL parameter extensively and clarifies max_rows behavior and default, but it does not mention the response_format parameter or distinguish its json and markdown options.

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: run one read-only SQLite query against the local Garmin cache. It also distinguishes this tool from its siblings by positioning it for analyses the other tools don't cover, such as custom aggregations, correlations, records, and cross-year comparisons.

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 usage context: use it for analyses not covered by other tools, prefer the views first, and use raw JSON only for fields not in the views. It does not name specific sibling tools as alternatives, which keeps it just below fully explicit routing guidance.

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