@bicharts/chart-mcp 0.6.104 → 0.6.107

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.6.104",
3
+ "version": "0.6.107",
4
4
  "description": "AI Data Components for Power BI, Excel, Fabric Apps and the web, over MCP: bivariate maps, what-if projections and about 90 everyday chart types, with selection and cross-filtering already wired. It profiles your table locally; the code it writes is yours and runs with no license.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -47,8 +47,8 @@
47
47
  },
48
48
  "// dependencies": "NONE, deliberately. dist/ bundles every module the server uses, so a runtime dependency installs nothing it needs - it only makes npx fetch that package (and its tree) before the first start. Everything the bundle carries is a devDependency; scripts/verify-package.mjs fails the release if a dependency appears or a shipped file imports anything but Node's built-ins.",
49
49
  "devDependencies": {
50
- "@bicharts/chart-host": "^0.6.103",
51
- "@bicharts/shape-core": "^0.6.103",
50
+ "@bicharts/chart-host": "^0.6.107",
51
+ "@bicharts/shape-core": "^0.6.107",
52
52
  "@modelcontextprotocol/sdk": "^1.32.1",
53
53
  "@types/node": "^26.6.5",
54
54
  "@types/papaparse": "^5.3.14",
@@ -15,7 +15,9 @@ on the same picture, not a looser one.
15
15
  | chart | needs | limits | renderers | good for |
16
16
  | --- | --- | --- | --- | --- |
17
17
  | 3D scatter plot | 3 continuous | needs 700x480 px | D3, Plotly | Three continuous measures whose joint structure is the question, on a tile large enough to turn. To read exact values off three or more measures, Pair plot (scatter matrix) and Parallel coordinates are both more precise |
18
+ | Africa (Bubbles) | lat/lon | needs 400x300 px | D3 | Best for point, city, province or country data within Africa: stores, offices, customers or revenue by place, with a measure for bubble size and optionally a second measure or category for color |
18
19
  | Africa Choropleth | 1 categorical, geo: country-iso3/country-iso2/country-name | <=250 categories, needs 400x300 px | D3 | Best for country-level metrics when the countries are in Africa: sales, users, or population by country (keyed to country names or ISO codes) |
20
+ | Africa Choropleth (by province) | 1 categorical, geo: admin1-code/admin1-name/city-name/city-name-world/latlon | <=2000 categories, needs 400x300 px, host-only: the Power BI visual and the Excel add-in, never this MCP | D3 | Best for metrics by province, state or region in Africa, or by city when you want the cities summed into their provinces (keyed to province names, ISO codes or city names) |
19
21
  | Animated bar chart | 1 categorical, 1 continuous, 5+ time points | <=40 categories, needs 360x300 px | D3 | Requires one categorical, one measure and a time column with 5 or more ordered periods; best for a leaderboard that changes over time (top products by year, teams by season, countries by decade) |
20
22
  | Animated treemap | 2 categorical, 1 continuous, 3+ time points | needs 800x560 px | D3 | Requires a 2-level categorical hierarchy plus an additive measure observed at 3 or more ordered time points |
21
23
  | Animated World (Bubbles) | 3+ time points, lat/lon | needs 400x320 px | D3 | Best for a measure per place observed at 3 or more ordered time points - revenue by country by year, openings by city by quarter, throughput by port by month - when the question is how each place changed rather than where it ranks |
@@ -23,7 +25,9 @@ on the same picture, not a looser one.
23
25
  | Annotated heatmap | 2 categorical, 1 continuous | <=20 categories, needs 320x280 px | D3, Matplotlib, Plotly, Seaborn | Requires two variables: categorical × categorical with values |
24
26
  | Arc diagram | 2 categorical | <=50 nodes, needs 380x240 px | D3 | Best for 5-50 nodes and a sparse-to-medium-density set of pairwise relationships |
25
27
  | Area chart | 1 continuous | needs 360x280 px | D3, Matplotlib, Plotly, Seaborn | Requires ordered categories or time with a continuous variable |
28
+ | Asia (Bubbles) | lat/lon | needs 400x300 px | D3 | Best for point, city, province or country data within Asia: stores, offices, customers or revenue by place, with a measure for bubble size and optionally a second measure or category for color |
26
29
  | Asia Choropleth | 1 categorical, geo: country-iso3/country-iso2/country-name | <=250 categories, needs 400x300 px | D3 | Best for country-level metrics when the countries are in Asia: sales, users, or population by country (keyed to country names or ISO codes) |
30
+ | Asia Choropleth (by province) | 1 categorical, geo: admin1-code/admin1-name/city-name/city-name-world/latlon | <=2000 categories, needs 400x300 px, host-only: the Power BI visual and the Excel add-in, never this MCP | D3 | Best for metrics by province, state or region in Asia, or by city when you want the cities summed into their provinces (keyed to province names, ISO codes or city names) |
27
31
  | Autocorrelation plot | 1 continuous, 20+ time points | needs 400x300 px | D3, Matplotlib, Plotly, Statsmodels | Requires a datetime series with one continuous variable |
28
32
  | Bar chart (horizontal) | - | needs 360x280 px | D3, Matplotlib, Plotly, Seaborn | Requires one categorical and one numeric variable |
29
33
  | Bar chart (vertical) | - | needs 600x420 px | D3, Matplotlib, Plotly, Seaborn | Requires one categorical and one numeric variable |
@@ -59,7 +63,9 @@ on the same picture, not a looser one.
59
63
  | ECDF plot | 1 continuous | needs 299x283 px | D3, Matplotlib, Plotly, Seaborn, Statsmodels | Requires one continuous variable |
60
64
  | Error band | 1 continuous | needs 360x240 px | D3 | Best for repeated measurements over time or over a continuous axis: latency trials, sensor readings, A/B metrics - anywhere the SPREAD matters as much as the average |
61
65
  | Error bar plot | 1 categorical, 1 continuous | needs 460x340 px | D3, Matplotlib, Plotly, Seaborn | Requires a category and a measure with a spread to show - repeated rows per category or a second measure holding the error |
66
+ | Europe (Bubbles) | lat/lon | needs 400x300 px | D3 | Best for point, city, province or country data within Europe: stores, offices, customers or revenue by place, with a measure for bubble size and optionally a second measure or category for color |
62
67
  | Europe Choropleth | 1 categorical, geo: country-iso3/country-iso2/country-name | <=250 categories, needs 400x300 px | D3 | Best for country-level metrics when the countries are in Europe: sales, users, or population by country (keyed to country names or ISO codes) |
68
+ | Europe Choropleth (by province) | 1 categorical, geo: admin1-code/admin1-name/city-name/city-name-world/latlon | <=2000 categories, needs 400x300 px, host-only: the Power BI visual and the Excel add-in, never this MCP | D3 | Best for metrics by province, state or region in Europe, or by city when you want the cities summed into their provinces (keyed to province names, ISO codes or city names) |
63
69
  | Event plot | 1 continuous | needs 400x300 px | D3, Matplotlib, Plotly, Seaborn | Requires a date or ordered value for each event, with an optional category that splits the events into lanes |
64
70
  | Flippable multi-card | 1 continuous | <=12 categories, needs 180x120 px | D3 | Best when more headline numbers compete for one tile than fit at once: several measures side by side, or one or two measures paged through a small category, with the details on hover |
65
71
  | Funnel chart | 1 continuous | <=12 categories, needs 460x340 px | D3, PLOTLY | Best for conversion/attrition pipelines: signup funnels, sales pipeline stages, checkout flow drop-off |
@@ -81,13 +87,17 @@ on the same picture, not a looser one.
81
87
  | Lollipop chart | 1 categorical, 1 continuous | <=50 categories, needs 700x480 px | D3, PLOTLY | Best as a cleaner bar replacement for ranking many categories by a single measure |
82
88
  | Marimekko / Mosaic plot | 2 categorical, 1 continuous | needs 320x280 px | D3 | Best for 3-10 outer × 3-10 inner categories with a positive measure |
83
89
  | Mermaid diagram | 1 categorical | <=150 categories, needs 360x240 px | D3 | A source and a target column (a process, a hand-off chain, a dependency list), two to four nested categories (an org or product hierarchy), or a date beside an event name (milestones, releases, history) - up to a few dozen boxes |
90
+ | Middle East Choropleth | 1 categorical, geo: country-iso3/country-iso2/country-name | <=250 categories, needs 400x300 px | D3 | Best for country-level metrics when the countries are in the Middle East: sales, users, or population by country (keyed to country names or ISO codes) |
84
91
  | Motion bubble chart | 1 categorical, 2 continuous, 3+ time points | <=40 categories, needs 360x320 px | D3 | Requires one categorical whose members are the bubbles, two measures for position and a time column with 3 or more ordered periods; best for watching entities travel - plans by subscribers and churn, countries by wealth and lifespan, teams by cost and output |
85
92
  | Multi-level Sankey | 3 categorical, 1 continuous | <=80 edges, needs 420x280 px | D3, Plotly | Requires three (or more) categorical and one continuous variable |
86
93
  | Network diagram | 2 categorical | <=150 categories, <=80 edges, needs 320x280 px | D3, Matplotlib | Requires node and edge data (source-target pairs); best for relationship, dependency, or social network visualization |
87
94
  | Normalized stacked bar chart | 2 categorical, 1 continuous | needs 600x420 px | D3 | Best with two categoricals and one additive measure when the question is what the composition is rather than how big the total is |
88
95
  | North America (Bubbles) | lat/lon | needs 400x300 px | D3 | Best for point-located data with latitude and longitude columns: stores, cities, facilities, or events across North America, with a measure for bubble size and optionally a second measure or category for color |
89
96
  | North America Choropleth | 1 categorical, geo: country-iso3/country-iso2/country-name | <=250 categories, needs 400x300 px | D3 | Best for country-level metrics when the countries are in North America: sales, users, or population by country (keyed to country names or ISO codes) |
97
+ | North America Choropleth (by province) | 1 categorical, geo: admin1-code/admin1-name/city-name/city-name-world/latlon/us-state-code/us-state-name | <=2000 categories, needs 400x300 px, host-only: the Power BI visual and the Excel add-in, never this MCP | D3 | Best for metrics by province, state or region in North America, or by city when you want the cities summed into their provinces (keyed to province names, ISO codes or city names) |
98
+ | Oceania (Bubbles) | lat/lon | needs 400x300 px | D3 | Best for point, city, province or country data within Oceania: stores, offices, customers or revenue by place, with a measure for bubble size and optionally a second measure or category for color |
90
99
  | Oceania Choropleth | 1 categorical, geo: country-iso3/country-iso2/country-name | <=250 categories, needs 400x300 px | D3 | Best for country-level metrics when the countries are in Oceania: sales, users, or population by country (keyed to country names or ISO codes) |
100
+ | Oceania Choropleth (by province) | 1 categorical, geo: admin1-code/admin1-name/city-name/city-name-world/latlon | <=2000 categories, needs 400x300 px, host-only: the Power BI visual and the Excel add-in, never this MCP | D3 | Best for metrics by province, state or region in Oceania, or by city when you want the cities summed into their provinces (keyed to province names, ISO codes or city names) |
91
101
  | Origin-Destination Flow Map | lat/lon | needs 400x300 px | D3 | Best for movement between places: flight routes, shipping and trade lanes, migration, commutes or transfers, where each row names where something started and where it ended plus a measure of how much moved |
92
102
  | Packed circles | 2 categorical, 1 continuous | needs 280x280 px | D3 | Best with one numeric measure plus 1-2 categorical groupings producing 20-150 leaves |
93
103
  | Pair plot (scatter matrix) | 3 continuous | needs 480x400 px | D3, Matplotlib, Plotly, Seaborn | Requires at least three continuous variables |
@@ -108,7 +118,9 @@ on the same picture, not a looser one.
108
118
  | Seasonal decomposition | 1 continuous, 24+ time points | needs 320x360 px | Matplotlib, Plotly, Statsmodels | Requires a datetime series with one continuous variable and at least two full seasonal cycles |
109
119
  | Selection explainer | 2 continuous | needs 560x360 px | D3 | Two measures over thirty or more rows that also carry other fields - region, plan, tenure, size - when the question is 'what do these points have in common?' |
110
120
  | Slope chart | 1 categorical, 1 continuous, 2+ time points | <=40 categories, needs 460x340 px | D3, PLOTLY | Best for two-period change across many categories: YoY by region/segment, before/after comparisons, ranking shifts between two snapshots |
121
+ | South America (Bubbles) | lat/lon | needs 400x300 px | D3 | Best for point, city, province or country data within South America: stores, offices, customers or revenue by place, with a measure for bubble size and optionally a second measure or category for color |
111
122
  | South America Choropleth | 1 categorical, geo: country-iso3/country-iso2/country-name | <=250 categories, needs 400x300 px | D3 | Best for country-level metrics when the countries are in South America: sales, users, or population by country (keyed to country names or ISO codes) |
123
+ | South America Choropleth (by province) | 1 categorical, geo: admin1-code/admin1-name/city-name/city-name-world/latlon | <=2000 categories, needs 400x300 px, host-only: the Power BI visual and the Excel add-in, never this MCP | D3 | Best for metrics by province, state or region in South America, or by city when you want the cities summed into their provinces (keyed to province names, ISO codes or city names) |
112
124
  | Spiral plot | 1 continuous, 12+ time points | needs 320x320 px | D3, PLOTLY | Best for long, finely-grained, strongly periodic series (years of daily data) where the cyclic pattern is the story |
113
125
  | Stacked area chart | 1 categorical, 1 continuous | needs 460x340 px | D3, Matplotlib, Plotly | Requires ordered categories with multiple continuous series |
114
126
  | Stacked bar chart | 2 categorical, 1 continuous | needs 700x480 px | D3, Matplotlib, Plotly, Seaborn | Requires one categorical, one subcategory, and one numeric variable |
@@ -1,6 +1,6 @@
1
1
  ---
2
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".
3
+ description: Build a web app or dashboard containing BIC-generated charts, maps, tables and app widgets — a bubble map, a table with in-cell bars, a table readers work with and keep their own way, a what-if widget, linked cross-filtering. Use whenever the bic-chart MCP tools are available and the task is "put a chart, map, table, widget or dashboard in this app".
4
4
  ---
5
5
 
6
6
  # Building an app with BIC charts
@@ -9,6 +9,11 @@ The golden path, end to end. Following it costs a handful of tool calls; derivin
9
9
  first principles costs about thirty, and the places people lose time are all called out
10
10
  below because they were all measured.
11
11
 
12
+ **Not only charts.** Maps, tables a reader works with and app widgets (KPI cards, what-if controls, card decks) are
13
+ built here like any chart: `list_eligible_charts` offers them and `generate_chart` writes each with its component.
14
+ Asked for one, list first, before hand-building it or reaching for another grid, map or widget library; step 5 says
15
+ how a generated table's component keeps the reader's view.
16
+
12
17
  **The mental model.** A BIC chart is *generated source you own* — a plain
13
18
  `render(container, data, options)` function you commit to your repo. There is no API key at
14
19
  run time, no per-render cost, and no network call. `@bicharts/chart-host` runs it; the MCP
@@ -287,8 +292,11 @@ Ctrl/Cmd/Shift-click adds or removes one mark, and a click on empty canvas clear
287
292
  import * as d3base from "d3";
288
293
  import { assembleD3, createChartGroup, createChartHost, loadGeo } from "@bicharts/chart-host";
289
294
  import { createLegendFitPass } from "@bicharts/chart-host/legend-fit";
295
+ import { hostLinkServices } from "@bicharts/chart-host";
290
296
 
291
297
  const d3 = assembleD3(d3base); // + any plugins a chart's contract names
298
+ // A chart opens a link and copies only through these (a new tab, the clipboard): built once, for every chart.
299
+ const links = hostLinkServices(u => window.open(u, "_blank", "noopener,noreferrer"), navigator.clipboard);
292
300
  const at = (path) => new URL(path, document.baseURI); // honors <base href> on a sub-path host
293
301
  async function text(path) {
294
302
  const r = await fetch(at(path));
@@ -333,7 +341,7 @@ export async function createGroup(sampleUrl, dotnet) {
333
341
  const host = createChartHost(el, {
334
342
  code, d3, geoKind: spec.geoKind || undefined,
335
343
  data: group.memberPayload(spec.id, opts).payload,
336
- options: { width: Math.floor(el.getBoundingClientRect().width), height: spec.height, ...theme(el), ...(lasso ? { lasso } : {}) },
344
+ options: { width: Math.floor(el.getBoundingClientRect().width), height: spec.height, ...links, ...theme(el), ...(lasso ? { lasso } : {}) },
337
345
  layoutPass: createLegendFitPass(), // after every render: a legend slid clear of the plot, text brought inside the frame
338
346
  });
339
347
  host.render();
@@ -670,6 +678,7 @@ host by hand instead - `generate_chart` returns `binding`; pass all three:
670
678
 
671
679
  ```tsx
672
680
  import * as d3 from "d3";
681
+ import { hostLinkServices } from "@bicharts/chart-host";
673
682
  import { BicChart, BicChartGroup } from "@bicharts/chart-host/react";
674
683
  import { createLegendFitPass } from "@bicharts/chart-host/legend-fit";
675
684
  import code from "@/charts/occupancy-map/chart.js?raw";
@@ -681,6 +690,8 @@ const RENAME = { "Geography[CountryIso3]": "CountryIso3", "Geography[CountryName
681
690
  "[Average Daily Rate]": "AverageDailyRate", "[Occupancy %]": "Occupancy" };
682
691
 
683
692
  const LAYOUT_PASS = createLegendFitPass(); // once, at module scope: a new function on each render rebuilds the host
693
+ // A chart opens a link and copies only through these (a new tab, the clipboard). Once, at module scope, too.
694
+ const LINKS = hostLinkServices(u => window.open(u, "_blank", "noopener,noreferrer"), navigator.clipboard);
684
695
 
685
696
  function CountryMap({ table, onPick }) { // table = the live query result
686
697
  const rows = table.rows.map(r => Object.fromEntries(
@@ -689,7 +700,7 @@ function CountryMap({ table, onPick }) { // table = the live query resu
689
700
  <BicChartGroup columns={columns} rows={rows}
690
701
  geo={binding.geo} point={binding.point} destination={binding.destination}>
691
702
  <BicChart id="map" code={code} d3={d3} geoKind={geoKind}
692
- options={{ width, height }} layoutPass={LAYOUT_PASS}
703
+ options={{ width, height, ...LINKS }} layoutPass={LAYOUT_PASS}
693
704
  onSelect={idxs => onPick(idxs.length ? rows[idxs[0]].CountryIso3 : null)} />
694
705
  </BicChartGroup>
695
706
  );
@@ -705,6 +716,9 @@ function CountryMap({ table, onPick }) { // table = the live query resu
705
716
  - **`LAYOUT_PASS` is built once, at module scope, and needs `@bicharts/chart-host` 0.6.86 or later.** After
706
717
  every render it slides a legend clear of the plot and brings text that runs past the frame back inside; the
707
718
  chart component `generate_chart` writes does the same, and a new function on each render would rebuild the host.
719
+ - **`LINKS` (`hostLinkServices`, `@bicharts/chart-host` 0.6.103 or later) is how a chart opens a link and copies.** A
720
+ table's link column draws as a link only where `openUrl` exists; only http(s) and mailto open, and nothing is logged.
721
+ The chart component passes the same; inside a sandboxed iframe the new tab needs `allow-popups`.
708
722
  - **The result's `capabilities.lasso` means the chart takes chart-host's lasso (`@bicharts/chart-host` 0.6.84 or later).**
709
723
  Pass `lasso: { capable: true, enabled: true }` in that chart's `options` (add `rowCap` when the result gives one), and a
710
724
  drag around marks selects the ones inside through the same `onSelect` / `selects` a click uses: the gesture and the