Skip to main content
A widget is two halves: a pipeline (which data-source tools feed it, plus the transform that shapes the rows) and a payload (the chart or table config). add_widget creates it, set_widget_pipeline wires it, set_widget_style dresses it.

list_widgets

Read-only List all widgets on a dashboard: id, title, type (payload dialect), kind (the semantic renderer — kpi | table | pivot | progress for Vistazo-native widgets, the lead series type for ECharts widgets, markdown, visualization), layout, and the current pipelineId. ARCHIVED (removed) widgets are hidden by default — pass includeArchived:true to list them too, each marked archived:true; that is how a restore_widget target is found without already knowing its id. For one widget’s full config and pipeline wiring, use get_widget; to retitle or edit a description, set_widget_style.

get_widget

Read-only Return ONE widget in full: title, description, type + semantic kind, archived (true = soft-deleted by remove_widget, restorable with restore_widget), layout, the stored payload config (echartsConfig / vistazoConfig / markdownContent / visualizationRef), the skill fields, and the complete pipeline wiring — every fetch stage’s mcpId / toolName / argumentTemplate / role plus the persisted transform function body. READ THIS BEFORE EDITING a widget: set_widget_pipeline and set_widget_style replace what they touch, so fetch the current wiring/config here and re-send it with your modification instead of reconstructing it from guesses. (Edits route: title/description/payload → set_widget_style; wiring → set_widget_pipeline; position/size → set_widget_layout.) This read fetches nothing; to also see what each stage returns TODAY (a fresh sample per source to write a transform against), call get_widget_inputs.

get_widget_data

Read-only Return the last refresh result for a widget without triggering a new refresh — the cheap way to read a chart’s actual numbers. Echoes the widget title, so readings across several widgets can be correlated without a get_widget per id. TWO DIFFERENT FRESHNESS FACTS COME BACK, DO NOT CONFLATE THEM: lastRefreshedAt is REFRESH recency (when the pipeline last ran) and latestPeriod is DATA recency ({field, value, granularity} — the newest period present in the rows, and the column it was read from). A widget refreshed four minutes ago whose latestPeriod is 2019 is running fine and reporting stale years — that is a pinned fetch window; check_freshness names the argument that pins it. latestPeriod is best-effort and null when no column reads as a time dimension, which is never evidence of freshness. fields gives the units and decimal precision the widget APPLIES when rendering each row field — check it before drawing a conclusion from a small difference, which may sit inside the displayed rounding. status values: idle = the last run completed (data can still be null when nothing has refreshed yet or the cached rows expired — refresh to materialize), running = a refresh is in flight, error = the last run failed (errorMessage says why).

search_widgets

Read-only Full-text search across widget titles and descriptions in the dashboards you can access within a workspace.

get_widget_inputs

Read-only The HYDRATE read for editing a widget’s data: everything get_widget returns PLUS, per fetch stage, the arguments as rendered against the dashboard’s current parameter values, the alias the transform receives that stage under (inputs.<alias>; the first stage is also rawResponse), the full row count, and a fresh 3-row sample of the unwrapped payload — fetched live from the source now, nothing cached or written. Call this BEFORE writing or changing a transform, so it is authored against the real shape instead of a guess; then set_widget_pipeline with transformFunctionBody + fields and NO transformedData validates that transform against these same sources before anything is written. A stage whose source is unreachable comes back with error instead of a sample (style edits via set_widget_style never need the data; a transform edit needs every stage reachable). Costs one call per stage against the live sources, so it is a deliberate authoring read, not a browse — for a widget’s published numbers use get_widget_data, for its wiring alone use get_widget. Requires a connection to each stage’s server (CONNECTION_NOT_AUTHENTICATED names add_connection as the remedy).

add_widget

Additive write Add a widget to a dashboard. type names the PAYLOAD you will supply and nothing else — one of four: vistazoConfig (a Vistazo-native kpi | table | pivot | progress, picked with kind), echartsConfig (an ECharts option object), visualizationRef (a saved library visualization, via entryId), markdownContent (authored prose, the one type with no data pipeline). Where the dialects overlap take the purpose-built kind — a single-value display is a vistazoConfig kpi, never an ECharts gauge — A series with seriesField: "*" is a TEMPLATE that expands at render into one series per numeric row field no other series claims (named by the field key) — use it when the column set only exists at run time, e.g. one line per country when the countries are a multi_select parameter and the transform pivots to one column per country. Note that the chart kind itself lives INSIDE the payload (series[].type for ECharts, kind for the Vistazo dialect), never at the tool layer. Placement: defaults to full-width (w=12) appended below existing widgets; pass width/height and optionally x/y (same grid semantics as set_widget_layout) to place it directly — a side-by-side row is chart {x:0,width:8} + KPI {x:8,width:4} at the same y. Reposition/resize later with set_widget_layout. The widget is created EMPTY: wire its data with set_widget_pipeline, author the payload with set_widget_style, then refresh_pipeline and VERIFY with get_widget_data (a refresh reporting ok:true with rowCount 0 means the fetch matched nothing). Requires edit access.

set_widget_pipeline

Destructive write Wire one or more connected MCP data-source tools to a widget — the REWIRE tool. REPLACES the widget’s whole pipeline on every call: a fresh pipelineId is returned and the superseded pipeline is deleted, so read the current wiring with get_widget first and re-send the complete stage list with your change. USE THE RIGHT TOOL FOR THE SIZE OF THE EDIT: if all you are changing is a stage’s ARGUMENTS (a country code, a date bound, dropping a pinned end_year), call patch_widget_pipeline instead — it edits those arguments in place and leaves the stage list, the transform and the fields untouched, so a one-token change cannot corrupt working wiring by mistranscribing the rest. Use this tool when the STRUCTURE changes: a different tool or connection, adding/removing a stage, a new transform or field list, a role change. Single tool: pass mcpId + toolName (+ argumentTemplate). Multi-tool pipeline: pass invocations (2+ stages): all stages fetch in parallel on refresh and ONE stitch transform combines their results (it receives inputs keyed by stage alias — the tool name, _2-suffixed on repeats — plus rawResponse aliasing the first stage). Optionally persist an agent-authored transform (transformFunctionBody + fields) so refresh reuses it instead of regenerating — and when you do, OMIT transformedData: the server then fetches every stage with the current parameter values, runs your transform exactly as refresh will, seeds its output so the widget renders at once, and REFUSES the whole write (nothing changes, error transform_degraded naming the rung: script_error / empty_output / field_key_mismatch / data_literal / missing_data) if the transform throws, returns no rows, misses a declared field, or a source is unreachable. Read get_widget_inputs first for a fresh sample of each stage to author against. Rows you pass in transformedData are trusted verbatim and skip that run; a call with neither rows nor a transform wires the stages and seeds nothing (the response says so). Transforms RESHAPE stage results, never carry data — never inline fetched values as literals (baked rows freeze; refresh only re-runs fetch stages). Rolling windows (“last 14 days”, “stay current”): for date-typed arguments, define_parameter with a relative default (today-14) referenced as {{ params.key }}; for integer-period sources (years, month counts), OMIT the end bound if the source treats it as optional — an open-ended window grows on its own — otherwise fetch wide (mind the source’s row cap and truncation order) and take the trailing N periods in the transform. Either way the window only advances when a refresh actually RUNS: pair it with set_refresh_cadence, or the chart silently pins at its last refresh. A pipeline serves exactly ONE role: widget (chart data) or parameter_source (dropdown options), never both — a parameter source is its own hidden widget, separate from any chart. After changing WHAT a widget fetches, fix any prose that named the old state — widget title/description (set_widget_style), dashboard description (update_dashboard) — then regenerate_dashboard_context, or the text and the AI skill summary built from it keep describing data that is no longer there; the response warns you when the prose still matches an argument value you just changed. Requires edit access.

patch_widget_pipeline

Destructive write Change a widget’s fetch ARGUMENTS without re-sending its pipeline. The small-edit counterpart to set_widget_pipeline: that tool replaces the whole pipeline (every stage, the transform, the fields) and mints a new pipelineId, so a one-token argument change means re-transcribing wiring you did not intend to touch — and every re-send is a chance to corrupt working wiring someone else built. This tool edits the arguments IN PLACE: the pipelineId is unchanged, the stage list, the persisted transform, and the skill fields are untouched, and stages you don’t name keep their current arguments. Reach for it whenever the edit is “append ;ITA to country_code”, “move end_year to 2025”, “drop the pinned end bound so the window rolls”. Pass stages, one entry per stage you are changing, each identifying its target by invocationId (from get_widget) or stageIndex (0-based) — omit both when the pipeline has exactly one stage. Per entry, EITHER setArguments / removeArguments for key-level edits (setArguments adds or overwrites named arguments, removeArguments deletes them; removing an argument that isn’t there is refused rather than silently ignored), OR argumentTemplate to replace that one stage’s whole template. Values may be {{ params.<key> }} holes, and an existing hole in an argument you don’t touch survives verbatim. The merged result is validated against the tool’s own input schema before anything is written (an out-of-range literal is refused with nothing changed), the stale-prose check runs on it, and the response echoes the EFFECTIVE wiring of every stage — before/after for what changed — so you can verify the merge instead of assuming it. When the pipeline has a persisted transform, the merged arguments are also FETCHED and the transform re-run BEFORE the write: a patch that breaks it is refused with nothing changed (error transform_degraded, same rungs as set_widget_pipeline), and one that works republishes the rows, so the widget renders the new arguments immediately — the response’s rows.source says ‘validated’. A pipeline with no transform yet keeps its previous rows (‘previous’) until refresh_pipeline runs. Requires edit access.

set_widget_style

Destructive write Update a widget’s presentation: its title, description, and the payload its type declares — echartsConfig, vistazoConfig (whose kind selects kpi | table | pivot | progress), or markdownContent. This is also the tool that RENAMES a widget — title and description live here (there is no update_widget). PARTIAL: fields you omit are left unchanged, so a title-only edit never touches the stored payload; a payload you do pass replaces the stored one and must match the widget’s type. ECharts series binding: series[].name IS the row-field key the series reads — ADDING a series means adding an entry whose name is the new field’s key; use seriesNames only when the DISPLAY label must differ from the field key (it renames while preserving the binding — never repurpose an existing series’ name for display text). ECharts number formatting is SEMANTIC: put a format object on a value axis or series (e.g. yAxis.format = { kind: “currency”, currency: “USD” }, kinds number | currency | percent | bytes | duration | date | text, plus decimals / unit / fullPrecision) and the renderer compiles it into axis-label and tooltip formatters with locale grouping and compaction ($15B) — never scale values in the transform to shrink an axis, and never send a JS function (configs are JSON; functions are rejected). For position/size/mobile-order use set_widget_layout instead; for data wiring use set_widget_pipeline. Requires edit access.

set_widget_layout

Destructive write Override a widget’s grid layout on a 12-column dashboard. Partial update — only the fields you pass change. Desktop position is {x,y,w,h}: y is stacking order (empty rows compact away, so you can’t author a blank row), while x (0–11) and w (2–12) place and size within a row, keeping x+w ≤ 12. A shared row is emergent — put widgets at the same y with widths summing to ≤12 (e.g. a 30/70 split = one widget {x:0,w:4} and its neighbor {x:4,w:8}); the model computes the widths. h is 2–20 rows tall. order (≥0) is the SEPARATE mobile single-column stack position (lower = higher on phones); set it to keep a logical group (KPI column + its chart) contiguous, otherwise leave it unset and mobile falls back to reading order. Widgets WITH an explicit order sort before ALL unset widgets on mobile — setting it on a subset hoists that subset above everything unordered, so when customizing the phone stack set order on every widget (or know that unordered ones follow after, in reading order). Execute the user’s desktop coordinates faithfully; the mobile collapse is automatic and governed by order, not by desktop coordinates. Requires edit access.

remove_widget

Destructive write Remove a widget from a dashboard — a SOFT DELETE (the same model as archive_dashboard): the widget is hidden everywhere and its data pipeline is PARKED, but nothing is destroyed and restore_widget brings both back intact. Nothing here hard-deletes a widget. Confirm with the user only when their request does NOT identify the widget unambiguously (“drop the chart” on a dashboard holding three charts); when the request names the widget, or you resolved the id from list_widgets / search_widgets and it matches what was asked for, that request IS the confirmation — verify the id, then remove it. dashboardId must be the widget’s own dashboard: a mismatch refuses instead of removing, so a stale or mistyped widgetId can never disrupt a widget somewhere else. The response echoes the removed widget’s title and kind for verification, plus restorable:true. What removal does to the agent-facing surfaces, automatically — no follow-up cleanup call exists or is needed: it disappears from list_widgets (unless includeArchived:true), get_dashboard, search_widgets, the canvas, and any public share link, and its parked pipeline stops running — it is dropped from refresh_dashboard’s fan-out and from scheduled auto-refresh, and refresh_pipeline / refresh_stage refuse on it, so a removed widget never fetches or spends again. Reads by id still work (get_widget reports archived:true and returns the full wiring; get_widget_data still returns its last published rows). Every other write refuses while it is archived. The dashboard’s AI skill summary does NOT auto-update — run regenerate_dashboard_context afterwards when the removal changes what the dashboard shows. Requires edit access.

restore_widget

Destructive write Bring back a widget that remove_widget archived, with its data pipeline, its stage wiring, its transform, and its last published rows intact — the exit from the widget archive, exactly as archive_dashboard’s restore:true is the exit from the dashboard archive. (Not to be confused with restore_dashboard, which rolls a whole dashboard back to a recorded VERSION; this only un-hides one widget and changes nothing about its content.) Find the target with list_widgets includeArchived:true, which marks archived rows archived:true. The widget returns to its STORED grid slot — archiving never moved the other widgets’ saved geometry, so it normally reappears exactly where it was; if a widget added while it was archived now occupies that space, the grid’s vertical compaction pushes one of them down at render (nothing is lost, but the arrangement may not be what you want), so the response echoes its position — reposition deliberately with set_widget_layout. The data is as stale as the moment it was removed: refresh_pipeline to bring it current. Refuses on a widget that is not archived. Run regenerate_dashboard_context afterwards so the dashboard summary describes it again. Requires edit access.