# Refresh and freshness

<!-- Generated by scripts/gen-docs-mcp.mjs from the shared tool catalog. Do not edit by hand —
     edit the catalog in packages/shared/src/mcp.ts and regenerate. -->

## Tools

Reading cached rows with `get_widget_data` costs nothing and is usually enough. Reach for a refresh only when the user needs data fresher than the last run.

| Tool | What it does | |
|---|---|---|
| [`check_freshness`](#check_freshness) | Check freshness | Read-only |
| [`refresh`](#refresh) | Refresh | Destructive write |
| [`explore_dashboard`](#explore_dashboard) | Explore dashboard | Additive write |

## check_freshness

`Read-only`

Answer "how stale is this actually?" for a dashboard (dashboardId) or one widget (widgetId) — a cheap read that runs nothing and publishes nothing. A SUCCESSFUL REFRESH DOES NOT MEAN RECENT DATA, and this is where both facts sit side by side. Per widget: lastRefreshedAt (when the fetch last ran) beside latestPeriod (the newest period in the cached rows; latestPeriodSource 'fetched' means it was read from the raw fetch because the transform dropped the column), and windowPinned — true when the argumentTemplate hard-codes a literal END bound or a literal period (year: 2025), with pinnedBy naming the stage, argument and role. A widget refreshed 5 minutes ago with latestPeriod 2020 and end_year 2020 will never become current: unpin the bound (update_widget's `pipelineArguments` removeArguments, or a relative parameter default) and refresh. A literal single period may be an intentional snapshot, so confirm before changing it. `selection` is the period the fetch REQUESTS (fixed, parameter, rolling, open or unknown, plus selectedPeriod) — never coverage; compare it with latestPeriod. `dataState` says whether rows are cached: populated, empty (zero rows is a real result), never_materialized, missing or no_pipeline; the summary counts dataUnavailable and latestPeriodUnknown charts, and neither is fresh. The response also carries the scheduled-refresh cadence (enabled, interval, paused/suspended): a schedule keeps the FETCH current, never a pinned WINDOW. Use it before promising a dashboard is up to date, to sweep for literal date bounds, and to diagnose a frozen chart. latestPeriod is best-effort and absent when no field reads as time — an absent value is never evidence of freshness. Any dashboard role may read it.

## refresh

`Destructive write` · `Reaches outside Vistazo`

Re-fetch NOW and publish the result as the baseline every viewer sees, on your own MCP credentials at the dashboard's default parameter values. Synchronous. One scope per call: `dashboardId` (every widget), `pipelineId` or `widgetId` (one widget), or `pipelineId` + `invocationId` (one stage, re-stitched with the others' stored results). ok:true is NOT data: rowCount 0 with a warning means the fetch matched nothing, so check rowCount before reporting success. Nor is a refresh recent DATA: a literal end bound (end_year 2020) re-fetches the same window forever; `latestPeriod` shows the newest period, and for "make it current" call check_freshness first. `skipped` widgets were already refreshing (nothing billed; not an error). Declined with nothing fetched: no usable connection to a source (`callerConnectionGaps` — connect first), or usage (`usageBlocked`; retrying will not help). A removed widget's pipeline refuses. Requires edit access.

## explore_dashboard

`Additive write` · `Reaches outside Vistazo`

Run every widget pipeline on a dashboard, or only the ones `pipelineIds` names, EPHEMERALLY under your own credentials, optionally overriding parameter values, and return the chart-ready rows in the result. Changes no data: the published baseline, the stored transform, and the parameter defaults are all untouched — this is the slice-and-dice lane, while refresh is the publish lane. `params` maps parameter keys to override values (same shapes as set_parameter's `value`, including relative date expressions); omitted keys use the dashboard defaults; unknown/invalid overrides are dropped and reported. Reuses each widget's cached transform only — a data-shape change surfaces as a per-widget stale_transform error meaning an editor must run a real refresh, and it files a broken-chart alert to the dashboard's editors (`editorsTold`). A selection the source has no data for (a year it does not cover, a cleared filter) is NOT a broken transform: that widget returns rows: [] with noData { reason: 'source_returned_no_rows', stages, emptyParameters } — pick another value rather than asking an editor. Cascading filters: pass `changed` (the keys this call moves relative to the view you are updating) and only the sources and charts reading them re-run; omit it for a full run. A sourced select whose source reads a changed key comes back with fresh options in `parameterOptions` (never persisted; `stale: true` means the source produced no rows and these are the last-good options), selections the fresh coverage no longer holds are removed and reported in `pruned` with a one-line note, and `effectiveOverrides` is the overrides the view actually ran with after pruning. Free: the run is recorded at zero cost, and capped at 300 data fetches per hour per MCP connection (per person in the app); past the cap every widget reports a rate_limited error. Any dashboard role of a member with a license may explore; a guest is refused.
