Semaphor
MCP

How Cards Read and Show

Change a card's column headers, number and date formats, hidden columns, widths, total row, data labels, legend, axes, chart variant and highlights, and a dashboard's title, through Semaphor MCP.

An agent can finish a card the way a person does in the editor: name its columns, format its numbers and dates, hide a column, add a total row, put the values on the bars, move the legend, title an axis, stack the bars, or highlight the rows that need attention. It reads each setting in the outline and changes it with the same words, through semaphor_propose_change and semaphor_apply_change like every other change (see Making Changes).

Name a column, format it as dollars and hide another
{
  "dashboardId": "d_8f2k",
  "changes": [
    {
      "op": "card.update",
      "cardId": "c_suppliers",
      "columns": {
        "Net Purchase Value": { "label": "Purchase value", "format": { "type": "currency", "currency": "USD", "maximumFractionDigits": 0 } },
        "Net Tons": { "hidden": true }
      }
    }
  ]
}

The proposal reads it back in plain words, with a value in the new format:

Renames the column "Net Purchase Value" to "Purchase value" in "Purchases by supplier", shows Purchase value as $12,480, and hides Net Tons for everyone (it still sorts and filters).

Read the Settings

semaphor_get_dashboard_details with fields: ["outline"] gives each editable card its settings, in the shape a change takes:

A card's settings in the outline
{
  "cardId": "c_suppliers",
  "title": "Purchases by supplier",
  "type": "table",
  "editable": true,
  "columns": {
    "Supplier": { "field": "supplier_id", "role": "dimension", "label": "Supplier", "inherits": ["label", "format"] },
    "Net Purchase Value": { "field": "net_purchase_value", "role": "measure", "label": "Net Purchase Value", "width": 180,
                            "format": { "type": "currency", "currency": "USD" }, "inherits": ["label"] }
  },
  "totals": { "row": true },
  "highlights": [
    { "ruleId": "h_1", "column": "Net Purchase Value", "apply": "row", "enabled": true,
      "when": { "operator": "<", "value": 1000 }, "color": "red" }
  ],
  "editorOnly": ["Column display (Supplier)"]
}
FieldWhat it holds
columnsEach column by the name its header shows: label, format (the card's own), hidden, width, and inherits, what it takes from the model. A column that inherits its format shows the model's format, which comes with the query's results. field and role say which column it is.
orientation, stack, donutA chart's variant (see Chart Variants)
totals, dataLabels, legend, axesThe card's own settings, when it has them
highlightsEach highlight rule, with the ruleId that removes it
editorOnlySettings the card has that a change doesn't state, in the editor's words. A change keeps them exactly as they are.

Send a card's settings back as you read them and nothing changes, so an agent can copy them, change only what the user asked, and send them back.

Columns

columns on card.add or card.update names each column by its name in the outline. Send only the settings that change.

SettingValues
labelThe header. null returns it to the model's label.
formatA number, currency, percent, duration or date format, in the shape the outline shows. Send a whole format with its type, or only the fields to change, which are merged onto the format the column shows. null returns the column to the model's format.
hiddentrue hides the column for everyone who views the card; it still sorts and filters. false shows it again. Tables and detail tables.
widthPixels, as the table draws it, from 50 to 500. null returns it to automatic. Tables and detail tables.
Formats
{ "Revenue": { "format": { "type": "number", "compact": true } } }
{ "Margin": { "format": { "type": "percent", "percentValueMode": "fraction", "maximumFractionDigits": 1 } } }
{ "Order month": { "format": { "type": "temporal_bucket", "presentation": { "mode": "preset", "preset": "long" } } } }
{ "Ordered at": { "format": { "type": "date", "preset": "short" } } }
{ "Revenue": { "format": { "maximumFractionDigits": 0 } } }
  • A date grouped by month, quarter or year takes a temporal_bucket format: a preset (short, long, numeric, iso, and the week, quarter and fiscal presets at their grains) or a pattern no finer than the grain.
  • A date shown as it is, in a detail table, a SQL table or a Matrix level, takes a date format with a preset or a pattern.
  • Each format is checked against the card that draws it, so the sentence's sample is what the viewer sees. A column whose card shows its values as they come (a chart's categories, text on a table) takes no format, and the refusal says where one applies.
  • A SQL table's columns are named by the query's result columns. The proposal runs the card once to read them.

Card Settings

SettingValuesCards
totals{ "row": true } adds a total row; false removes itTables
dataLabels{ "show": true } shows the values on the chart; add format for a number format of their own, or null to follow the measureBar, line, area and pie charts
legend{ "show": true, "position": "bottom" }; position is top, bottom, left or rightBar, line, area and pie charts
axes{ "x": {...}, "y": {...} }, each { "title", "min", "max" }; null removes a title or returns a bound to automaticBar, line and area charts
Values on the bars, the legend at the bottom, and the vertical axis from zero
{
  "op": "card.update",
  "cardId": "c_rev_region",
  "dataLabels": { "show": true },
  "legend": { "show": true, "position": "bottom" },
  "axes": { "y": { "title": "Revenue", "min": 0 } }
}

x and y are the axes as they appear on screen: on a horizontal bar chart, y lists the categories and x shows the values. A range goes on the axis that shows values.

Chart Variants

A card's type is one of the eight card types, and its variant is a property of it:

Varianttype and properties
Horizontal barbar with "orientation": "horizontal"
Stacked barbar with "stack": "stacked" (horizontal too, with both)
Stacked line, stacked arealine or area with "stack": "stacked"
Doughnutpie with "donut": true
Stack the bars by a second field
{
  "op": "card.update",
  "cardId": "c_rev_region",
  "stack": "stacked",
  "query": { "dimensions": ["region", "category"] }
}

A variant change keeps the card's legend, data labels, axes and colors. A bar chart turned horizontal keeps each axis's title and range with its role, so the value axis keeps "Revenue" and its range. Changing to another chart family, such as a bar chart to a table, works like the editor's type picker.

Highlights

highlight.add colors the cells or rows of a table, detail table or KPI where a condition holds, shades a column on a color scale, or adds data bars:

Rows with margin under 10% in red
{ "op": "highlight.add", "cardId": "c_orders", "column": "Margin", "when": { "operator": "<", "value": 0.1 }, "color": "red", "apply": "row" }
A color scale and data bars
{ "op": "highlight.add", "cardId": "c_orders", "column": "Margin", "scale": { "low": "red", "high": "green" } }
{ "op": "highlight.add", "cardId": "c_orders", "column": "Revenue", "bars": { "color": "blue" } }
FieldValues
columnA column's name in the outline
when and color{ "operator": "=", "!=", ">", ">=", "<" or "<=", "value" }, { "operator": "between", "values": [low, high] }, { "operator": "contains", "value" }, { "operator": "is_null" }, { "top": n } or { "bottom": n }, with the color for the cell or row where it holds
scale{ "low", "high", "mid" }: colors from the column's lowest value to its highest
bars{ "color" }: a bar in each cell, in proportion to its value
applycell (the default) or row, for a condition

Colors are red, amber, green, blue and gray, the editor's own, or a hex color such as #1d4ed8. A KPI's highlight colors its value when a condition holds.

The proposal's change entry gives the new rule's ruleId, and so does the outline afterwards. highlight.remove takes it and keeps the card's other rules:

Remove one highlight
{ "op": "highlight.remove", "cardId": "c_orders", "ruleId": "h_1" }

The Dashboard's Title and Description

Rename the dashboard
{ "op": "dashboard.update", "title": "Weekly sales review" }

description sets the dashboard's description; null removes it. The outline shows both.

Confirm

A proposal's confirm says whether the user needs to see it before it's applied:

  • not_needed: the proposal only changes how cards read and show (labels, formats, hidden columns, widths, data labels, legend, axes, variants and highlights) or the dashboard's title and description. An agent can apply it as soon as it's proposed.
  • needed: anything else, such as a query, a type, a card added or removed, a filter, or a total row (which runs its own query). It's also needed when a change would remove something viewers saved, such as a column their bookmarks use; the viewer_settings_affected warning says what. Show the summary to the user first.

The apply checks again, and refuses with confirm_changed if the proposal now needs the user's confirmation.

When a Setting Is Refused

A refused setting changes nothing in the proposal and says what to do. Each refusal names the card and column as the user sees them, lists what the card or setting takes in allowed, and often carries a suggestedChange you can send as written.

CodeWhen
setting_not_for_cardThe card doesn't take that setting, such as axes on a pie chart
column_not_found, column_ambiguousNo column, or two, have that name; allowed lists the card's column names
columns_unavailableA SQL table's query couldn't be run to read its columns
format_invalidA format that isn't valid, or that the column's card doesn't draw
date_finer_than_grainA date format finer than the column's grouping; allowed lists that grain's presets
color_unknownA color that isn't one of the five names or a hex color
highlight_not_foundNo highlight on the card has that ruleId
value_invalidA width outside the column's range, an axis that ends before it starts, an empty title, or two labels for one column

On this page