BonnardBonnard

API Reference

The full @bonnard/mcp-charts export surface, including addCharts, the dashboard and views authoring API, widget hosting, the embed-mode contract, and the adapter building blocks.

The package root exports two registration entry points plus the authoring, widget-hosting, embed, and adapter helpers:

ExportRegisters / does
addChartsThe ad-hoc visualize tool (agent writes SQL).
addViewsexplore_views + render_view over a set of named views.
chart, chartCell, explainBuild specs / cells; diagnose an encoding.
Widget hostingWIDGET_HTML, WIDGET_META, registerChartWidget, the resource URI.
Embed modeThe postMessage contract for driving the widget in your own layout.
Adapter kitbuildChartData, defaultNormalizeCell, assertReadOnlySql.

addCharts(server, options)

Registers the visualize tool and the ui://bonnard/chart widget resource on an existing MCP server.

import { addCharts } from "@bonnard/mcp-charts";

addCharts(server, options);

AddChartsOptions

OptionTypeDescription
runSql(sql, ctx: ChartContext) => Promise<ChartData>Required. Runs the agent's SQL and returns rows (and optionally typed fields). ctx carries tenant/roles/signal.
discovery{ toolName: string }Optional. Names your schema-discovery tool so the visualize description can point the agent to it.
allowChartType[]Optional. Restricts the chartType enum exposed to the agent (default: all eight).
toolNamestringOptional. Override the tool name (default "visualize").

ChartData

interface ChartData {
  rows: Record<string, unknown>[];
  fields?: FieldMeta[]; // optional typed columns; inferred from the rows when omitted
}

When fields are omitted, column roles (dimension, measure, time) and formats are inferred from the data and column names.

The visualize tool

Once registered, the agent calls visualize with:

  • sql: the query to run (required)
  • chartType: one of the supported chart types (optional; auto-detected when omitted)
  • title: a chart title (optional)
  • stacking: "stacked", "grouped", or "stacked100" (optional). Bar and area only. stacked100 normalises each x position to 100%.
  • horizontal: boolean (optional). Bar only. Runs bars horizontally with categories on the y-axis. Bars are vertical unless you set this, except that the widget auto-flips when a category label runs past 12 characters.
  • reference: { target?: number, average?: boolean } (optional). Draws horizontal lines on the value axis: target at a fixed value, average at the mean of the primary series.
  • encode: explicit column mapping (optional). Accepts x, y, series, y2 (measures on a secondary right axis, drawn as a line), line (measures drawn as a line on the same axis), and size (scatter only, a third numeric column mapped to point size).

The result returns a ChartSpec in structuredContent for the widget, plus a text fallback for non-widget clients.

addViews(server, options)

Registers two tools over a registry of named views: explore_views (list) and render_view (render one by view_id). Each view returns a ChartSpec or a DashboardSpec. This is the one authored entrypoint for both single charts and dashboards.

import { addViews, chart } from "@bonnard/mcp-charts";

addViews(server, {
  views: [
    {
      id: "revenue_trend",
      title: "Revenue trend",
      description: "Monthly revenue",
      render: () => chart(rows, { chartType: "line" }),
    },
  ],
});
OptionTypeDescription
viewsViewDef[]Required, non-empty. Duplicate ids throw.
exploreToolNamestringRename the discovery tool (default "explore_views").
renderToolNamestringRename the execute tool (default "render_view").
renderDescriptionstringExtra text appended to render_view's description.

render_view inputs

render_view takes:

  • view_id (required): the view to render, an enum of the registered ids.
  • params (optional): the chosen view's declared params, validated per view (strict).
  • item_id (optional): for a dashboard-kind view, the id of one chart cell to render alone. params apply to the whole view first, then the named cell is projected out and returned as a ChartSpec. A ChartCell gets its id from chartCell(rows, { id }). See Rendering one cell.

See Named views for the ViewDef shape and per-view params.

Authoring helpers

Build specs and cells directly, or diagnose an encoding:

ExportSignaturePurpose
chart(rows | ChartData, opts?) => ChartSpecBuild a single chart spec. Inference sniffs raw rows; a typed ChartData is trusted.
chartCell(rows | ChartData, opts) => ChartCellLike chart, wrapped as a dashboard cell (adds span and an optional id for item_id selection).
explain(rows | ChartData, opts?) => ChartExplanationThe inferred typing and resolved encoding, no render payload, for tests. See Connecting a Database.
resolve(ChartData, opts?) => ChartSpecThe pure encoding brain chart is built on.
dashboardResult(DashboardSpec, opts?) => resultBuild the widget-linked result envelope by hand.
summarizeDashboard(DashboardSpec) => stringThe default text summary (chart lines carry the cell id when set).
DASHBOARD_OUTPUT_SCHEMAzod raw shapeThe permissive outputSchema for a hand-registered DashboardSpec-returning tool.
isChartSpec / isDashboardSpec(spec) => booleanRuntime guards discriminating the two spec shapes.
inferFields(ChartData) => FieldMeta[]The typing pass on its own: the resolved FieldMeta for each column, unioning declared fields with the returned columns.

opts on chart / chartCell / explain is ResolveOptions (chartType, title, stacking, horizontal, reference, strict) plus the fields and encode escape hatches. See Connecting a Database for typed fields and strict.

Widget hosting

addCharts and addViews register the widget for you. These exports let you serve the same renderer yourself, or register the resource without a tool.

ExportTypePurpose
WIDGET_HTMLstringThe self-contained widget HTML, the same file the MCP resource serves. Serve it from your own route for embed mode.
WIDGET_META{ ui, "openai/..." }The _meta that links a tool result to the widget: ui.resourceUri plus the openai/outputTemplate alias for ChatGPT.
VIEW_OUTPUT_SCHEMAzod objectThe permissive outputSchema for a hand-registered view tool, so hosts that gate structuredContent on a schema forward it.
registerChartWidget(server) => voidRegisters the ui://bonnard/chart resource alone, with no tool. Idempotent.
CHART_RESOURCE_URI"ui://bonnard/chart"The resource URI the widget is registered under.

Embed mode

Render one chart, KPI, or table with no chrome of its own inside a layout you own, driven over postMessage. Serve WIDGET_HTML from your own route with a #embed fragment, then send it a render message. The package root exports the wire contract:

ExportTypePurpose
EMBED_PROTOCOL_VERSIONnumberThe protocol version the installed widget speaks. Carried on bonnard:ready.
EMBED_LIMITSobjectThe bounds the widget enforces on a payload (maxRows, maxItems, maxSeries, and others). Exceeding one is refused whole with a payload-too-large error, not truncated. The values are not part of the stable surface.
EmbedPayloadtypeWhat you send to render: the spec plus sizing and theme tokens.
EmbedTokenstypeTheme tokens the parent passes so the widget matches its surface.
EmbedSizing"fill" | "content"How the payload is sized: fill takes the container, content measures itself.
BonnardRenderMessagetypeThe parent-to-widget render message.
BonnardParentMessagetypeUnion of every message the parent sends.
BonnardWidgetMessagetypeUnion of every message the widget sends back.
BonnardReadyMessagetypeSent once the widget is ready to receive a render.
BonnardSizeMessagetypeSent when the widget reports its size.
BonnardContentSizeMessage / BonnardFillSizeMessagetypesThe two sizing replies, for content-sized and fill-sized modes.
BonnardErrorMessage / BonnardErrorCodetypesThe error reply and its code enum, for a payload the widget refuses.

See Embed mode for the fragment flags, the message sequence, sizing, theme precedence, and the security model.

Building blocks for custom adapters

If you are writing your own adapter, these are exported from the package root:

ExportPurpose
buildChartDataTurns driver rows + columns into ChartData using a kind mapper.
defaultNormalizeCellDefault per-cell normalisation (dates, numerics, etc.).
assertReadOnlySqlLightweight SELECT-only guardrail for SQL strings.

Supporting types: SourceColumn, KindMapper, CellNormalizer, BuildChartDataOptions.

The bundled warehouse adapters are built on exactly these primitives. Read their source for worked examples.

On this page