@bicharts/chart-mcp 0.6.101 → 0.6.104

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.101",
3
+ "version": "0.6.104",
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,10 +47,10 @@
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.99",
51
- "@bicharts/shape-core": "^0.6.99",
50
+ "@bicharts/chart-host": "^0.6.103",
51
+ "@bicharts/shape-core": "^0.6.103",
52
52
  "@modelcontextprotocol/sdk": "^1.32.1",
53
- "@types/node": "^20.0.0",
53
+ "@types/node": "^26.6.5",
54
54
  "@types/papaparse": "^5.3.14",
55
55
  "d3": "^7.9.0",
56
56
  "d3-hexbin": "^0.2.2",
@@ -59,7 +59,8 @@
59
59
  "esbuild": "^0.28.1",
60
60
  "happy-dom": "^20.14.5",
61
61
  "papaparse": "^5.4.1",
62
- "typescript": "^5.4.0",
63
- "zod": "^3.23.0"
62
+ "typescript": "^7.0.2",
63
+ "typescript5": "npm:typescript@^5.9.3",
64
+ "zod": "^4.6.7"
64
65
  }
65
66
  }
@@ -180,6 +180,12 @@ disqualifies it; leave it unset when they only asked for a chart, and the engine
180
180
  `@bicharts/chart-host` draws), `width`/`height`, and
181
181
  `reasoning_mode: "1P"` when you want the cheapest, fastest pass.
182
182
 
183
+ **Check a named request before generating it.** When the person's request names a chart type or something
184
+ specific (a date grain, a limit, an overlay, a column that must show), pass the same arguments to
185
+ `check_request` first. It says, in the service's own words, which asks this data can't honor and why,
186
+ with chart types that fit when the type itself is denied; tell the person what it denies and why rather
187
+ than generating around it. It spends no generation credits and is metered like `list_eligible_charts`.
188
+
183
189
  **Settings are the user's to answer, not yours to guess.** Every `generate_chart` result carries a
184
190
  `structuredContent.settings` block: `applied` lists each setting that took effect and whose choice it
185
191
  was (`user`, `app`, `default`, `server-roll`, `from-prompt`), `askable` names the ones still open to
@@ -547,9 +553,21 @@ overwrites a file, and its reply ends with a worked example. Building notes on m
547
553
  data service is on (the notes recipe below, step a), run it again with `features: ["notes", "scenarios"]`: it writes
548
554
  those files finished.
549
555
 
556
+ **The model's name is the `connection`.** Connect the semantic model the way the template's AGENTS.md says - before or
557
+ after `setup_fabric_app`, whose reply names it either way. On the template's current layout the model is a Rayfin
558
+ connector: `npx rayfin connector search "<model name>" --all-workspaces --type fabric-semanticmodel --json`, then the
559
+ `npx rayfin connector add --type fabric-semanticmodel --name <name> --workspace-id <id> --item-id <id>` it prints (ids from
560
+ the search, never guessed); the connector's name in `rayfin/rayfin.yml` is what `useSemanticModelQuery({ connection })`
561
+ takes. On the template's older layout (a `fabric.yaml`, `@microsoft/fabric-app-data`) it is the model's alias in
562
+ `fabric.yaml`. `query_semantic_model` and `suggest_charts` read it from whichever file the project has; pass `alias` only
563
+ when the project declares more than one.
564
+
550
565
  **1. Pull each chart's rows at the chart's GRAIN, with a query written for that chart.** One row per
551
- country for a country map, one per route for a flow map, one per month for a trend. The template's
552
- writing-phase command is `npx fabric-app-data query <alias> --query '<DAX>'`. Don't pull a fact
566
+ country for a country map, one per route for a flow map, one per month for a trend. The template's own
567
+ command runs a `.dax` file through the connector: `npx fabric-app-semantic-model-tools run-dax-query --dax <file.dax>
568
+ --alias <connector>` (on its older layout, `npx fabric-app-data query <alias> --query '<DAX>'`).
569
+ `query_semantic_model` runs the query through that same connector and the project's own sign-in, so a query it returned
570
+ has passed the template's check: don't run it again with `run-dax-query`. Don't pull a fact
553
571
  table and aggregate it in the browser: the Execute Queries API refuses a response over 15 MB, and a
554
572
  column repeated on every fact row (a country's population on each sale) sums to nonsense.
555
573
 
@@ -567,12 +585,14 @@ name. Pass the model's metadata as you rename: `isMeasure`, `format` and `descri
567
585
  Power BI visual gets for free. In `INFO.VIEW.COLUMNS()` a column's name is `[Name]`, not `[Column]`.
568
586
 
569
587
  **Steps 1-3 are one call: `query_semantic_model`.** Give it the chart's DAX (`dax`, or a `.dax` file) and a
570
- `name`; it runs the query through the project's own `fabric-app-data` CLI, renames the headers (dropping the
588
+ `name`; it runs the query through the project's own tooling - the model's Rayfin connector (through
589
+ `@microsoft/fabric-app-semantic-model-tools`, else the Rayfin CLI), or on the older layout the `fabric-app-data` CLI - so
590
+ it signs in and gets the reply the app will get. It renames the headers (dropping the
571
591
  table and any symbols: `[Occupancy %]` becomes `Occupancy`), saves every row to `.bic/data/<name>.csv`,
572
592
  reads each column's role, format and description from the model (`INFO.VIEW.MEASURES()` / `INFO.VIEW.COLUMNS()`),
573
593
  and profiles the result. Its reply ends with the arguments for the next two calls - `csv_path`, `measures`,
574
594
  `dimensions`, `formats`, `descriptions` - so pass them to `list_eligible_charts` and `generate_chart` as they
575
- are. The CLI returns at most 1,000 rows; the tool says so when it cut a result, and the fix is a query at the
595
+ are. It keeps at most 1,000 rows of a query; the tool says so when it cut a result, and the fix is a query at the
576
596
  chart's grain.
577
597
 
578
598
  **4. Ask before choosing, then choose what answers the question.** `list_eligible_charts` on that
@@ -590,13 +610,15 @@ without naming:
590
610
  | every place drawn at the same size, because which are high or low matters more than where | World tile-grid cartogram (or US hex-tile cartogram for states) |
591
611
  | actual against a budget, plan or target, with the gap shown for each period or unit | Variance chart (budget vs actual) |
592
612
  | that same actual-against-target comparison across many accounts or nested groups, read as a table with subtotals | Variance grid (a preview type) - it needs a category to group by; a date series alone is the Variance chart |
593
- | a table with one row per item and each value DRAWN (bars, dots or icons in the cells), so a reader can scan down a column | Table with embedded |
594
- | a table a reader sorts, hides columns in and opens a row's detail from, with plain values, chips or links | Interactive table (a preview type) |
613
+ | a table with one row per item and each value DRAWN (bars, dots or icons in the cells), compact, for scanning down a column and nothing more | Table with embedded |
614
+ | a table a reader WORKS with: sorts, drags column widths, copies cells out, hides columns, scrolls a wide table sideways with frozen columns or rows, opens a row's detail; plain values by default, and where the request asks, data bars, chips, icons, or one value compared with several others as bars (this week against its averages) | Interactive table (a preview type) - name the cells to draw in `prompt`; widths, sort and hidden columns are the reader's, kept through the host's view state |
595
615
  | circling a group of points to see what sets them apart from the rest | Selection explainer (a preview type) - the lasso and the comparison are drawn inside the chart; put the other fields to compare in the same table (which ones: below); on a page, give it `selects` so a circled group filters the page (step 6) |
596
616
 
597
617
  If the list doesn't offer what you expected, read its notes: it names a type refused on a count
598
618
  when your table is small, and it says when `name_filter` hid description matches.
599
619
 
620
+ The Interactive table and the Variance grid are preview types too, so either may be missing from the list. When the person asked for one and it isn't listed, say so and ask how to go on; don't build a table by hand in its place.
621
+
600
622
  The Selection explainer is a preview type: the server offers it only where it's switched on, so it may be missing from the
601
623
  list even when the data fits. When `list_eligible_charts` doesn't list it for your data, tell the person it isn't available
602
624
  for this data right now, and ask how they want to go on. Don't silently draw a plain scatter in its place, and don't write the
@@ -627,7 +649,8 @@ import { BicChartPanel } from "@/components/bic-chart-panel";
627
649
  import { useBicChartOptions } from "@/lib/bic-chart-options";
628
650
  import QUERY from "@/queries/overview/occupancy-map.dax?raw"; // the template's rule: DAX lives in .dax files
629
651
 
630
- const result = useSemanticModelQuery({ connection: "<alias>", query: QUERY }); // the DAX it was generated on
652
+ // connection: the model's connector name in rayfin/rayfin.yml (fabric.yaml's alias on the older layout)
653
+ const result = useSemanticModelQuery({ connection: "<connector name>", query: QUERY }); // the DAX it was generated on
631
654
  const options = useBicChartOptions();
632
655
  const country = useBicFilter("CountryIso3", { label: "Country", display: "CountryName" }); // step 6
633
656
  <BicChartPanel result={result}>
@@ -637,6 +660,11 @@ const country = useBicFilter("CountryIso3", { label: "Country", display: "Countr
637
660
  </BicChartPanel>
638
661
  ```
639
662
 
663
+ **A reader's view outlives the page only if you keep it.** What a reader sets inside a chart - an Interactive table's sort,
664
+ column widths and hidden columns, a 3D camera, an expanded row - lives while the chart is mounted and is gone on reload.
665
+ Pass `rememberAs="<a key per chart>"` to keep it in that browser, or `viewState={{ load, save }}` to keep it per signed-in
666
+ person on your server (a plain JSON bag). Hand-hosting `BicChart`, pass the same `viewState` prop.
667
+
640
668
  It is rewritten with the chart on every generation, so keep app logic outside it. What it does, if you
641
669
  host by hand instead - `generate_chart` returns `binding`; pass all three:
642
670
 
@@ -719,7 +747,7 @@ import FORECAST_DAX from "@/queries/overview/bookings-forecast.dax?raw";
719
747
  const country = useBicFilter("CountryIso3", { label: "Country", display: "CountryName" });
720
748
  const route = useBicFilter(["OriginCode", "DestinationCode"],
721
749
  { label: "Route", display: ["OriginName", "DestinationName"] });
722
- const forecast = useSemanticModelQuery({ connection: "<alias>",
750
+ const forecast = useSemanticModelQuery({ connection: "<connector name>",
723
751
  query: filterQuery(FORECAST_DAX, treatAs(country, "Geography[CountryIso3]")) });
724
752
 
725
753
  <BicFilterChips /> {/* "Country: Japan ×" - what's filtered, and its clear */}
@@ -786,8 +814,10 @@ npx rayfin init --services auth,data --auth-methods fabric --dialect mssql --ove
786
814
  Each flag is needed: without `--overwrite` it prints "Initialization cancelled" and exits 0 with no
787
815
  reason; without `--project-name` (pass the `id:` already in `rayfin/rayfin.yml`, so nothing is renamed)
788
816
  it stops with "--project-name is required in non-interactive mode". It rewrites `rayfin/rayfin.yml`
789
- and `.gitignore`, so `git diff` both and put back what's yours (on 1.36.1 it dropped the template's
790
- `src/fabric.generated.ts` line from `.gitignore`). It writes `rayfin/tsconfig.json` - keep its
817
+ and `.gitignore`, so `git diff` both and put back what's yours: on the template's connector layout that is the
818
+ `connectors:` list in `rayfin/rayfin.yml` (put it back, or run the same `npx rayfin connector add` again - without it
819
+ the app and `query_semantic_model` have no model) and the template's `.gitignore` lines; on the older layout, on 1.36.1, it
820
+ dropped the `src/fabric.generated.ts` line. It writes `rayfin/tsconfig.json` - keep its
791
821
  `outDir`, `.temp/compiled`, which is where the deploy reads the entities from - and no entities. On 1.36.2 it
792
822
  writes no `rayfin/data/schema.ts` either: don't write one by hand - `setup_fabric_app` with `features` (step c) writes it
793
823
  when `rayfin/rayfin.yml` shows the data service on.
@@ -796,9 +826,11 @@ when `rayfin/rayfin.yml` shows the data service on.
796
826
  - `rayfin/tsconfig.json`, in `compilerOptions`: `"tsBuildInfoFile": ".temp/tsconfig.tsbuildinfo"` and
797
827
  `"allowImportingTsExtensions": false` (it inherits both from the root: TS6377 and TS5096 otherwise).
798
828
  - the root `tsconfig.json`: `"references": [{ "path": "./rayfin" }]`.
799
- - type the client with your schema: `RayfinClient<AppSchema>` in `src/lib/rayfin-client.ts`
800
- (`import type { AppSchema } from "../../rayfin/data/schema";`) and in the constructor of
801
- `src/services/rayfin-auth.service.ts` (TS2345 otherwise).
829
+ - type the client with your schema (`import type { AppSchema } from "../../rayfin/data/schema";`): in
830
+ `src/lib/rayfin-client.ts`, on the connector layout, `AppSchema` in place of `EntitySchema` as the first type argument
831
+ of `ConnectorsRayfinClient<EntitySchema, FunctionsSchema, AppConnectorsSchema>` (the older layout's file has
832
+ `RayfinClient<AppSchema>`); and `RayfinClient<AppSchema>` in the constructor of `src/services/rayfin-auth.service.ts`
833
+ (TS2345 otherwise).
802
834
 
803
835
  Check with `npx tsc -b`; a bare `tsc --noEmit` reports TS6305 until the `rayfin/` project is built. If a
804
836
  TS2345 names two copies of `rayfin-auth`, something installed only some Rayfin packages: run
@@ -818,8 +850,9 @@ never rewrites them:
818
850
  chart's card (a card has a fixed height and `overflow-hidden`, and clips it). The reader's text is cleared only once
819
851
  the save succeeds; a failure is shown with the text kept.
820
852
 
821
- *d. Badges on the marks: pass `annotations`, never measure the chart.* The host draws each badge on its key's mark
822
- after every render and keeps it there through filters, re-queries and zooms; it never reads a row position. A route is
853
+ *d. Badges on the marks: pass `annotations`, never measure the chart.* The host draws each badge on its key's mark (on a
854
+ table row, just after the row's label; on a chart type that asks for it, such as a tile map, a small dot inside the
855
+ tile's top-right corner with the `label` and `title` in its tooltip) after every render and keeps it there through filters, re-queries and zooms; it never reads a row position. A route is
823
856
  keyed by BOTH of its ends with `where` - no key column to add, no query to change and no chart to regenerate:
824
857
 
825
858
  ```tsx