@slickfast/mcp 0.7.2 → 0.7.3

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.
Files changed (3) hide show
  1. package/README.md +58 -33
  2. package/dist/index.js +23 -3
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -1,37 +1,54 @@
1
- # SlickFast MCP server
1
+ # SlickFast charts & dashboards for AI agents
2
2
 
3
- Exposes the render-core engine as an MCP tool so an AI agent can generate charts.
3
+ SlickFast turns a small JSON spec into a polished, retina-quality chart **47 chart and
4
+ information-design types** (bar, line, pie, KPI, cards, funnel, gauge, heatmap, calendar,
5
+ gantt, waterfall…), plus **multiple charts tiled into a single dashboard image in one call**.
6
+ It runs as an [MCP](https://modelcontextprotocol.io) tool, so an AI agent hands it a spec and
7
+ gets back a finished PNG (or SVG). Everything renders **locally** — nothing leaves your machine.
4
8
 
5
- - **Tool:** `render_chart(spec)` → returns the chart as an SVG string. Spec contract
6
- is in `../../packages/render-core/SPEC.md` (also served as the `chart-spec` resource).
7
- - **Transport:** stdio (local). Streamable HTTP (remote/hosted, e.g. Railway) comes later.
8
-
9
- ## Run / test
10
- ```bash
11
- npm install
12
- node test-client.mjs # spawns the server, calls render_chart, checks the SVG
9
+ ```txt
10
+ render_chart({ type: "bar", data: { labels: ["Q1","Q2","Q3"], series: [{ values: [12,19,8] }] } })
11
+ a retina PNG, rendered on your machine
13
12
  ```
14
13
 
15
- ## Use it in Claude Desktop
16
- Add to `claude_desktop_config.json` (Settings → Developer → Edit Config):
17
- ```json
18
- {
19
- "mcpServers": {
20
- "slickfast": {
21
- "command": "node",
22
- "args": ["/Users/alexmacbook/SlickFast/platform/apps/mcp/server.mjs"]
23
- }
24
- }
25
- }
26
- ```
27
- Restart Claude Desktop, then ask it to "render a bar chart of …" — it calls `render_chart`.
14
+ ## Why it's built for agents
15
+
16
+ - **Deterministic — same spec, same bytes, forever.** No randomness, no timestamps, no
17
+ headless-browser drift. Outputs are **cacheable, testable, and reproducible**, with zero
18
+ flaky pixel diffs. Almost no charting tool can promise this — and it's exactly what a
19
+ tool-calling agent needs.
20
+ - **Never throws garbage at the model.** Empty data, a bad tile, a filtered-to-nothing series →
21
+ a clean, graceful frame, not a crash or a stack trace. Reliability is a feature when the
22
+ caller is an agent, not a human who can eyeball the error.
23
+ - **Fails loud on real mistakes.** An unknown palette or enum is *rejected* with a clear error
24
+ listing the valid options — so the agent fixes it immediately instead of silently shipping the
25
+ wrong-looking chart.
26
+ - **Good-looking by default.** A spec of just `{type, data}` renders a complete, well-designed
27
+ chart; fonts, colors, palettes, and size are optional overrides.
28
+ - **100% local & private.** Rendered and rasterized on your machine. Nothing is sent anywhere.
29
+
30
+ ## Tools
31
+
32
+ - **`render_chart(spec)`** → the chart as a PNG image (default) or SVG (`format: "svg"`). For a
33
+ dashboard, pass `type: "dashboard"` with `tiles: [{ chart, span }]` — each tile is a full spec
34
+ of any other type, composited into one image in a single render.
35
+ - **`describe_type(type)`** → the exact data shape, a minimal working spec, and per-type
36
+ gotchas. Call it first when you're unsure how to structure a type.
37
+
38
+ ## Install
39
+
40
+ Add to your MCP config and restart — it runs locally via `npx`, no clone or build needed:
28
41
 
29
- ## Use it in Claude Code
30
- Project-scoped config (`.mcp.json` at the workspace root):
31
42
  ```json
32
- { "mcpServers": { "slickfast": { "command": "node", "args": ["/Users/alexmacbook/SlickFast/platform/apps/mcp/server.mjs"] } } }
43
+ { "mcpServers": { "slickfast": { "command": "npx", "args": ["-y", "@slickfast/mcp"] } } }
33
44
  ```
34
- Restart the session; the `render_chart` tool becomes available.
45
+
46
+ - **Claude Desktop** — `claude_desktop_config.json` (Settings → Developer → Edit Config)
47
+ - **Claude Code** — project `.mcp.json` at the workspace root
48
+ - **claude.ai** — connector settings
49
+
50
+ Then ask it to *"render a bar chart of last quarter's revenue"* or *"build a dashboard with an
51
+ MRR tile, a signups funnel, and a usage heatmap."*
35
52
 
36
53
  ## Seeing your charts (why an image might not show inline)
37
54
 
@@ -64,14 +81,22 @@ embedding, posting to Slack/X/email, or getting a chart into a surface that can'
64
81
  local image (see the table above). The agent should **offer this only when you ask to share
65
82
  or post** — it never auto-inserts links. (The endpoint stays unadvertised during soft-launch.)
66
83
 
67
- ## Install via npm (published)
68
- ```json
69
- { "mcpServers": { "slickfast": { "command": "npx", "args": ["-y", "@slickfast/mcp"] } } }
70
- ```
71
- Restart Claude; everything runs locally on your machine — nothing leaves.
72
-
73
84
  ## License
85
+
74
86
  **AGPL-3.0-only.** Free to use, self-host, and embed under the AGPL's terms (your friends
75
87
  running it locally are completely unaffected). Building it into a **closed-source product
76
88
  or a hosted service**? That needs the AGPL'd source opened — or a **commercial license**
77
89
  from us instead. Reach out for commercial terms.
90
+
91
+ ## Developing locally
92
+
93
+ Clone the repo, then from the package directory:
94
+
95
+ ```bash
96
+ cd apps/mcp
97
+ npm install
98
+ node test-client.mjs # spawns the server, calls render_chart, checks the output
99
+ ```
100
+
101
+ To point an MCP client at a local checkout instead of the published package, use
102
+ `"command": "node", "args": ["<path-to-clone>/apps/mcp/server.mjs"]`.
package/dist/index.js CHANGED
@@ -786,7 +786,7 @@ function renderKpi(spec) {
786
786
  const fs = spec.fontSize ? Number(spec.fontSize) : Math.max(13, Math.round(13 * Math.sqrt(W * H) / 600));
787
787
  const font = resolveFont(spec);
788
788
  const watermark = spec.watermark !== false;
789
- const accent = resolveFlatPalette(spec.palette || "Clean Corporate", 1)[0];
789
+ const accent = spec.color || resolveFlatPalette(spec.palette || "Clean Corporate", 1)[0];
790
790
  const labelCol = txt(spec, isDark ? "#94a3b8" : "#64748b");
791
791
  const valueCol = txt(spec, isDark ? "#f1f5f9" : "#0f172a");
792
792
  const faint = isDark ? "#475569" : "#94a3b8";
@@ -2002,7 +2002,9 @@ function renderTable(spec) {
2002
2002
  const v = cells[ci];
2003
2003
  if (v === void 0 || v === null || v === "") continue;
2004
2004
  const num = ci > 0 && isNum(v);
2005
- const out = num ? fmt(Number(v)) : String(v);
2005
+ const nv = Number(v);
2006
+ const yearLike = num && Number.isInteger(nv) && nv >= 1900 && nv <= 2100;
2007
+ const out = num ? yearLike ? String(nv) : fmt(nv) : String(v);
2006
2008
  p.push(`<text x="${r(cellX(ci, num))}" y="${r(y + ROWH / 2 + 4)}" ${num ? 'text-anchor="end" ' : ""}font-size="${fs}"${wOpt(spec)} fill="${cellCol}">${esc(out)}</text>`);
2007
2009
  }
2008
2010
  });
@@ -3055,7 +3057,23 @@ var inputSchema = {
3055
3057
  scale: z.number().optional().describe("png pixel-density multiplier (default 2 = retina)"),
3056
3058
  outputPath: z.string().optional().describe('LOCAL save: write the rendered chart to this file on disk AND still return the inline image. PNG by default, or SVG if the path ends in ".svg". Accepts absolute, ~, or relative paths (parent dirs auto-created). Works on a local stdio install only \u2014 a hosted/remote server has no access to your disk.')
3057
3059
  };
3058
- var server = new McpServer({ name: "slickfast", version: "0.7.2" });
3060
+ var server = new McpServer({ name: "slickfast", version: "0.7.3" });
3061
+ var GOTCHAS = {
3062
+ gantt: ["start/end are timeline positions; the axis spans min(start)\u2026max(end), so a non-zero-based timeline (years, offset quarters) fills the plot correctly."],
3063
+ diverging: ["needs 2 series \u2014 series A is forced positive (up), series B negative (down), regardless of stored sign."],
3064
+ difference: ["needs 2 series; the gap between them is shaded."],
3065
+ kpi: ["sparkline is landscape-only (omit it in portrait).", "the accent bar follows the palette \u2014 pass `color` to fix it."],
3066
+ waffle: ["values are cell counts out of a 10\xD710 grid (100 total); a single part renders as one % gauge."],
3067
+ heatmap: ["`values` is a 2D matrix values[row][col]; `rows` and `columns` are the axis labels."],
3068
+ stacked: ["each ROW is a stack segment shared across every bar; segment color comes from the row, not the series."],
3069
+ stacked100: ["each bar sums to 100%; each row is a shared segment."],
3070
+ pieofpie: ['uses `pies:[\u2026]`, not `data`; each pie\u2019s first slice ("bridge") drills into the next.'],
3071
+ gauge: ["`value` is clamped to [min,max]; set min/max to your scale (default 0\u2013100)."],
3072
+ bullet: ["`bands` are qualitative thresholds on the measure scale; `target` draws the comparison marker."],
3073
+ calendar: ['`days` maps "YYYY-MM-DD" \u2192 value; weekday is computed deterministically (no clock/Date).'],
3074
+ dashboard: ["each tile.chart is a full spec of any other type; tiles keep their OWN scale \u2014 for a shared-scale comparison use one grouped/multi-series chart, not side-by-side tiles."],
3075
+ table: ["year-like integers (1900\u20132100) are shown without thousands separators; other numbers get them."]
3076
+ };
3059
3077
  function typeContract(t) {
3060
3078
  const meta = TYPES.find((x) => x.type === t);
3061
3079
  if (!meta) return null;
@@ -3067,6 +3085,8 @@ function typeContract(t) {
3067
3085
  needsData: meta.needsData,
3068
3086
  honorsToggles: TYPE_TOGGLES[t] || [],
3069
3087
  // which of showValues/showTotal/showPoints this type uses (others are ignored)
3088
+ gotchas: GOTCHAS[t] || [],
3089
+ // non-obvious per-type rules (else discovered by rendering twice)
3070
3090
  example: EXAMPLES[t] || null
3071
3091
  };
3072
3092
  }
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@slickfast/mcp",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "SlickFast — render 47 chart & info-design types (bar, line, pie, KPI, cards, funnel, matrix, gauge, calendar…) plus multi-chart dashboards tiled into one image, as SVG/PNG via MCP. Local and deterministic; nothing leaves your machine.",
5
+ "keywords": ["mcp", "model-context-protocol", "chart", "charts", "dashboard", "data-visualization", "svg", "png", "ai", "agent", "claude", "llm", "deterministic"],
5
6
  "license": "AGPL-3.0-only",
6
7
  "type": "module",
7
8
  "bin": { "slickfast-mcp": "dist/index.js" },