@bicharts/chart-mcp 0.2.0 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bicharts/chart-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP (Model Context Protocol) stdio server for BIC AI charts: profile a dataset locally, then generate chart code that has passed the BIC backend's render gates. Works with any MCP-capable client (Claude Code, Claude Desktop, Cursor, Copilot Studio). Requires a BIC trial or paid account.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -25,6 +25,7 @@
25
25
  "// files": "dist ONLY — this package ships the built server, not its source. LICENSE.txt and README.md are included automatically by npm, but listed so an audit does not have to know that.",
26
26
  "files": [
27
27
  "dist",
28
+ "skills",
28
29
  "LICENSE.txt",
29
30
  "README.md"
30
31
  ],
@@ -44,8 +45,8 @@
44
45
  "zod": "^3.23.0"
45
46
  },
46
47
  "devDependencies": {
47
- "@bicharts/chart-host": "^0.3.0",
48
- "@bicharts/shape-core": "^0.3.0",
48
+ "@bicharts/chart-host": "^0.4.0",
49
+ "@bicharts/shape-core": "^0.4.0",
49
50
  "@types/node": "^20.0.0",
50
51
  "@types/papaparse": "^5.3.14",
51
52
  "esbuild": "^0.28.1",
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: bic-charts
3
+ description: Build a web app or dashboard containing BIC-generated charts — a bubble map, a table with in-cell bars, linked cross-filtering. Use whenever the bic-chart MCP tools are available and the task is "put a chart / dashboard in this app".
4
+ ---
5
+
6
+ # Building an app with BIC charts
7
+
8
+ The golden path, end to end. Following it costs a handful of tool calls; deriving it from
9
+ first principles costs about thirty, and the places people lose time are all called out
10
+ below because they were all measured.
11
+
12
+ **The mental model.** A BIC chart is *generated source you own* — a plain
13
+ `render(container, data, options)` function you commit to your repo. There is no API key at
14
+ run time, no per-render cost, and no network call. `@bicharts/chart-host` runs it; the MCP
15
+ generates it. Generation happens **once, at build time, by you** — never in your users'
16
+ browsers.
17
+
18
+ ## 1. Scaffold (one command block)
19
+
20
+ ```bash
21
+ npm create vite@latest my-app -- --template react-ts
22
+ cd my-app
23
+ npm install d3@7 @bicharts/chart-host
24
+ npm install -D @types/d3
25
+ ```
26
+
27
+ `d3` is a peer requirement of the **chart**, not of chart-host. `@types/d3` only for
28
+ TypeScript. chart-host has no runtime dependencies.
29
+
30
+ ## 2. Generate — say what the output must BE, not just what it should look like
31
+
32
+ Call `generate_chart` once per chart, with `out_dir` so the artifacts land on disk.
33
+
34
+ The single most important habit: **`prompt` is a suggestion lane.** It steers style and
35
+ emphasis, and it competes with the chart lane's own guidance about summarizing. When your
36
+ app *depends* on the shape of the output, use the contract parameters instead — they are
37
+ authoritative, and `required_columns` is verified in the generated code with an automatic
38
+ correction:
39
+
40
+ | Parameter | Use it when |
41
+ | --- | --- |
42
+ | `rows_policy: "all"` | every source row must appear — a row-per-entity table, a point per location. Without it the engine may legitimately show a Top-N with an "Other" rollup. |
43
+ | `required_columns: [...]` | a field must be visible because your app's interactions depend on it (e.g. the column you colour or filter by). |
44
+ | `forbid_derived_columns: true` | your app owns the analytics; the chart is only the display. Stops per-capita / share-of-total / rank columns being added. |
45
+
46
+ Asking for these in `prompt` prose instead is the most expensive mistake available here: it
47
+ routinely costs two or three extra generations, and each one is minutes of wall-clock.
48
+
49
+ Other parameters worth knowing: `chart_type` (a preference, honored unless the data shape
50
+ disqualifies it), `renderer: "D3"` for a web app, `width`/`height`, and
51
+ `reasoning_mode: "1P"` when you want the cheapest, fastest pass.
52
+
53
+ **Generation takes minutes.** Fire the calls for independent charts **in parallel** rather
54
+ than in sequence — it is the difference between ~4 minutes and ~12.
55
+
56
+ ## 3. Wire it up
57
+
58
+ Import the generated code as raw text and the sample payload as JSON:
59
+
60
+ ```tsx
61
+ import * as d3 from "d3";
62
+ import { BicChart, BicChartGroup } from "@bicharts/chart-host/react";
63
+ import mapCode from "./charts/map/chart.js?raw";
64
+ import tableCode from "./charts/table/chart.js?raw";
65
+ import payload from "./charts/map/data.sample.json";
66
+
67
+ // data.sample.json rows are POSITIONAL arrays; the group wants row OBJECTS.
68
+ const columns = payload.columns;
69
+ const rows = payload.rows.map(r =>
70
+ Object.fromEntries(columns.map((c, i) => [c.name, r[i]])));
71
+ ```
72
+
73
+ ### The coordinated dashboard — the recipe, memorized
74
+
75
+ ```tsx
76
+ <BicChartGroup columns={columns} rows={rows} point={{ city: "City", state: "StateOrProvince" }}>
77
+ <BicChart id="map" code={mapCode} d3={d3} geoKind="na" respondsWith="highlight" />
78
+ <BicChart id="table" code={tableCode} d3={d3} />
79
+ </BicChartGroup>
80
+ ```
81
+
82
+ That is all of it. The map **highlights** (keeps every bubble, dims the rest) and the table
83
+ **filters**. Cross-filtering is mutual by default, a chart never filters itself, and
84
+ `group.clear()` clears.
85
+
86
+ Do **not** hand-roll dimming out of the `lch-*` CSS classes. They are an implementation
87
+ detail, they are re-applied on every render (so a `classList` poke is lost at the next data
88
+ change), and translating row indices across a filtered payload is the hazard below.
89
+
90
+ > **The row-index hazard.** `__rowIdx__` is a position *within the payload a chart
91
+ > received*, not an id in your table. Re-render a chart with filtered rows and its payload
92
+ > renumbers from zero, so the same integer denotes a different record. `BicChartGroup` owns
93
+ > that mapping. Comparing indices across two charts by hand does not throw — it quietly
94
+ > filters to the wrong thing.
95
+
96
+ ### Sizing
97
+
98
+ Sizing is yours. Give each `<BicChart>` a sized container and pass `width`/`height` in
99
+ `options` — a chart handed `undefined` dimensions draws nothing visible.
100
+
101
+ ## 4. Things that will otherwise cost you time
102
+
103
+ - **Place names, not coordinates.** If your data has city/state/ZIP but no lat/lon, pass a
104
+ `point` binding and the host resolves coordinates. Never hardcode a city→coordinate table
105
+ from memory: it breaks silently off famous cities and reports nothing. The host reports
106
+ what it achieved in `options.geoPoint` — `precisionCounts` (rows per tier) and
107
+ `unplaced` — so a chart can annotate honestly instead of implying exact positions.
108
+ - **Both code forms work.** `wrap: "esm"` appends `export { render };` so the file can be
109
+ imported; chart-host strips the clause before compiling. Either form runs anywhere.
110
+ - **D3 plugins.** Some charts call `d3.sankey`, `d3.hexbin` etc., which live in separate
111
+ packages. `requiredD3Plugins(code)` tells you which to install **before** rendering;
112
+ `structuredContent.plugins` on the MCP result says the same thing.
113
+ - **Read `integration_contract`** in the MCP result if you need anything beyond this file —
114
+ it describes the exact payload and option shape for the chart you just generated.
115
+
116
+ ## 5. Check it
117
+
118
+ Verify in a real browser, not jsdom — a chart can pass a DOM-shape assertion and paint
119
+ nothing. Assert marks carry `data-row-idx`, that clicking one changes the other chart, and
120
+ that `Clear` restores both. If a check fails, suspect the probe before the product: query
121
+ `fillOpacity` as well as `opacity` when testing dimming, and match buttons by role rather
122
+ than by text that also appears in hint copy.