Skip to main content

Analytics tools

Datasets, charts, dashboards, and running SQL / NL→SQL queries.

25 tools. Each is callable over MCP with a Bearer agx_ key that holds the required scope. The catalog is public (tools/list isn't scope-filtered); the scope below is enforced when the tool is called (tools/call) — a key without it is refused (default-deny).

get_chart

Get one chart's config. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
chart_idstring

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_chart",
"arguments": {
"chart_id": "\u2026"
}
}
}

get_dashboard

Get one dashboard + the charts it contains. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
dashboard_idstring

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_dashboard",
"arguments": {
"dashboard_id": "\u2026"
}
}
}

get_dashboard_with_data

Get a dashboard AND every chart's plotted data in one call — the batch loader. Optional dashboard-wide date filter: date_preset (today/yesterday/last_7_days/last_30_days/this_month/this_quarter/this_year/last_month/…) OR date_start+date_end (YYYY-MM-DD). The filter applies per chart via its date-column mapping. Each chart's data is under _chart_data (with a per-chart error if that one failed). Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
dashboard_idstring
date_presetstringe.g. last_30_days, this_month (omit for all-time).
date_startstringYYYY-MM-DD (custom range; needs date_end).
date_endstringYYYY-MM-DD (custom range; needs date_start).
freshbooleanBypass the analytics cache.

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_dashboard_with_data",
"arguments": {
"dashboard_id": "\u2026"
}
}
}

get_data_model

The org's grounded analysis data model: tables + columns/types, the REAL enum values per column, custom-field sql_refs (e.g. (custom_fields->>'budget')::numeric), the join graph, and deal/lifecycle stages. Read this BEFORE writing SQL for run_query so you use real column/value/stage names instead of guessing. Org database only — for external DBs use list_data_sources + describe_analytics_table. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
force_refreshbooleanRebuild the cached manifest (after a schema change).

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_data_model",
"arguments": {}
}
}

get_dataset

Get one dataset with its SQL + column manifest. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
dataset_idstring

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_dataset",
"arguments": {
"dataset_id": "\u2026"
}
}
}

create_chart

Create a chart on a dataset. chart_type ∈ bar/line/pie/area/table/stacked_bar/horizontal_bar/donut/scatter/kpi/… chart_config holds dimensions[], metrics[], breakdownBy, filters[], topN. Requires analytics:write. RENDER CONTRACT (charts render BLANK if violated): (1) EVERY chart — including kpi and table — needs ≥1 entry in dimensions[]; a chart with dimensions:[] shows 'No dimensions/metrics configured'. For a single-value KPI, add a constant column to the dataset (e.g. "'Total'::text AS scope") and use it as the sole dimension so it groups to one row. (2) Every metric/dimension alias MUST be a lowercase snake_case identifier ([a-z0-9_], no spaces/slashes/caps). The engine sanitizes aliases and Postgres lowercases them, so the returned data key = lowercase(sanitized alias); the UI looks up series/KPI values by the RAW alias, so "Sign Ups" → key sign_ups → mismatch → empty chart. Use alias:"sign_ups", "ad_spend", "r_org_conv". RATIO / COST-PER / AOV (derived) metrics: use chart_config.calculatedMetrics = [{alias, metricA, operator:'+|-|*|/|%', metricB (or constantB)}] — computed POST-aggregation as metricA <op> metricB (division guards /0 → NULL), so it is a period-accurate SUM(a)/SUM(b). metricA/metricB reference the (sanitized) metric aliases. For a ratio KPI: metrics=[SUM(num) with hidden:true, SUM(den) with hidden:true] + calculatedMetrics=[{alias:'ratio', metricA:'num', operator:'/', metricB:'den'}]; the scorecard displays the calculated metric (first visible metric or, if base metrics are hidden, the calculated one).

Required scope: analytics:write

Input

ParameterTypeRequiredDescription
namestring
chart_typestring
query_idstringThe dataset id this chart visualizes (required unless chart_type='text').
chart_configobjectdimensions[] (≥1 required, even for kpi/table), metrics[] (function ∈ COUNT/SUM/AVG/MIN/MAX/COUNT_DISTINCT; mark a base metric hidden:true to keep it out of the display but usable by calculatedMetrics), calculatedMetrics[] (derived ratio/cost/AOV: {alias, metricA, operator, metricB|constantB} computed post-aggregation = period-accurate SUM(a)/SUM(b)), breakdownBy ({field, alias} — a bare column name also works), filters[], topN, valueFormat, sortByColumn (a dimension/metric ALIAS string + sortDirection 'asc'|'desc'). ALL aliases must be lowercase snake_case identifiers matching the dataset columns.
is_sharedboolean

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_chart",
"arguments": {
"name": "\u2026",
"chart_type": "\u2026"
}
}
}

create_dashboard

Create a dashboard composing existing charts (by chart_ids). Optional layout (grid positions + per-chart date-filter mapping). Requires analytics:write. For the dashboard's global date filter to drive a chart, that chart's layout entry MUST set filter_mappings.date_range.column to a date column its dataset's SELECT actually exposes — map it to a column that does not exist in the chart's own query and that chart errors ('column base.<col> does not exist'). When charts come from different sources with different date columns, build them on ONE dataset with a single shared date column (a daily calendar-spine) so one filter can anchor all. CUSTOM FILTER DROPDOWNS (industry, size, …) beyond the built-in date filter go in filters (array of controls); a chart responds to a control ONLY if its layout filter_mappings[<control id>] = {column:'<col>'} points at a real column in that chart's dataset. Leave a chart unmapped to exclude it (e.g. keep ad-spend charts OUT of an industry filter when spend has no industry). Give the dataset the filterable dimension as a real column and grain the rows by it.

Required scope: analytics:write

Input

ParameterTypeRequiredDescription
namestring
descriptionstring
chart_idsarray<string>Chart ids to include.
layoutobject{chart_layouts: {<chart_id>: {position:{x,y}, size:{width,height}, filter_mappings:{date_range:{column:'<date_col>'}, <control_id>:{column:'<col>'}}}}}. GRID UNITS: 12 columns; rowHeight is 15px with a per-chart minimum of 8 rows (120px). Set size.height in these units: kpi/scorecard/table height:8 (120px), line/bar/area charts height:16 (240px). Small heights like 2–4 render 30–60px → KPI numbers overflow and plots flatten. x/y are also in grid units (stack kpi rows h8 at y0/y8/y16, then charts h16).
filtersarray<object>Custom filter controls beyond the built-in date filter: [{id, name, type:'single_select'|'multi_select'|'text_search'|'numeric_range', field?}]. Use a stable id (e.g. 'industry') and reference that same id in each chart's layout.filter_mappings to wire it to a column. Options are auto-populated from distinct column values.
is_sharedboolean

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_dashboard",
"arguments": {
"name": "\u2026"
}
}
}

create_dataset

Save a reusable dataset from a read-only SQL SELECT. The column manifest is auto-extracted. Charts are built on datasets. Requires analytics:write.

Required scope: analytics:write

Input

ParameterTypeRequiredDescription
namestring
sqlstringA read-only SELECT.
descriptionstring
integration_idstringBuild the dataset on an external database (from list_data_sources). Omit for the org DB.
is_sharedboolean

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_dataset",
"arguments": {
"name": "\u2026",
"sql": "\u2026"
}
}
}

update_chart

Update a chart's name/type/config/dataset/sharing. Requires analytics:write. Same RENDER CONTRACT as create_chart: dimensions[] must be non-empty (even for kpi/table) and every alias must be a lowercase snake_case identifier matching the dataset columns, or the chart renders blank.

Required scope: analytics:write

Input

ParameterTypeRequiredDescription
chart_idstring
namestring
chart_typestring
query_idstring
chart_configobject
is_sharedboolean

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "update_chart",
"arguments": {
"chart_id": "\u2026"
}
}
}

update_dashboard

Update a dashboard's name/description/layout/chart_ids/filters/sharing. Requires analytics:write. layout and filters each REPLACE the stored value, so send the COMPLETE object each time (layout: preserve every chart's filter_mappings + use grid-unit sizes kpi/table height:8, charts height:16 at 15px/row — a partial layout drops mappings and resets heights; filters: send the full control array).

Required scope: analytics:write

Input

ParameterTypeRequiredDescription
dashboard_idstring
namestring
descriptionstring
chart_idsarray<string>
layoutobject
filtersarray<object>Custom filter controls (REPLACES stored): [{id, name, type:'single_select'|'multi_select'|...}]; wire each to charts via layout.filter_mappings[<id>]={column}.
is_sharedboolean

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "update_dashboard",
"arguments": {
"dashboard_id": "\u2026"
}
}
}

update_dataset

Update a dataset's name/description/sql/sharing (changing sql re-extracts columns). Requires analytics:write.

Required scope: analytics:write

Input

ParameterTypeRequiredDescription
dataset_idstring
namestring
descriptionstring
sqlstring
integration_idstringMove the dataset onto an external database (or 'current_org' for the org DB).
is_sharedboolean

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "update_dataset",
"arguments": {
"dataset_id": "\u2026"
}
}
}

delete_chart

Delete a chart. Requires analytics:write.

Required scope: analytics:write

Input

ParameterTypeRequiredDescription
chart_idstring

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_chart",
"arguments": {
"chart_id": "\u2026"
}
}
}

delete_dashboard

Delete a dashboard (its charts are not deleted). Requires analytics:write.

Required scope: analytics:write

Input

ParameterTypeRequiredDescription
dashboard_idstring

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_dashboard",
"arguments": {
"dashboard_id": "\u2026"
}
}
}

delete_dataset

Delete a dataset (its dependent charts cascade). Requires analytics:write.

Required scope: analytics:write

Input

ParameterTypeRequiredDescription
dataset_idstring

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_dataset",
"arguments": {
"dataset_id": "\u2026"
}
}
}

list_analytics_tables

List the tables available to query for analytics (name + column count). Call describe_analytics_table for a table's columns and row count. Use to discover what you can build a dataset/query from. Pass integration_id (from list_data_sources) to list an external database's tables instead. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
integration_idstringExternal database integration. Omit for the org DB.

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_analytics_tables",
"arguments": {}
}
}

list_charts

List saved charts. Optional dataset_id filters to charts on one dataset. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
dataset_idstring

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_charts",
"arguments": {}
}
}

list_dashboards

List saved dashboards. Requires analytics:read.

Required scope: analytics:read

Input

No input parameters.

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_dashboards",
"arguments": {}
}
}

list_data_sources

List the databases you can analyze: the org database plus every connected external database integration (PostgreSQL/MySQL/…), each with its integration_id. External DBs have no pre-loaded schema — discover it live: list_analytics_tables(integration_id) → describe_analytics_table → preview → run_query. Note generate_sql/get_data_model are org-DB only; for external DBs hand-write SQL from the discovered schema. Requires analytics:read.

Required scope: analytics:read

Input

No input parameters.

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_data_sources",
"arguments": {}
}
}

list_datasets

List saved analytics datasets (saved SQL queries). Requires analytics:read.

Required scope: analytics:read

Input

No input parameters.

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_datasets",
"arguments": {}
}
}

describe_analytics_table

Get a table's columns + types (including custom fields). Pass integration_id to introspect a table in an external database. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
table_namestring
integration_idstringExternal database integration. Omit for the org DB.

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "describe_analytics_table",
"arguments": {
"table_name": "\u2026"
}
}
}

describe_entity_fields

The writable field schema for ONE CRM entity (contact / company / deal / task / note / …): its standard columns plus every custom field with its slug (field_name), type, and — for dropdown/multiselect — the EXACT allowed option values. Read this BEFORE a create_/update_ call so you set custom_fields.<field_name> to a real slug and a valid dropdown option instead of guessing (an off-list value is stored silently and never shows in the UI). Lightweight, entity-scoped alternative to get_data_model. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
entity_typestringEntity singular: contact, company, deal, task, note, product, activity.
force_refreshbooleanRebuild the cached schema manifest first.

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "describe_entity_fields",
"arguments": {
"entity_type": "\u2026"
}
}
}

generate_sql

Turn a natural-language question into grounded, validated, read-only SQL — the SAME NL→SQL agent the in-product dataset builder uses (it knows your real schema, enum values, custom-field sql_refs, join graph, and deal/lifecycle stages, and self-corrects against the DB). Prefer this over hand-writing SQL. mode: validate (default, self-corrects + returns sample rows), preview (more rows), generate_only (no DB). Feed the returned sql to run_query or create_dataset. Org database only — for external DBs discover schema via list_data_sources + describe_analytics_table and hand-write SQL. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
questionstringThe business question in plain English.
modeenum(validate, preview, generate_only)

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "generate_sql",
"arguments": {
"question": "acme"
}
}
}

preview_analytics_table

Preview the first rows of a table. Pass integration_id for a table in an external database. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
table_namestring
integration_idstringExternal database integration. Omit for the org DB.
limitinteger

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "preview_analytics_table",
"arguments": {
"table_name": "\u2026"
}
}
}

run_chart

Get server-side aggregated data for a chart (GROUP BY dimensions + metrics, breakdownBy, filters, topN). Provide chart_id (saved chart) OR (dataset_id and/or sql) plus a chart_config. Returns the plotted rows. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
chart_idstringA saved chart (uses its dataset + config).
dataset_idstringAggregate a saved dataset.
sqlstringAd-hoc base SELECT to aggregate.
integration_idstringWith ad-hoc sql: aggregate against an external database. Saved charts/datasets carry their own.
chart_configobjectdimensions[], metrics[], breakdownBy ({field, alias} — a bare column name also works), filters[], topN, sortByColumn (a dimension/metric ALIAS string, with sortDirection 'asc'|'desc'; sortByMetric is the deprecated name for the same string).
limitinteger
freshboolean

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "run_chart",
"arguments": {}
}
}

run_query

Run a read-only SQL query and get rows back — the way to ANALYZE data. Provide sql (ad-hoc SELECT), dataset_id (a saved dataset), OR question (plain English — the NL→SQL agent grounds + validates it, then it's executed; the response includes the generated_sql). Only SELECTs are allowed (DROP/DELETE/etc. blocked); org-scoped. Paginated via limit/offset. Tip: call get_data_model first to learn real columns/values. Requires analytics:read.

Required scope: analytics:read

Input

ParameterTypeRequiredDescription
sqlstringA read-only SELECT (ad-hoc).
dataset_idstringRun a saved dataset.
questionstringNatural-language question; auto-converted to SQL and run (org database only).
integration_idstringRun against a connected external database (from list_data_sources). Omit for the org DB.
limitinteger
offsetinteger
freshbooleanBypass cache.

Example

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "run_query",
"arguments": {}
}
}