@microcharts/mcp 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ganapati V S
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # @microcharts/mcp
2
+
3
+ An MCP server and Vercel AI-SDK toolset for [microcharts](https://microcharts.dev) — let a model **find** the right
4
+ word-sized chart, **get** exactly how to wire it, and **render** it to a finished SVG with real alt text.
5
+
6
+ microcharts is built so a model can _write_ charts. This is how a model _calls_ them: not "emit some grammar and hope
7
+ the client renders it," but a tool call that returns the real library's static SVG, honest by construction, with the
8
+ generated `describeSeries` accessible name attached.
9
+
10
+ - **Runs on your machine.** stdio server, distributed on npm. Nothing is hosted; no account, no key, no data leaves.
11
+ - **Works anywhere.** The render tool returns self-contained SVG, so a chat surface that can't run React can still show
12
+ a real chart.
13
+ - **Zero setup.** `npx @microcharts/mcp` — the package brings its own copy of `@microcharts/react`.
14
+
15
+ ## Install
16
+
17
+ Add it to any MCP client. For **Claude Desktop** (`claude_desktop_config.json`) or **Cursor** (`.cursor/mcp.json`):
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "microcharts": {
23
+ "command": "npx",
24
+ "args": ["-y", "@microcharts/mcp"]
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ That's it — the client spawns the server over stdio on demand.
31
+
32
+ ## Tools
33
+
34
+ ### `find_microchart(question, dataShape?)`
35
+
36
+ Rank the catalog against a plain-language question. Start here when you know the question, not the chart.
37
+
38
+ ```
39
+ find_microchart({ question: "is it trending?" })
40
+ → [{ slug: "sparkline", name: "Sparkline", why: "inline trend", dataShape: "number[]" }, …]
41
+ ```
42
+
43
+ ### `get_microchart(slug)`
44
+
45
+ Everything needed to wire one chart: import paths, its props plus the shared props, data shape, best/avoid guidance, a
46
+ copy-runnable example, and `sample` — that same example as JSON props, ready to pass straight to `render_microchart`.
47
+
48
+ ```
49
+ get_microchart({ slug: "bullet" })
50
+ → {
51
+ staticImport: "@microcharts/react/bullet",
52
+ props: [...],
53
+ example: { code: "<Bullet value={72} target={80} bands={[50, 90]} title=\"Quota\" />" },
54
+ sample: { value: 72, target: 80, bands: [50, 90], title: "Quota" },
55
+
56
+ }
57
+ ```
58
+
59
+ Every chart takes its own data shape — `number[]` for a sparkline, `{ label, value }[]` for a dot plot,
60
+ `{ open, high, low, close }[]` for OHLC — so `sample` is the shortest path from "which chart" to "a render that works".
61
+
62
+ ### `render_microchart(type, data?, props?, format?)`
63
+
64
+ Render to a finished, self-contained SVG plus its generated alt text. Pass the series as `data`; put other props
65
+ (`value`, `target`, `curve`, `color`, `width`) in `props`.
66
+
67
+ ```
68
+ render_microchart({ type: "sparkline", data: [132, 148, 141, 165, 159, 182] })
69
+ → {
70
+ svg: "<svg …><style>…</style>…</svg>",
71
+ summary: "Trending up 38%. Range 132 to 182. Last value 182.",
72
+ mimeType: "image/svg+xml", width: 80, height: 20
73
+ }
74
+ ```
75
+
76
+ `format` is `"svg"` (default, styles embedded — drops into any surface) or `"bare"` (no CSS, for pages that already load
77
+ `@microcharts/react/styles.css`).
78
+
79
+ Missing or wrong-shaped data is rejected by name rather than passed through to React, so a caller gets
80
+ `"dot-plot" needs \`data\`. Data shape: { label, value }[]. Call get_microchart("dot-plot") for a ready-to-render
81
+ sample.` instead of a stack trace. Oversized payloads are refused too — a microchart is a word-sized mark.
82
+
83
+ It also exposes two resources: `microcharts://catalog` (every chart + metadata) and `microcharts://agent-setup` (the
84
+ prompt for wiring microcharts into a codebase).
85
+
86
+ ## Use it from the Vercel AI SDK
87
+
88
+ The same three capabilities ship as AI-SDK tools (on the `/ai-sdk` subpath, so the core never pulls in `ai`):
89
+
90
+ ```ts
91
+ import { microchartsTools } from "@microcharts/mcp/ai-sdk";
92
+ import { streamText } from "ai";
93
+
94
+ const result = streamText({
95
+ model,
96
+ tools: microchartsTools,
97
+ prompt: "Summarise this quarter and show the revenue trend as a chart.",
98
+ });
99
+ ```
100
+
101
+ The functions are exported directly too — `findChart`, `getChart`, `renderChart` — if you want them without the tool
102
+ wrapper.
103
+
104
+ ## Versioning
105
+
106
+ This server bundles the chart catalog and renders with `@microcharts/react` (installed as a normal dependency). Its
107
+ version tracks its own changes; a compatible library is pulled in automatically. The library version a given snapshot
108
+ was cut from is on the `microcharts://catalog` resource.
109
+
110
+ ## Links
111
+
112
+ - Docs: <https://microcharts.dev/docs/mcp>
113
+ - Library: [`@microcharts/react`](https://www.npmjs.com/package/@microcharts/react)
114
+ - Source: <https://github.com/ganapativs/microcharts/tree/main/packages/mcp>
115
+
116
+ MIT
@@ -0,0 +1,10 @@
1
+ import { ToolSet } from "ai";
2
+ //#region src/ai-sdk.d.ts
3
+ /**
4
+ * The same three capabilities as the MCP server, packaged as Vercel AI-SDK
5
+ * tools for apps built with the `ai` package: `import { microchartsTools }` and
6
+ * spread them into `streamText`/`generateText`. One core, two front doors.
7
+ */
8
+ declare const microchartsTools: ToolSet;
9
+ //#endregion
10
+ export { microchartsTools };
@@ -0,0 +1,46 @@
1
+ import { i as findChart, r as getChart, t as renderChart } from "./render-core-CnQfk-v1.mjs";
2
+ import { z } from "zod";
3
+ import { tool } from "ai";
4
+ //#region src/ai-sdk.ts
5
+ /**
6
+ * The same three capabilities as the MCP server, packaged as Vercel AI-SDK
7
+ * tools for apps built with the `ai` package: `import { microchartsTools }` and
8
+ * spread them into `streamText`/`generateText`. One core, two front doors.
9
+ */
10
+ const microchartsTools = {
11
+ find_microchart: tool({
12
+ description: "Find which microcharts chart type best answers a question about data (e.g. \"is it trending?\", \"error budget\", \"part to whole\"). Returns ranked candidates with the reason each matched. Call this first when you know the question but not the chart.",
13
+ inputSchema: z.object({
14
+ question: z.string().describe("What the data needs to show, in plain language."),
15
+ dataShape: z.string().optional().describe("Optional filter, e.g. \"number[]\" or \"{label,value}[]\"."),
16
+ limit: z.number().int().min(1).max(20).optional().describe("Max results (default 6).")
17
+ }),
18
+ execute: async ({ question, dataShape, limit }) => findChart(question, {
19
+ ...dataShape ? { dataShape } : {},
20
+ ...limit ? { limit } : {}
21
+ })
22
+ }),
23
+ get_microchart: tool({
24
+ description: "Get the full wiring detail for one chart by slug: import paths, its props plus the shared props, the data shape, best/avoid guidance, and a copy-runnable example. Call after find_microchart to scaffold the component.",
25
+ inputSchema: z.object({ slug: z.string().describe("Chart slug, e.g. \"sparkline\" or \"bullet\".") }),
26
+ execute: async ({ slug }) => getChart(slug) ?? { error: `Unknown chart "${slug}".` }
27
+ }),
28
+ render_microchart: tool({
29
+ description: "Render a chart to a finished, self-contained SVG string (styles embedded) plus its generated alt text — usable in any surface that can't run React. Pass the series as `data` and any other props (value, target, curve, color, width) in `props`; check get_microchart for the exact shape.",
30
+ inputSchema: z.object({
31
+ type: z.string().describe("Chart slug, e.g. \"sparkline\"."),
32
+ data: z.any().optional().describe("Primary series; omit for scalar charts."),
33
+ props: z.record(z.string(), z.any()).optional().describe("Other props (value, target, color, …)."),
34
+ format: z.enum(["svg", "bare"]).optional().describe("`svg` (default, self-contained) or `bare` (no embedded CSS).")
35
+ }),
36
+ execute: async (input) => {
37
+ try {
38
+ return await renderChart(input);
39
+ } catch (err) {
40
+ return { error: err.message };
41
+ }
42
+ }
43
+ })
44
+ };
45
+ //#endregion
46
+ export { microchartsTools };
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export {}
package/dist/cli.mjs ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { t as createServer } from "./server-C0ga2mbD.mjs";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ //#region src/cli.ts
5
+ /**
6
+ * The stdio entry point (`npx @microcharts/mcp`). A client (Claude Desktop,
7
+ * Cursor, …) spawns this process and speaks MCP over stdin/stdout. Nothing is
8
+ * hosted; it runs on the user's machine.
9
+ */
10
+ async function main() {
11
+ await createServer().connect(new StdioServerTransport());
12
+ }
13
+ main().catch((err) => {
14
+ process.stderr.write(`microcharts-mcp: ${err.message}\n`);
15
+ process.exit(1);
16
+ });
17
+ //#endregion
18
+ export {};
@@ -0,0 +1,190 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ //#region src/tools/find.d.ts
3
+ interface FindResult {
4
+ slug: string;
5
+ name: string;
6
+ tagline: string;
7
+ dataShape: string;
8
+ /** Why this chart matched — the bestFor phrase or tagline that hit. */
9
+ why: string;
10
+ }
11
+ interface FindOptions {
12
+ /** Filter to charts whose dataShape contains this substring (e.g. "number[]"). */
13
+ dataShape?: string;
14
+ /** Max results (default 6). */
15
+ limit?: number;
16
+ }
17
+ /**
18
+ * Rank the catalog against a natural-language question ("is it trending?",
19
+ * "error budget", "part to whole"). Pure over the committed snapshot — no
20
+ * rendering, no library import. Returns only stable charts (the wireable set),
21
+ * best first; empty when nothing scores.
22
+ */
23
+ declare function findChart(question: string, opts?: FindOptions): FindResult[];
24
+ //#endregion
25
+ //#region src/types.d.ts
26
+ /**
27
+ * Local mirror of the catalog shapes the package consumes. Kept self-contained
28
+ * (not imported from the docs app) so the published package never reaches into
29
+ * `apps/docs`. The `catalog-sync` test guarantees `catalog.generated.json` still
30
+ * matches the live registry, so these types can't silently drift.
31
+ */
32
+ interface ChartProp {
33
+ name: string;
34
+ type: string;
35
+ required: boolean;
36
+ description: string;
37
+ /** `true` ⇒ only on the `…/interactive` entry (callbacks, announce config). */
38
+ interactive?: boolean;
39
+ }
40
+ interface ChartEntry {
41
+ name: string;
42
+ slug: string;
43
+ status: "stable" | "planned";
44
+ collection: "core" | "decision" | "expressive" | "frontier";
45
+ variantOf?: string;
46
+ tagline: string;
47
+ staticImport: string;
48
+ interactiveImport?: string;
49
+ animates?: boolean;
50
+ picker?: false;
51
+ dataShape: string;
52
+ encoding: {
53
+ channel: string;
54
+ precision: string;
55
+ };
56
+ nodeBudget: string;
57
+ bestFor: string[];
58
+ avoidFor: string[];
59
+ props: ChartProp[];
60
+ /** Copy-runnable snippet — sample-data definitions already prepended. */
61
+ example: {
62
+ title: string;
63
+ code: string;
64
+ };
65
+ /**
66
+ * A ready-to-render JSON prop bag derived from `example` at generation time —
67
+ * what `render_microchart` actually takes. Present for every chart whose
68
+ * example is fully serializable; absent when the example is mostly callbacks.
69
+ */
70
+ sample?: Record<string, unknown>;
71
+ }
72
+ /** The committed snapshot: catalog data + the library version it was cut from. */
73
+ interface Catalog {
74
+ /** `@microcharts/react` version this snapshot was generated from. */
75
+ library: string;
76
+ /** Shared grammar/layout/i18n props every chart accepts. */
77
+ sharedProps: ChartProp[];
78
+ charts: ChartEntry[];
79
+ }
80
+ //#endregion
81
+ //#region src/tools/get.d.ts
82
+ interface GetResult {
83
+ slug: string;
84
+ name: string;
85
+ tagline: string;
86
+ status: "stable" | "planned";
87
+ dataShape: string;
88
+ encoding: {
89
+ channel: string;
90
+ precision: string;
91
+ };
92
+ staticImport: string;
93
+ interactiveImport?: string;
94
+ bestFor: string[];
95
+ avoidFor: string[];
96
+ props: ChartProp[];
97
+ /** Grammar / layout / i18n props every chart accepts, in addition to `props`. */
98
+ sharedProps: ChartProp[];
99
+ /** Copy-runnable example: sample-data defs prepended to the snippet. */
100
+ example: {
101
+ title: string;
102
+ code: string;
103
+ };
104
+ /**
105
+ * The same example as a JSON prop bag — exactly what `render_microchart`
106
+ * takes. `example.code` is JSX for a human to paste; this is for a model to
107
+ * adapt. Absent only if the example is not fully serializable.
108
+ */
109
+ sample?: Record<string, unknown>;
110
+ }
111
+ /**
112
+ * Full wiring detail for one chart: import paths, its own props + the shared
113
+ * props, dataShape, best/avoid, and a copy-runnable example. Pure over the
114
+ * snapshot. Returns undefined for an unknown slug.
115
+ */
116
+ declare function getChart(slug: string): GetResult | undefined;
117
+ //#endregion
118
+ //#region src/render-core.d.ts
119
+ /**
120
+ * Render a static chart to a self-contained SVG string, using the real
121
+ * `@microcharts/react` static component (imported at runtime from the package's
122
+ * own dependency — carry model A). The default `svg` format embeds the shipped
123
+ * stylesheet so the mark renders correctly dropped into any surface with no
124
+ * external CSS; `bare` omits it for callers that already load `styles.css`.
125
+ *
126
+ * The `summary` is the chart's own generated accessible name (read back out of
127
+ * the rendered markup) — correct for every data shape, no assumption that the
128
+ * data is a number series.
129
+ *
130
+ * React and `react-dom/server` are imported lazily, inside the first render:
131
+ * a session that only calls `find` / `get` (and every consumer of the AI-SDK
132
+ * subpath that never renders) then never pays for loading them.
133
+ */
134
+ type RenderFormat = "svg" | "bare";
135
+ interface RenderResult {
136
+ /** The rendered mark. SVG for most charts; HTML for the few inline text marks
137
+ * (delta, token-confidence) — see `mimeType`. */
138
+ svg: string;
139
+ /** `image/svg+xml` for SVG-rooted charts, `text/html` for inline text marks. */
140
+ mimeType: "image/svg+xml" | "text/html";
141
+ /** The chart's generated accessible name — its honest alt text. */
142
+ summary: string;
143
+ /** Pixel size for SVG-rooted charts; 0 for font-relative inline marks. */
144
+ width: number;
145
+ height: number;
146
+ /** The `@microcharts/react` version that produced this render. */
147
+ library: string;
148
+ }
149
+ interface RenderInput {
150
+ /** Chart slug, e.g. "sparkline". */
151
+ type: string;
152
+ /** Primary data — mapped to the `data` prop; omit for scalar charts. */
153
+ data?: unknown;
154
+ /** Any other props (e.g. `value`, `target`, `curve`, `color`, `width`). */
155
+ props?: Record<string, unknown> | undefined;
156
+ /** `svg` (default, self-contained) or `bare` (no embedded CSS). */
157
+ format?: RenderFormat | undefined;
158
+ }
159
+ declare function renderChart(input: RenderInput): Promise<RenderResult>;
160
+ //#endregion
161
+ //#region src/server.d.ts
162
+ /**
163
+ * Build the microcharts MCP server: three tools (find / get / render) + two
164
+ * resources (the catalog, the agent-setup prompt). Transport-agnostic — `cli.ts`
165
+ * wires it to stdio; a remote host could wire the same server to Streamable HTTP
166
+ * without changing anything here.
167
+ */
168
+ declare function createServer(): McpServer;
169
+ //#endregion
170
+ //#region src/catalog.d.ts
171
+ /**
172
+ * The committed catalog snapshot, loaded once. `catalog.generated.json` is
173
+ * produced by `scripts/gen.ts` from the docs registry and guard-tested by
174
+ * `catalog-sync.test.ts`, so this is always in step with the shipped library.
175
+ */
176
+ declare const catalog: Catalog;
177
+ declare const CHARTS: ChartEntry[];
178
+ /** The `@microcharts/react` version this snapshot was cut from (compat stamp). */
179
+ declare const LIBRARY_VERSION: string;
180
+ declare function getEntry(slug: string): ChartEntry | undefined;
181
+ /** Only stable charts have a shipped subpath — the wireable/renderable set. */
182
+ declare const STABLE_CHARTS: ChartEntry[];
183
+ //#endregion
184
+ //#region src/assets.generated.d.ts
185
+ declare const AGENT_SETUP: string;
186
+ //#endregion
187
+ //#region src/version.d.ts
188
+ declare const MCP_VERSION: string;
189
+ //#endregion
190
+ export { AGENT_SETUP, CHARTS, type Catalog, type ChartEntry, type ChartProp, type FindOptions, type FindResult, type GetResult, LIBRARY_VERSION, MCP_VERSION, type RenderFormat, type RenderInput, type RenderResult, STABLE_CHARTS, catalog, createServer, findChart, getChart, getEntry, renderChart };
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { a as CHARTS, c as catalog, i as findChart, l as getEntry, n as AGENT_SETUP, o as LIBRARY_VERSION, r as getChart, s as STABLE_CHARTS, t as renderChart } from "./render-core-CnQfk-v1.mjs";
2
+ import { n as MCP_VERSION, t as createServer } from "./server-C0ga2mbD.mjs";
3
+ export { AGENT_SETUP, CHARTS, LIBRARY_VERSION, MCP_VERSION, STABLE_CHARTS, catalog, createServer, findChart, getChart, getEntry, renderChart };