Agents and the API¶
Everything in Dashboards can be built by an AI agent, through the MCP server (Claude Desktop, Claude.ai connectors) or the REST API. The agent works with exactly your account's rights: it sees the dashboards and datasets you can see and edits what you can edit.
A metric's source is dataset (the default), manual or rate. For manual, set values with
metric_record_value {"key", "date", "value", "note"} or POST
/smallstack/dashboards/api/metrics/<key>/entries/. For rate, set numerator and denominator
to metric keys.
To track a goal list over time, set its cadences with goal_list_tracking, read them back with
goal_list_history, and capture on demand with goal_list_capture.
Asking an agent¶
With the SmallStack connector added, ask in plain language:
Build a "Support health" dashboard: open tickets, tickets opened this month, average first-response time with a warning over 4 hours, and open tickets by queue.
A well-behaved agent will:
- Look at the datasets —
list_datasets, thendescribe_datasetfor the fields, the operators each takes and the period names. - Dry-run each metric with
metric_preview. That returns the value, how many rows match and every problem, without saving anything. It repeats until the problems are gone and the number is plausible. - Save with
create_metric, thencreate_dashboard, thendashboard_add_cardper card. Personal is the default: a staff agent passes"visibility": "shared"for the team's copy, on every piece. - Check with
dashboard_snapshot, which evaluates every card.
The MCP tools¶
| Tool | Does |
|---|---|
list_datasets, describe_dataset |
what can be measured, and how it can be filtered |
metric_preview |
evaluate an unsaved metric (dry run) |
list_metrics, get_metric, create_metric, update_metric, delete_metric |
metric CRUD. The CRUD families here share these verbs |
metric_value |
a saved metric's value, optionally for a period, with the change from the previous period |
metric_trend |
a saved metric per day, week, month, quarter or year across a period, which is what a chart draws |
metric_rows |
the rows behind a number, to explain it |
metric_usage |
where a metric is used, before you change or delete it |
list_dashboard_components |
the card types and their options |
card_preview, *_component |
try a card without saving; saved cards you can place by key |
get_dashboard, create_dashboard, update_dashboard, … |
dashboard CRUD (the whole layout at once) |
dashboard_add_card, dashboard_remove_card |
one card at a time |
dashboard_snapshot |
every card on a dashboard with its live value. Nothing is stored, and a chart or calendar card has no one number |
create_goal_list, goal_list_add_goal |
goal lists and their targets. To change or remove a goal, read the list with get_goal_list, edit its sections and send them all to update_goal_list |
goal_list_values, goal_list_weeks |
a list judged now; a list week over week |
goal_list_save_week |
save one named week as it stands (a list tracking weeks is also saved each Monday) |
goal_list_tracking, goal_list_capture, goal_list_history |
the cadences a list is captured on; capture the current period or fill past ones; read captures back |
metric_record_value, metric_delete_value |
a hand-entered metric's value for a date |
create_report, report_values, … |
KPI reports; report_values gives the CSV's link too |
create_playlist, playlist_slides |
slides for a meeting: dashboards and goal lists |
list_calendars, calendar_events, create_event, create_calendar_view |
the calendar. Give an event a start_time and it's timed, and a repeat and it's a series |
event_skip_date |
take one date out of a series, or put it back |
query_dataset_<key> |
raw rows from a dataset, when the site publishes that tool. Bundled datasets don't by default (SMALLSTACK_FRAMEWORK_DATASETS_MCP); list_datasets says which do |
Rows can be named as well as numbered: get_metric, update_metric and delete_metric
take key in place of id; dashboards, reports, goal lists and playlists take slug.
A slug is optional when creating one: leave it out and it's made from the name (site-health,
then site-health-2), and the answer says what it is. An existing one's slug doesn't change
with its name. Only an administrator (a superuser, or a member of the admin group) may change it;
anyone else's change, over REST and MCP too, is refused. A changed slug breaks the old address: there
is no redirect, so bookmarks, embeds and playlists that used it stop working.
Periods are today, yesterday, wtd (this week so far), pwtd (last week), mtd, pmtd,
qtd, pqtr, ytd, prev_year, this_month and this_year (the whole month or year, days to come
included), last_<N>, next_<N> and all. A name that isn't one is refused,
never answered with an all-time number (a stored default_period takes only the fixed names, not
all or an arbitrary last_14). A metric with no period_field can't be narrowed, so it gives
its all-time value and a note saying so, and a goal on one can't have its own period.
Counts. A list tool's count is the page and total is how many match. Tool links are relative
to the site. dashboard_snapshot gives metric cards' values, grouped cards' groups and notes' text;
for a calendar card, ask calendar_events.
REST¶
With a token (Authorization: Bearer …), the CRUD routes are
/smallstack/api/dashboards/metrics/, …/boards/, …/reports/, …/goals/,
…/components/ and …/playlists/. These routes evaluate:
GET /smallstack/dashboards/api/datasets/
GET /smallstack/dashboards/api/datasets/<key>/schema/
POST /smallstack/dashboards/api/preview/ {"dataset": …, "filter_tree": {…}, "agg": …}
POST /smallstack/dashboards/api/report-preview/ {"items": [{"metric": …}], "periods": ["mtd", "pmtd"]}
POST /smallstack/dashboards/api/card-preview/ {"type": …, "metric": …, "options": {…}}
GET /smallstack/dashboards/api/metrics/<key>/value/?period=mtd
GET /smallstack/dashboards/api/metrics/<key>/trend/?period=&grain=
GET /smallstack/dashboards/api/metrics/<key>/rows/?period=&order=&limit=
GET /smallstack/dashboards/api/boards/<slug>/values/
GET /smallstack/dashboards/api/reports/<slug>/values/ (?format=csv for the file)
GET /smallstack/dashboards/api/goals/<slug>/values/?period=
GET /smallstack/dashboards/api/goals/<slug>/weeks/?week=&weeks=
POST /smallstack/dashboards/api/goals/<slug>/weeks/<week>/save/
GET /smallstack/dashboards/api/goals/<slug>/tracking/
POST /smallstack/dashboards/api/goals/<slug>/tracking/ {"cadences": ["weekly", "monthly"]}
GET /smallstack/dashboards/api/goals/<slug>/snapshots/?cadence=weekly
POST /smallstack/dashboards/api/goals/<slug>/snapshots/ {"cadence": "weekly", "fill": 4}
GET /smallstack/dashboards/api/metrics/<key>/entries/
POST /smallstack/dashboards/api/metrics/<key>/entries/ {"date": …, "value": …, "note": …}
GET /smallstack/dashboards/api/playlists/<slug>/slides/
GET /smallstack/dashboards/api/components/
All of them are in the OpenAPI schema (/api/schema/openapi.json, browsable at /api/docs/).
Safety¶
- A non-staff account's agent can't share; only a staff account's can mark something shared.
- A metric can only use datasets its user may read. A card on a shared dashboard shows restricted to anyone whose account can't read its data.
- A bad filter is refused with a precise reason. It is never applied as "no filter". So is a misspelt argument, period or week.
delete_metricalso removes the metric's cards, report rows, goals and saved cards in everything the account can edit, and lists them underalso_removed, with any rates it leaves showing an error underalso_removed.rates_left_without_it. It isn't a dry run:metric_usagesays where a metric is used, first.