BonnardBonnard

Getting Started

Add interactive, agent-ready charts, dashboards, and views to your MCP server with @bonnard/mcp-charts.

@bonnard/mcp-charts adds interactive charts to any MCP server. Your agent asks for data, you run the query, and the result renders as an interactive chart inside the MCP host (Claude, ChatGPT, and other MCP Apps clients). You write no frontend code: one widget renders across every host.

Pre-1.0: the API may change before a 1.0 release.

Install

npm install @bonnard/mcp-charts

Two ways to add charts

There are two shapes, depending on who chooses the query:

  • Ad-hoc visualize (the agent writes SQL). Add a generic visualize tool with addCharts. The agent writes SQL against your warehouse and the rows render as a chart. Best for open-ended exploration.
  • Named views (you author the queries). Register named views with addViews. Each view returns a single chart or a full dashboard, and the agent picks a view instead of writing SQL. Best for repeatable analytics.

Both paths render through the same ui://bonnard/chart widget and the same encoding logic. Start with visualize below; jump to Named views for the authored path (and Dashboards for the DashboardSpec a dashboard view returns).

Quickstart: the visualize tool

Call addCharts on your existing MCP server and give it a read-only query callback. Use a bundled warehouse adapter so the driver's column types become chart field kinds:

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

addCharts(server, {
  runSql: postgresRunSql(pool), // maps driver column types to chart field kinds
  discovery: { toolName: "explore_schema" }, // your schema-discovery tool
});

That registers a visualize tool and a ui://bonnard/chart widget resource. The agent calls visualize with SQL (and optional presentation hints); the rows render as a chart in the host, with a text fallback for non-widget clients. The agent chooses the chart type, or omit it to auto-detect from the shape of the data. See Chart Types.

Warehouse adapters

Adapters ship for Postgres, BigQuery, DuckDB, Snowflake, and Databricks. Each lives at its own import subpath and turns a native driver result into typed chart data. See Warehouse Adapters.

Writing runSql by hand

Without an adapter, return ChartData yourself. Types matter: the resolver infers field kinds from the row values, so a driver that returns numbers as strings (Postgres NUMERIC/BIGINT, for example) charts a measure as a category unless you declare typed fields. This "numbers must be numbers" story, and how to declare types, is covered in Connecting a Database.

addCharts(server, {
  runSql: async (sql) => ({ rows: await db.query(sql) }), // only if your driver returns native JS types
});

The full export surface

Beyond addCharts, the package exports the authoring surface for dashboards and views:

ExportWhat it does
addChartsRegister the ad-hoc visualize tool (agent writes SQL).
addViewsRegister explore_views + render_view over a set of named views.
chartBuild a ChartSpec from rows or typed ChartData.
chartCellBuild a dashboard chart cell from rows or typed ChartData.
explainDiagnose the encoding in a test, without rendering.
buildChartData, defaultNormalizeCell, assertReadOnlySqlAdapter authoring kit. See API Reference.

Security

visualize executes agent-written SQL against your database. Treat it as untrusted input. Connect runSql to a read-only, least-privilege role scoped to the data you want exposed. Your database permissions are the only security boundary; the SDK does not sandbox or restrict queries.

On this page