@bonnard/mcp-charts 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <h1 align="center">@bonnard/mcp-charts</h1>
2
2
 
3
- <p align="center">Interactive charts for your MCP server, in a few lines.</p>
3
+ <p align="center">Interactive charts, dashboards, and named views for your MCP server, in a few lines.</p>
4
4
 
5
5
  <p align="center">
6
6
  <a href="https://www.npmjs.com/package/@bonnard/mcp-charts"><img src="https://img.shields.io/npm/v/@bonnard/mcp-charts" alt="npm version"></a>
@@ -9,10 +9,12 @@
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <img src="https://raw.githubusercontent.com/bonnard-data/mcp-charts/main/assets/hero-bubble.png" alt="A chart rendered inside Claude from a visualize tool call" width="820">
12
+ Built by <a href="https://bonnard.dev">Bonnard</a> &middot; <a href="https://docs.bonnard.dev/mcp-charts/getting-started">Docs</a>
13
13
  </p>
14
14
 
15
- `@bonnard/mcp-charts` adds a `visualize` tool plus an embedded chart widget to any MCP server. The agent writes SQL, your database returns the rows, and the result renders as an interactive chart inside the host (Claude, ChatGPT, and other MCP Apps clients). You write no frontend code.
15
+ `@bonnard/mcp-charts` adds interactive charts to any MCP server. Your agent asks for data, your
16
+ database returns the rows, and the result renders as an interactive chart inside the host (Claude,
17
+ ChatGPT, and other MCP Apps clients). You write no frontend code: one widget renders across every host.
16
18
 
17
19
  > Pre-1.0: the API may change before a 1.0 release.
18
20
 
@@ -22,7 +24,20 @@
22
24
  npm install @bonnard/mcp-charts
23
25
  ```
24
26
 
25
- ## Quickstart
27
+ ## Two ways to add charts
28
+
29
+ There are two shapes, depending on who chooses the query:
30
+
31
+ - **Ad-hoc `visualize` (the agent writes SQL).** Add a generic `visualize` tool with `addCharts`. The
32
+ agent writes SQL against your warehouse and the rows render as a chart. Best for open-ended
33
+ exploration.
34
+ - **Named views (you author the queries).** Register named, reviewed views with `addViews`. Each view
35
+ returns a single chart or a full dashboard, and the agent picks a view instead of writing SQL. Best
36
+ for trusted, repeatable analytics.
37
+
38
+ Both paths render through the same `ui://bonnard/chart` widget and the same encoding logic.
39
+
40
+ ## Quickstart: the `visualize` tool
26
41
 
27
42
  Call `addCharts` on your existing MCP server and give it a read-only query callback:
28
43
 
@@ -36,36 +51,137 @@ addCharts(server, {
36
51
  });
37
52
  ```
38
53
 
39
- That registers a `visualize` tool and a `ui://bonnard/chart` widget resource. The agent calls it with SQL; the rows render as a chart in the host, with a text fallback for non-widget clients.
54
+ That registers a `visualize` tool and a `ui://bonnard/chart` widget resource. The agent calls it with
55
+ SQL; the rows render as a chart in the host, with a text fallback for non-widget clients.
40
56
 
41
- ## Why
57
+ Adapters ship for `postgres`, `bigquery`, `snowflake`, `databricks`, and `duckdb`. For an engine
58
+ without one, build typed `ChartData` with `buildChartData` (or declare `fields` yourself) so
59
+ numeric/temporal columns aren't inferred from raw driver values — see
60
+ [Connecting a database](#connecting-a-database).
42
61
 
43
- - **Grounded in real data.** Charts render the rows your query returned, not numbers the model typed into a tool call. No hallucinated figures.
44
- - **A few lines, no frontend.** One function, one widget that works across every MCP Apps host. You don't maintain per-client rendering code.
45
- - **Interactive, not static images.** Tooltips, legends, and axis formatting, native to the client.
62
+ ## Chart types
46
63
 
47
- <p align="center">
48
- <img src="https://raw.githubusercontent.com/bonnard-data/mcp-charts/main/assets/interactive-waterfall.png" alt="Interactive waterfall chart with a hover tooltip, rendered in Claude" width="820">
49
- </p>
64
+ Eight types, chosen automatically from the shape of your data or set explicitly: `bar`, `line`,
65
+ `area`, `pie`, `scatter`, `funnel`, `waterfall`, `table`. Plus bar variants (stacked, grouped, 100%
66
+ stacked, horizontal), dual-axis combos, bubble sizing, and reference lines. See the
67
+ [chart types reference](https://docs.bonnard.dev/mcp-charts/chart-types).
50
68
 
51
- ## Chart types
69
+ ## Named views (charts and dashboards)
70
+
71
+ When you author the queries, register named **views** with `addViews`. It registers two tools over a
72
+ registry: `explore_views` lists what's available (id, title, description, params) and `render_view`
73
+ renders one by `view_id` (a single `ChartSpec` via `chart(rows, opts)`, or a composed
74
+ `DashboardSpec`), binding the result to the widget. Each `ViewDef` can declare zod `params` that
75
+ `render_view` validates per view.
76
+
77
+ ```ts
78
+ import { addViews, chart, chartCell } from "@bonnard/mcp-charts";
79
+ import { z } from "zod";
80
+
81
+ addViews(server, {
82
+ views: [
83
+ {
84
+ id: "revenue_trend",
85
+ title: "Revenue trend",
86
+ description: "Monthly revenue",
87
+ kind: "chart",
88
+ render: () => chart(monthlyRows, { chartType: "line", title: "Revenue by month" }),
89
+ },
90
+ {
91
+ id: "sales_overview",
92
+ title: "Sales overview",
93
+ description: "KPIs + charts, optionally per region",
94
+ kind: "dashboard",
95
+ params: { region: z.enum(["EU", "US", "APAC"]).optional() },
96
+ render: ({ region }) => ({
97
+ title: "Sales overview",
98
+ columns: 2,
99
+ items: [
100
+ { type: "kpi", label: "Revenue", value: 336800, format: "currency", currency: "USD", delta: 61800 },
101
+ chartCell(monthlyRows, { chartType: "line", title: "Revenue by month", span: 2, id: "revenue_by_month" }),
102
+ chartCell(regionRows, { chartType: "bar", title: "Revenue by region", id: "revenue_by_region" }),
103
+ ],
104
+ }),
105
+ },
106
+ ],
107
+ });
108
+ ```
109
+
110
+ A `dashboard`-kind view returns a `DashboardSpec` (a grid of chart cells, KPI tiles, and text blocks);
111
+ `chartCell` builds a cell from raw rows. Give a cell an `id` and the agent can re-render it alone by
112
+ passing `render_view` an `item_id` (the ids appear in the dashboard summary). See `examples/dashboard`
113
+ for a six-view server, the [views guide](https://docs.bonnard.dev/mcp-charts/views), and the
114
+ [dashboards reference](https://docs.bonnard.dev/mcp-charts/dashboards) for the `DashboardSpec` shape.
115
+
116
+ ## Connecting a database
52
117
 
53
- Eight types, chosen automatically from the shape of your data or set explicitly: `bar`, `line`, `area`, `pie`, `scatter`, `funnel`, `waterfall`, `table`. Plus bar variants (stacked, grouped, 100% stacked, horizontal), dual-axis combos, bubble sizing, and reference lines. See the [chart types reference](https://docs.bonnard.dev/mcp-charts/chart-types).
118
+ When you build views from live, unseen data, prefer a **typed source**. An adapter (or
119
+ `buildChartData`) hands `resolve()` a `ChartData` with column types from your driver, so the encoding
120
+ is decided from types, not sniffed from a sample:
121
+
122
+ ```ts
123
+ import { chart, buildChartData } from "@bonnard/mcp-charts";
124
+
125
+ // A typed ChartData is accepted anywhere raw rows are — same one line, driver types instead of a sniff.
126
+ const data = buildChartData({ rows, columns, mapKind }); // or an adapter's runSql(...)
127
+ const spec = chart(data, { chartType: "line" });
128
+ ```
129
+
130
+ `chart(rows, opts)` and `chart(chartData, opts)` are the same call: pass raw `Record<string, unknown>[]`
131
+ to sniff, or a `{ rows, fields?, encode?, notes? }` to trust declared types.
132
+
133
+ **Numbers must arrive as numbers.** Some drivers stringify decimals/bigints (`revenue: "1234"`).
134
+ Inference recovers all-numeric-string columns to a measure and adds an advisory note, but the robust
135
+ fix is to declare the column's `kind` (via `fields` or an adapter) or cast in SQL. `fields` and
136
+ `encode` are trusted verbatim: a wrong declaration is honored, so a mistyped measure yields a blank
137
+ series (with a note).
138
+
139
+ To catch these before a host renders, assert the encoding in a test with `explain()`:
140
+
141
+ ```ts
142
+ import { explain } from "@bonnard/mcp-charts";
143
+
144
+ expect(explain(sampleRows, { chartType: "bar" }).series.length).toBeGreaterThan(0);
145
+ // or fail loud on a bad encoding:
146
+ explain(sampleRows, { chartType: "bar", strict: true }); // throws on zero series / ignored encode
147
+ ```
148
+
149
+ See the [connecting-a-database guide](https://docs.bonnard.dev/mcp-charts/connecting-a-database) for
150
+ the full DB-correctness story and a troubleshooting table.
54
151
 
55
152
  ## Warehouse adapters
56
153
 
57
- Skip writing `runSql` by hand. Each adapter wraps your driver and maps native column types to chart roles (dimension, measure, time):
154
+ Skip writing `runSql` by hand. Each adapter wraps your driver and maps native column types to chart
155
+ roles (dimension, measure, time):
58
156
 
59
157
  ```ts
60
158
  import { postgresRunSql } from "@bonnard/mcp-charts/postgres";
61
159
  addCharts(server, { runSql: postgresRunSql(pool) });
62
160
  ```
63
161
 
64
- Bundled for Postgres, BigQuery, Snowflake, Databricks, and DuckDB. Each driver is an optional peer dependency, installed only if you import its subpath. See [warehouse adapters](https://docs.bonnard.dev/mcp-charts/adapters).
162
+ Bundled for Postgres, BigQuery, Snowflake, Databricks, and DuckDB. Each driver is an optional peer
163
+ dependency, installed only if you import its subpath. See
164
+ [warehouse adapters](https://docs.bonnard.dev/mcp-charts/adapters).
165
+
166
+ ## Exports at a glance
167
+
168
+ | Export | What it does |
169
+ | ----------------------------- | ------------------------------------------------------------------- |
170
+ | `addCharts` | Register the ad-hoc `visualize` tool (agent writes SQL). |
171
+ | `addViews` | Register `explore_views` + `render_view` over a set of named views. |
172
+ | `chart` / `chartCell` | Build a `ChartSpec` / dashboard cell from rows or typed `ChartData`. |
173
+ | `explain` | Diagnose the encoding in a test, without rendering. |
174
+ | `resolve` / `inferFields` | The pure encoding brain and its field inference. |
175
+ | `buildChartData`, `defaultNormalizeCell`, `assertReadOnlySql` | Adapter authoring kit. |
176
+
177
+ Full details in the [API reference](https://docs.bonnard.dev/mcp-charts/api-reference).
65
178
 
66
179
  ## Security
67
180
 
68
- `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 security boundary; the SDK does not sandbox queries. See [Security](https://docs.bonnard.dev/mcp-charts/getting-started#security).
181
+ `visualize` executes agent-written SQL against your database. Treat it as untrusted input: connect
182
+ `runSql` to a **read-only, least-privilege** role scoped to the data you want exposed. Your database
183
+ permissions are the security boundary; the SDK does not sandbox queries. See
184
+ [Security](https://docs.bonnard.dev/mcp-charts/getting-started#security).
69
185
 
70
186
  ## Links
71
187
 
@@ -1,5 +1,5 @@
1
1
  import { TableField, BigQuery } from '@google-cloud/bigquery';
2
- import { C as ChartData } from './types-6ALzXWjE.js';
2
+ import { C as ChartData } from './types-DUKpye7m.js';
3
3
 
4
4
  /** A BigQuery schema field. Anchored to the client's own `TableField` type so it tracks the driver:
5
5
  * if @google-cloud/bigquery changes the schema shape, this and its consumers fail to compile.
package/dist/bigquery.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  assertReadOnlySql,
3
3
  buildChartData
4
- } from "./chunk-I3HINKHN.js";
4
+ } from "./chunk-IXRGLZX2.js";
5
5
 
6
6
  // src/adapters/bigquery.ts
7
7
  var NUMERIC = /* @__PURE__ */ new Set(["INT64", "INTEGER", "FLOAT64", "FLOAT", "NUMERIC", "BIGNUMERIC"]);