graphein-mcp 0.20.0 → 0.21.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.
@@ -516,7 +516,7 @@ function mcpToolMetadata(name) {
516
516
  }
517
517
 
518
518
  // src/create-server.ts
519
- var VERSION = "0.20.0";
519
+ var VERSION = "0.21.0";
520
520
  var SERVER_INSTRUCTIONS = `Graphein is an agent-first data-visualization library: you describe a chart as one JSON ChartSpec ({ type, data, encoding, ... }) and it renders. This server lets you build correct charts without prior knowledge of the API.
521
521
 
522
522
  Workflow:
@@ -719,4 +719,4 @@ export {
719
719
  VERSION,
720
720
  createServer
721
721
  };
722
- //# sourceMappingURL=chunk-7DJMHUCG.js.map
722
+ //# sourceMappingURL=chunk-DNKOUF77.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tabular.ts","../src/handlers.ts","../src/resources.ts","../src/create-server.ts","../src/toolMetadata.ts"],"sourcesContent":["/** A tidy row parsed from CSV/TSV text. */\nexport type TabularRow = Record<string, number | string>;\n\n/** Error thrown when CSV/TSV text is malformed. */\nexport class TabularParseError extends Error {\n /** Create a parse error with a human-readable message. */\n constructor(message: string) {\n super(message);\n this.name = 'TabularParseError';\n }\n}\n\ninterface Cell {\n value: string;\n}\n\nfunction detectDelimiter(text: string): ',' | '\\t' {\n let comma = 0;\n let tab = 0;\n let quoted = false;\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (ch === '\"') {\n if (quoted && text[i + 1] === '\"') {\n i++;\n } else {\n quoted = !quoted;\n }\n } else if (!quoted && (ch === '\\n' || ch === '\\r')) {\n break;\n } else if (!quoted && ch === ',') {\n comma++;\n } else if (!quoted && ch === '\\t') {\n tab++;\n }\n }\n\n return tab > comma ? '\\t' : ',';\n}\n\nfunction coerceLosslessNumber(value: string): number | string {\n const trimmed = value.trim();\n if (/^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$/.test(trimmed)) {\n const n = Number(trimmed);\n if (Number.isFinite(n)) return n;\n }\n return value;\n}\n\nfunction coerceColumns(records: Cell[][], headers: string[]): TabularRow[] {\n const columnsAsNumbers = headers.map((_, i) =>\n records.every((record) => typeof coerceLosslessNumber(record[i].value) === 'number'),\n );\n return records.map((record) => {\n const row: TabularRow = {};\n for (let i = 0; i < headers.length; i++) {\n row[headers[i]] = columnsAsNumbers[i] ? coerceLosslessNumber(record[i].value) : record[i].value;\n }\n return row;\n });\n}\n\nfunction parseRecords(text: string, delimiter: ',' | '\\t'): Cell[][] {\n const records: Cell[][] = [];\n let record: Cell[] = [];\n let value = '';\n let quoted = false;\n let afterQuote = false;\n\n const pushCell = () => {\n record.push({ value });\n value = '';\n afterQuote = false;\n };\n const pushRecord = () => {\n pushCell();\n records.push(record);\n record = [];\n };\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n\n if (quoted) {\n if (ch === '\"') {\n if (text[i + 1] === '\"') {\n value += '\"';\n i++;\n } else {\n quoted = false;\n afterQuote = true;\n }\n } else {\n value += ch;\n }\n continue;\n }\n\n if (afterQuote && ch !== delimiter && ch !== '\\n' && ch !== '\\r') {\n if (/\\s/.test(ch)) continue;\n throw new TabularParseError(`Unexpected character '${ch}' after closing quote.`);\n }\n\n if (ch === '\"') {\n if (value.length > 0) throw new TabularParseError('Unexpected quote in an unquoted field.');\n quoted = true;\n } else if (ch === delimiter) {\n pushCell();\n } else if (ch === '\\n') {\n pushRecord();\n } else if (ch === '\\r') {\n pushRecord();\n if (text[i + 1] === '\\n') i++;\n } else {\n value += ch;\n }\n }\n\n if (quoted) throw new TabularParseError('Unclosed quoted field.');\n if (value.length > 0 || record.length > 0 || text.endsWith(String(delimiter))) pushRecord();\n return records.filter((r) => r.some((cell) => cell.value.length > 0));\n}\n\n/**\n * Parse CSV or TSV text with a header row into tidy data rows. Handles quoted\n * fields, escaped quotes, embedded delimiters, and embedded newlines.\n */\nexport function parseTabularText(text: string): TabularRow[] {\n const trimmed = text.replace(/^\\uFEFF/, '');\n const delimiter = detectDelimiter(trimmed);\n const records = parseRecords(trimmed, delimiter);\n if (records.length === 0) return [];\n\n const headers = records[0].map((cell) => cell.value.trim());\n if (headers.some((h) => h.length === 0)) {\n throw new TabularParseError('CSV/TSV header row must not contain empty column names.');\n }\n if (new Set(headers).size !== headers.length) {\n throw new TabularParseError('CSV/TSV header row must not contain duplicate column names.');\n }\n\n const dataRecords = records.slice(1);\n for (const [rowIndex, record] of dataRecords.entries()) {\n if (record.length !== headers.length) {\n throw new TabularParseError(\n `Row ${rowIndex + 2} has ${record.length} cells, expected ${headers.length}.`,\n );\n }\n }\n return coerceColumns(dataRecords, headers);\n}\n\n/**\n * Return a copy of a spec-like value with any `data: \"csv/tsv...\"` properties\n * parsed into tidy rows. Non-spec values are returned unchanged.\n */\nexport function parseInlineData(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(parseInlineData);\n if (typeof value !== 'object' || value === null) return value;\n\n const out: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n out[key] = key === 'data' && typeof child === 'string' ? parseTabularText(child) : parseInlineData(child);\n }\n return out;\n}\n","/**\n * Pure tool handlers — the generate → validate → repair → render → critique loop\n * exposed as plain functions so they can be unit-tested without a transport. Each\n * returns MCP-shaped content (`text` and/or `image` blocks). `createServer` wires\n * these into the `McpServer`.\n *\n * The handlers wrap `graphein`'s self-validating / self-repairing / self-explaining\n * core (`validateSpec`, `repairSpec`, `summarize`) and `@graphein/node`'s headless\n * `renderChart`, so an agent gets the chart **plus** a vision-free critique in one\n * call — and a one-step repair when its spec is slightly wrong.\n */\nimport {\n validateSpec,\n draft,\n repairSpec,\n recommendChart,\n profileData,\n listChartTypes,\n summarize,\n type AnySpec,\n type QualityOptions,\n type RecommendOptions,\n type RepairOptions,\n type ValidationError,\n} from 'graphein';\nimport { NodeRenderError, renderChart, validateRenderImageOptions } from '@graphein/node';\nimport { parseInlineData, parseTabularText } from './tabular.js';\n\n/** A subset of MCP content blocks the handlers emit. */\nexport type McpContent =\n | { type: 'text'; text: string }\n | { type: 'image'; data: string; mimeType: string };\n\n/**\n * The shape every handler returns — assignable to the SDK's `CallToolResult`\n * (which is an open/passthrough type, hence the index signature).\n */\nexport interface ToolResult {\n content: McpContent[];\n structuredContent?: Record<string, unknown>;\n isError?: boolean;\n [key: string]: unknown;\n}\n\n/** Options accepted by {@link renderChartHandler}. */\nexport interface RenderArgs {\n spec: unknown;\n width?: number;\n height?: number;\n dpr?: number;\n /** Auto-apply safe repairs before rendering when the spec is invalid. Default true. */\n repair?: boolean;\n /** Independent structural/data repair policy; defaults to safe. */\n repairLevel?: RepairOptions['level'];\n /** Opt-in presentation-default improvement, capped at three whole-visual renders. */\n quality?: boolean | QualityOptions;\n}\n\n/** Options accepted by {@link critiqueChartHandler}. */\nexport type CritiqueArgs = RenderArgs;\n\nexport interface RecommendChartArgs {\n data: Record<string, unknown>[] | string;\n intent?: string;\n maxResults?: number;\n /** Layout guidance only; never filters/groups the supplied rows to fit. */\n targetSize?: RecommendOptions['targetSize'];\n}\n\n/** Options accepted by {@link repairChartHandler}. */\nexport interface RepairChartArgs {\n spec: unknown;\n /** Repair level: safe fixes by default, or data-aware inference from inline rows. */\n level?: RepairOptions['level'];\n}\n\nfunction text(value: string): McpContent {\n return { type: 'text', text: value };\n}\n\nfunction json(value: unknown): McpContent {\n return text(JSON.stringify(value, null, 2));\n}\n\nfunction specType(spec: unknown): string {\n return typeof spec === 'object' && spec !== null && 'type' in spec\n ? String((spec as { type: unknown }).type)\n : '(missing)';\n}\n\nfunction isRecommendIntent(value: string | undefined): value is RecommendOptions['intent'] {\n return (\n value === undefined ||\n value === 'trend' ||\n value === 'comparison' ||\n value === 'distribution' ||\n value === 'relationship' ||\n value === 'composition'\n );\n}\n\nfunction parseErrorResult(e: unknown, quality?: RenderArgs['quality']): ToolResult {\n const payload = {\n ok: false,\n stage: 'parse-data',\n message: e instanceof Error ? e.message : String(e),\n ...(quality ? {\n rendered: false,\n quality: draft(undefined, { repair: false, quality }).quality,\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n}\n\nfunction optionErrorResult(e: unknown, quality?: RenderArgs['quality']): ToolResult {\n const payload = {\n ok: false,\n rendered: false,\n stage: 'options',\n message: e instanceof Error ? e.message : String(e),\n ...(quality ? {\n quality: draft(undefined, { repair: false, quality }).quality,\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n}\n\nfunction specWithParsedData(spec: unknown): unknown {\n return parseInlineData(spec);\n}\n\nfunction rowsWithParsedData(data: RecommendChartArgs['data']): Record<string, unknown>[] {\n return (typeof data === 'string' ? parseTabularText(data) : data) as Record<string, unknown>[];\n}\n\n/** Slim a validation error for an agent payload (drops nothing useful). */\nfunction tidyError(e: ValidationError) {\n const out: Record<string, unknown> = { path: e.path, message: e.message };\n if (e.rule) out.rule = e.rule;\n if (e.severity) out.severity = e.severity;\n if (e.fix) out.fix = e.fix;\n if (e.suggestion) out.suggestion = e.suggestion;\n if (e.evidence) out.evidence = e.evidence;\n if (e.requiresDecision !== undefined) out.requiresDecision = e.requiresDecision;\n return out;\n}\n\nfunction authoringMetadata(spec: AnySpec) {\n const types = listChartTypes();\n const capabilities = (type: AnySpec['type']) => types.find((t) => t.type === type)?.capabilities;\n if (spec.type !== 'dashboard') {\n return { profile: profileData(spec.data ?? []), capabilities: capabilities(spec.type) };\n }\n return {\n ...(spec.data ? { profile: profileData(spec.data) } : {}),\n capabilities: capabilities(spec.type),\n views: spec.views.map((view) => ({\n id: view.id,\n capabilities: capabilities(view.spec.type),\n ...(view.spec.data\n ? { profile: profileData(view.spec.data) }\n : { inheritsSharedData: true }),\n })),\n };\n}\n\n/**\n * **The flagship.** Validate a spec, auto-repair it if it's safely fixable, render\n * it to a PNG headless, and return the image alongside a machine-readable critique\n * (the render report + lint warnings + any repairs applied). When the spec can't be\n * made valid, returns the structured errors and JSON-Patch fixes instead of an image\n * so the agent corrects in one step rather than regenerating.\n */\nexport function renderChartHandler(args: RenderArgs): ToolResult {\n return renderOrCritique(args, true);\n}\n\n/**\n * Validate, optionally repair, render, and return only the machine-readable\n * render report + summary. This avoids sending a base64 PNG when an agent only\n * needs diagnostics.\n */\nexport function critiqueChartHandler(args: CritiqueArgs): ToolResult {\n return renderOrCritique(args, false);\n}\n\nfunction renderOrCritique(args: RenderArgs, includeImage: boolean): ToolResult {\n const { spec, width, height, dpr, repair = true, repairLevel, quality } = args;\n try {\n validateRenderImageOptions({ width, height, dpr });\n } catch (e) {\n return optionErrorResult(e, quality);\n }\n let working: unknown;\n try {\n working = specWithParsedData(spec);\n } catch (e) {\n return parseErrorResult(e, quality);\n }\n const prepared = draft(working, { repair, repairLevel, quality });\n const type = specType(prepared.spec);\n if (!prepared.valid) {\n const payload = {\n ok: false, rendered: false, stage: 'validate', type,\n errors: prepared.errors.map(tidyError),\n lint: prepared.warnings.map(tidyError),\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? { effectiveSpec: prepared.spec, quality: prepared.quality } : {}),\n hint: `Apply each error.fix JSON Patch (or the repair_chart tool), then call ${includeImage ? 'render_chart' : 'critique_chart'} again. See the graphein://agent-guide and graphein://schema resources.`,\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n }\n\n try {\n const rendered = renderChart(prepared.spec as AnySpec, { width, height, dpr, quality });\n const { report } = rendered;\n const payload = {\n ok: report.ok, rendered: true, type,\n pixelSize: { width: rendered.width, height: rendered.height },\n summary: report.summary,\n ...(includeImage ? {\n marks: report.markCount, series: report.seriesCount, colors: report.colorCount,\n diagnostics: report.diagnostics,\n } : {}),\n report,\n lint: validateSpec(rendered.spec).warnings.map(tidyError),\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? {\n effectiveSpec: rendered.spec, quality: rendered.quality,\n authoring: authoringMetadata(rendered.spec),\n } : {}),\n };\n return {\n isError: false,\n content: [\n ...(includeImage ? [{ type: 'image' as const, data: rendered.png.toString('base64'), mimeType: 'image/png' }] : []),\n json(payload),\n ],\n structuredContent: payload,\n };\n } catch (e) {\n const failed = e instanceof NodeRenderError ? e.result : undefined;\n const payload = {\n ok: false, rendered: false, stage: 'render', type,\n message: e instanceof Error ? e.message : String(e),\n summary: prepared.summary,\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? {\n effectiveSpec: failed?.spec ?? prepared.spec,\n quality: failed?.quality ?? { ...prepared.quality, stopReason: 'render-failed' },\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n }\n}\n\n/**\n * Validate a spec without rendering — fast structural + best-practice feedback.\n * Returns errors (each with a JSON-Patch `fix` when unambiguous and \"did you mean\"\n * suggestions) and lint `warnings`.\n */\nexport function validateChartHandler(args: { spec: unknown }): ToolResult {\n let spec: unknown;\n try {\n spec = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const result = validateSpec(spec);\n return {\n isError: false,\n content: [\n json({\n valid: result.valid,\n type: specType(spec),\n errors: result.errors.map(tidyError),\n warnings: result.warnings.map(tidyError),\n }),\n ],\n };\n}\n\n/** Recommend ready-to-render ChartSpecs from tidy rows and an optional intent. */\nexport function recommendChartHandler(args: RecommendChartArgs): ToolResult {\n if (!isRecommendIntent(args.intent)) {\n return {\n isError: true,\n content: [\n json({\n ok: false,\n message: 'Unsupported intent. Expected trend, comparison, distribution, relationship, or composition.',\n }),\n ],\n };\n }\n let data: Record<string, unknown>[];\n try {\n data = rowsWithParsedData(args.data);\n } catch (e) {\n return parseErrorResult(e);\n }\n const recommendations = recommendChart(data, {\n intent: args.intent, maxResults: args.maxResults, targetSize: args.targetSize, detailed: true,\n });\n const payload = { ok: true, ...recommendations };\n return { isError: false, content: [json(payload)], structuredContent: payload };\n}\n\n/**\n * List every supported chart family with its purpose, required channels, and a\n * minimal runnable starter spec.\n */\nexport function listChartTypesHandler(): ToolResult {\n const payload = { ok: true, chartTypes: listChartTypes() };\n return { isError: false, content: [json(payload)], structuredContent: payload };\n}\n\n/**\n * Apply every safe, unambiguous repair Graphein proposes and return the corrected\n * spec, the JSON Patch operations applied, and whether it is now valid.\n */\nexport function repairChartHandler(args: RepairChartArgs): ToolResult {\n let input: unknown;\n try {\n input = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const { spec, applied, appliedDetails, remaining } = repairSpec(input, { level: args.level ?? 'safe' });\n return {\n isError: false,\n content: [\n json({\n valid: remaining.length === 0,\n level: args.level ?? 'safe',\n applied,\n appliedDetails,\n remaining: remaining.map(tidyError),\n spec,\n }),\n ],\n };\n}\n\n/**\n * Return a deterministic, plain-English summary of what the chart's data shows —\n * doubles as alt-text, needs no LLM.\n */\nexport function summarizeChartHandler(args: { spec: unknown }): ToolResult {\n let spec: unknown;\n try {\n spec = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const result = validateSpec(spec);\n if (!result.valid) {\n return {\n isError: true,\n content: [\n json({\n summary: null,\n reason: 'Spec is invalid; fix it first (validate_chart / repair_chart).',\n errors: result.errors.map(tidyError),\n }),\n ],\n };\n }\n const validSpec = spec as AnySpec;\n const summary = validSpec.type === 'dashboard' ? undefined : summarize(validSpec);\n return {\n isError: false,\n content: [\n text(summary || `(No narrative summary is available for a '${specType(args.spec)}' chart.)`),\n ],\n };\n}\n","/**\n * The agent-facing knowledge Graphein serves as MCP **resources** — the schema\n * and the prose guides — so a model that has never seen Graphein's API can read\n * the contract at runtime instead of relying on training data. This is the core\n * of the MCP server's \"neutralize the training-data gap\" purpose.\n *\n * The files live in `../resources/` (committed copies of the repo's `docs/`, kept\n * in sync by `scripts/sync-resources.mjs`). They are read lazily and cached so the\n * server pays nothing until an agent actually asks for one.\n */\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\n/** Metadata describing one served resource. */\nexport interface GrapheinResource {\n /** Short registration name. */\n name: string;\n /** Stable `graphein://…` URI an agent reads. */\n uri: string;\n /** Human title. */\n title: string;\n /** What the resource is and when to read it. */\n description: string;\n /** IANA media type. */\n mimeType: string;\n /** File under `resources/`. */\n file: string;\n}\n\n/** Every resource the server exposes, in the order they should be advertised. */\nexport const RESOURCES: GrapheinResource[] = [\n {\n name: 'schema',\n uri: 'graphein://schema',\n title: 'Graphein ChartSpec JSON Schema',\n description:\n 'The machine-readable JSON Schema for every Graphein ChartSpec and DashboardSpec field — chart types, channels, transforms, annotations, and required properties. Generate or check a spec against this.',\n mimeType: 'application/json',\n file: 'chart-spec.schema.json',\n },\n {\n name: 'agent-guide',\n uri: 'graphein://agent-guide',\n title: 'Graphein Agent Guide',\n description:\n 'A task-oriented guide for producing correct Graphein charts: the one-rule workflow, choosing a chart type, encodings, transforms, the validate → repair → render → critique loop, and worked recipes. Read this first.',\n mimeType: 'text/markdown',\n file: 'agent-guide.md',\n },\n {\n name: 'spec-reference',\n uri: 'graphein://spec-reference',\n title: 'Graphein Spec Reference',\n description:\n 'The exhaustive field-by-field reference for every chart type, channel, transform, annotation, and modifier. Consult this for the precise shape of a specific field.',\n mimeType: 'text/markdown',\n file: 'spec-reference.md',\n },\n];\n\nconst cache = new Map<string, string>();\nconst allowedResourceFiles = new Set(RESOURCES.map((r) => r.file));\n\n/**\n * Read a bundled resource file's text, cached. Resolved relative to this module\n * so it works both from `dist/` (published) and `src/` (tests) — the committed\n * `resources/` dir always sits one level up from either.\n */\nexport function readResourceFile(file: string): string {\n if (!allowedResourceFiles.has(file)) {\n throw new Error(`Unknown Graphein MCP resource \"${file}\".`);\n }\n const hit = cache.get(file);\n if (hit !== undefined) return hit;\n const url = new URL(`../resources/${file}`, import.meta.url);\n const text = readFileSync(fileURLToPath(url), 'utf8');\n cache.set(file, text);\n return text;\n}\n\n/** Look up a resource by its `graphein://…` URI. */\nexport function resourceByUri(uri: string): GrapheinResource | undefined {\n return RESOURCES.find((r) => r.uri === uri);\n}\n","/**\n * `createServer()` — builds the Graphein MCP server: the generate → validate →\n * repair → render → critique loop as four tools, the schema + guides as resources,\n * and a `create_chart` prompt that teaches the workflow. Split from the stdio\n * entry point (`server.ts`) so it can be driven over any transport — including the\n * in-memory transport in tests.\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { RENDER_LIMITS } from '@graphein/node';\nimport { z } from 'zod';\nimport {\n critiqueChartHandler,\n listChartTypesHandler,\n renderChartHandler,\n validateChartHandler,\n repairChartHandler,\n recommendChartHandler,\n summarizeChartHandler,\n} from './handlers.js';\nimport { RESOURCES, readResourceFile } from './resources.js';\nimport { mcpToolMetadata } from './toolMetadata.js';\n\n/** Package version, surfaced as the MCP server version. */\nexport const VERSION = '0.20.0';\n\nconst SERVER_INSTRUCTIONS = `Graphein is an agent-first data-visualization library: you describe a chart as one JSON ChartSpec ({ type, data, encoding, ... }) and it renders. This server lets you build correct charts without prior knowledge of the API.\n\nWorkflow:\n1. Call list_chart_types to see every supported chart type with required channels, field roles, aggregation behavior, cardinality caveats, and starter specs; read graphein://agent-guide (and graphein://schema for exact fields) only when you need deeper detail.\n2. Shape data as tidy rows — one row per observation, one column per variable. Tools that accept rows also accept CSV/TSV text with a header row.\n3. Use recommend_chart when you want ranked specs from data, or start from a list_chart_types starter. Inspect profile, findings, and status: needs-decision/no-candidate are not permission to guess aggregation, date roles, missing values, or geometry.\n4. Emit a ChartSpec and call critique_chart for report-only diagnostics, or render_chart when you need the PNG plus critique. Both validate, auto-repair safe mistakes, render headlessly once by default, and return lint/report feedback. Opt in with quality:true for presentation-default improvements within three TOTAL whole-visual renders, including restoration. Read effectiveSpec, quality history and unresolved diagnostics; the loop never changes data or explicit settings.\n5. If a spec is invalid, validate_chart, critique_chart, and render_chart return structured errors with JSON-Patch fixes. Apply them or call repair_chart; use repair_chart level \"data\" to infer missing encodings or close field-name typos from the spec's own data.\nUse summarize_chart for deterministic alt-text. Every type rasterizes headlessly, including kpi, table, matrix, slicers and dashboard (static canvas snapshots).`;\n\n/** A permissive object schema for a Graphein spec — validateSpec does the real checking. */\nconst specSchema = z\n .record(z.string(), z.unknown())\n .describe(\n 'A Graphein ChartSpec or DashboardSpec object, e.g. { \"type\": \"line\", \"data\": [...], \"encoding\": {...} }. Any data property may be tidy rows or CSV/TSV text with a header row. See the graphein://schema and graphein://agent-guide resources.',\n );\n\nconst dataRowsSchema = z.union([\n z.array(z.record(z.string(), z.any())),\n z.string().describe('CSV or TSV text with a header row; quoted delimiters, quotes, and newlines are supported.'),\n]);\n\nconst intentSchema = z\n .enum(['trend', 'comparison', 'distribution', 'relationship', 'composition'])\n .optional()\n .describe(\n 'Optional analytical intent used to rank recommendations: trend, comparison, distribution, relationship, or composition.',\n );\n\nconst qualitySchema = z.union([\n z.boolean(),\n z.object({\n maxPasses: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional()\n .describe('Total whole-visual render ceiling including initial and rollback passes (default 3).'),\n }).strict(),\n]).optional().describe(\n 'Opt in to bounded presentation-default improvement. Default false: one render. Never alters data, encodings, explicit palettes/domains, or other caller settings. Returns effectiveSpec and quality history. Mutable targets reserve a rollback pass.',\n);\n\nconst repairLevelSchema = z.enum(['safe', 'data']).optional()\n .describe('Independent repair policy: safe (default), or explicitly opt in to data-aware field/encoding inference.');\nconst widthSchema = z.number().min(RENDER_LIMITS.minWidth).max(RENDER_LIMITS.maxWidth).optional()\n .describe(`Logical width in CSS px (default 800; ${RENDER_LIMITS.minWidth}-${RENDER_LIMITS.maxWidth}).`);\nconst heightSchema = z.number().min(RENDER_LIMITS.minHeight).max(RENDER_LIMITS.maxHeight).optional()\n .describe(`Logical height in CSS px (default 500; ${RENDER_LIMITS.minHeight}-${RENDER_LIMITS.maxHeight}).`);\nconst dprSchema = z.number().min(RENDER_LIMITS.minDpr).max(RENDER_LIMITS.maxDpr).optional()\n .describe(`Device pixel ratio for crisp output (default 2; ${RENDER_LIMITS.minDpr}-${RENDER_LIMITS.maxDpr}; total raster pixels capped at ${RENDER_LIMITS.maxPixels.toLocaleString('en-US')}).`);\n\nconst toolOptions = (name: string): { title: string; description: string } => {\n const { title, description } = mcpToolMetadata(name);\n return { title, description };\n};\n\n/**\n * Build a fully-configured Graphein MCP server. The caller connects it to a\n * transport (`server.connect(transport)`).\n */\nexport function createServer(): McpServer {\n const server = new McpServer(\n { name: 'graphein-mcp', version: VERSION },\n { instructions: SERVER_INSTRUCTIONS },\n );\n registerTools(server);\n registerResources(server);\n registerCreateChartPrompt(server);\n return server;\n}\n\nfunction registerTools(server: McpServer): void {\n // --- Tools: the runtime loop -------------------------------------------------\n registerRenderTools(server);\n registerSpecTools(server);\n}\n\nfunction registerRenderTools(server: McpServer): void {\n server.registerTool(\n 'render_chart',\n {\n ...toolOptions('render_chart'),\n inputSchema: {\n spec: specSchema,\n width: widthSchema,\n height: heightSchema,\n dpr: dprSchema,\n repair: z\n .boolean()\n .optional()\n .describe('Auto-apply safe repairs before rendering when the spec is invalid (default true).'),\n repairLevel: repairLevelSchema,\n quality: qualitySchema,\n },\n },\n async (args) => renderChartHandler(args),\n );\n\n server.registerTool(\n 'critique_chart',\n {\n ...toolOptions('critique_chart'),\n inputSchema: {\n spec: specSchema,\n width: widthSchema,\n height: heightSchema,\n dpr: dprSchema,\n repair: z\n .boolean()\n .optional()\n .describe('Auto-apply safe repairs before rendering when the spec is invalid (default true).'),\n repairLevel: repairLevelSchema,\n quality: qualitySchema,\n },\n },\n async (args) => critiqueChartHandler(args),\n );\n}\n\nfunction registerSpecTools(server: McpServer): void {\n server.registerTool(\n 'validate_chart',\n {\n ...toolOptions('validate_chart'),\n inputSchema: { spec: specSchema },\n },\n async (args) => validateChartHandler(args),\n );\n\n server.registerTool(\n 'recommend_chart',\n {\n ...toolOptions('recommend_chart'),\n inputSchema: {\n data: dataRowsSchema,\n intent: intentSchema,\n maxResults: z.number().int().positive().optional(),\n targetSize: z.object({\n width: z.number().positive(),\n height: z.number().positive(),\n }).optional().describe('Optional target CSS-pixel size for layout guidance only; does not filter or group data.'),\n },\n },\n async (args) => recommendChartHandler(args),\n );\n\n server.registerTool(\n 'repair_chart',\n {\n ...toolOptions('repair_chart'),\n inputSchema: {\n spec: specSchema,\n level: z\n .enum(['safe', 'data'])\n .optional()\n .describe('Repair aggressiveness. \"safe\" is default; \"data\" also infers from the spec data.'),\n },\n },\n async (args) => repairChartHandler(args),\n );\n\n server.registerTool(\n 'list_chart_types',\n {\n ...toolOptions('list_chart_types'),\n inputSchema: {},\n },\n async () => listChartTypesHandler(),\n );\n\n server.registerTool(\n 'summarize_chart',\n {\n ...toolOptions('summarize_chart'),\n inputSchema: { spec: specSchema },\n },\n async (args) => summarizeChartHandler(args),\n );\n}\n\nfunction registerResources(server: McpServer): void {\n\n // --- Resources: deliver the API knowledge at runtime -------------------------\n for (const r of RESOURCES) {\n server.registerResource(\n r.name,\n r.uri,\n { title: r.title, description: r.description, mimeType: r.mimeType },\n async (uri) => ({\n contents: [{ uri: uri.href, mimeType: r.mimeType, text: readResourceFile(r.file) }],\n }),\n );\n }\n}\n\nfunction registerCreateChartPrompt(server: McpServer): void {\n\n // --- Prompt: teach the workflow ---------------------------------------------\n server.registerPrompt(\n 'create_chart',\n {\n title: 'Create a Graphein chart',\n description:\n 'Scaffold the workflow for building a validated Graphein chart from a goal (and optional data).',\n argsSchema: {\n goal: z.string().describe('What the chart should show, e.g. \"monthly active users over the last year\".'),\n data: z\n .string()\n .optional()\n .describe('Optional: the data as a JSON array, or a description of the columns available.'),\n },\n },\n ({ goal, data }) => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Build a Graphein chart for this goal:\\n\\n${goal}\\n${\n data ? `\\nData:\\n${data}\\n` : ''\n }\\nSteps:\\n1. Call list_chart_types for available chart families and starter specs; read graphein://agent-guide or graphein://schema only for deeper details.\\n2. Shape the data as tidy rows — one row per observation, one column per variable. CSV/TSV text with a header row is accepted anywhere data rows are accepted.\\n3. Choose a chart type (or call recommend_chart) and write a single ChartSpec ({ type, data, encoding, title }).\\n4. Call critique_chart for report-only feedback or render_chart when you need the PNG too. Read the returned render report + lint to confirm it looks right.\\n5. If it reports errors, apply each error.fix patch (or call repair_chart, using level \"data\" when field/encoding inference from data is useful) and render again — do not regenerate from scratch.`,\n },\n },\n ],\n }),\n );\n}\n","export interface McpToolMetadata {\n readonly name: string;\n readonly title: string;\n readonly description: string;\n}\n\nexport const MCP_TOOL_METADATA = Object.freeze([\n {\n name: 'render_chart',\n title: 'Render a Graphein chart',\n description: 'The one-call loop: validate a ChartSpec, auto-repair safe mistakes, render it to a PNG, and return the image plus a vision-free critique (render report, lint warnings, repairs applied). If the spec cannot be made valid, returns structured errors with JSON-Patch fixes instead of an image. Every type rasterizes headlessly — kpi, table, matrix, slicers and dashboard render static canvas snapshots.',\n },\n {\n name: 'critique_chart',\n title: 'Critique a Graphein chart without an image',\n description: 'Validate a ChartSpec, auto-repair safe mistakes, render it headlessly, and return only the RenderReport, deterministic summary, lint warnings, and repairs applied — no base64 PNG. Use this when you need diagnostics but not an image.',\n },\n {\n name: 'validate_chart',\n title: 'Validate a Graphein chart spec',\n description: 'Validate a ChartSpec without rendering. Returns structural errors (each with a JSON-Patch fix when unambiguous, plus did-you-mean suggestions) and best-practice lint warnings. Fast feedback before rendering.',\n },\n {\n name: 'recommend_chart',\n title: 'Recommend Graphein chart specs',\n description: 'Profile tidy rows and return ranked ChartSpecs with rationale, profile evidence, alternatives, and explicit needs-decision/no-candidate findings. Use this before guessing a chart type or encoding; no supplied data is changed.',\n },\n {\n name: 'repair_chart',\n title: 'Repair a Graphein chart spec',\n description: 'Apply Graphein repairs and return the corrected spec, JSON Patch ops, per-patch rationales, and whether it is now valid. The default safe level applies validator-provided fixes; level \"data\" may infer missing encodings and field-name typo fixes from the spec\\'s own data.',\n },\n {\n name: 'list_chart_types',\n title: 'List Graphein chart types',\n description: 'Return every supported chart type with purpose, required channels/properties, field roles, aggregation semantics, cardinality guidance, supported features, and a minimal runnable starter. Use this before reading the full schema.',\n },\n {\n name: 'summarize_chart',\n title: 'Summarize a Graphein chart',\n description: 'Return a deterministic, plain-English description of what the chart\\'s data shows (e.g. \"Users grew 46% over six months, peaking in June\"). Doubles as alt-text; needs no LLM.',\n },\n] satisfies readonly McpToolMetadata[]);\n\nexport function mcpToolMetadata(name: string): McpToolMetadata {\n const tool = MCP_TOOL_METADATA.find((item) => item.name === name);\n if (!tool) throw new Error(`Unknown Graphein MCP tool: ${name}`);\n return tool;\n}\n"],"mappings":"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","names":["text","text"]}
1
+ {"version":3,"sources":["../src/tabular.ts","../src/handlers.ts","../src/resources.ts","../src/create-server.ts","../src/toolMetadata.ts"],"sourcesContent":["/** A tidy row parsed from CSV/TSV text. */\nexport type TabularRow = Record<string, number | string>;\n\n/** Error thrown when CSV/TSV text is malformed. */\nexport class TabularParseError extends Error {\n /** Create a parse error with a human-readable message. */\n constructor(message: string) {\n super(message);\n this.name = 'TabularParseError';\n }\n}\n\ninterface Cell {\n value: string;\n}\n\nfunction detectDelimiter(text: string): ',' | '\\t' {\n let comma = 0;\n let tab = 0;\n let quoted = false;\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (ch === '\"') {\n if (quoted && text[i + 1] === '\"') {\n i++;\n } else {\n quoted = !quoted;\n }\n } else if (!quoted && (ch === '\\n' || ch === '\\r')) {\n break;\n } else if (!quoted && ch === ',') {\n comma++;\n } else if (!quoted && ch === '\\t') {\n tab++;\n }\n }\n\n return tab > comma ? '\\t' : ',';\n}\n\nfunction coerceLosslessNumber(value: string): number | string {\n const trimmed = value.trim();\n if (/^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$/.test(trimmed)) {\n const n = Number(trimmed);\n if (Number.isFinite(n)) return n;\n }\n return value;\n}\n\nfunction coerceColumns(records: Cell[][], headers: string[]): TabularRow[] {\n const columnsAsNumbers = headers.map((_, i) =>\n records.every((record) => typeof coerceLosslessNumber(record[i].value) === 'number'),\n );\n return records.map((record) => {\n const row: TabularRow = {};\n for (let i = 0; i < headers.length; i++) {\n row[headers[i]] = columnsAsNumbers[i] ? coerceLosslessNumber(record[i].value) : record[i].value;\n }\n return row;\n });\n}\n\nfunction parseRecords(text: string, delimiter: ',' | '\\t'): Cell[][] {\n const records: Cell[][] = [];\n let record: Cell[] = [];\n let value = '';\n let quoted = false;\n let afterQuote = false;\n\n const pushCell = () => {\n record.push({ value });\n value = '';\n afterQuote = false;\n };\n const pushRecord = () => {\n pushCell();\n records.push(record);\n record = [];\n };\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n\n if (quoted) {\n if (ch === '\"') {\n if (text[i + 1] === '\"') {\n value += '\"';\n i++;\n } else {\n quoted = false;\n afterQuote = true;\n }\n } else {\n value += ch;\n }\n continue;\n }\n\n if (afterQuote && ch !== delimiter && ch !== '\\n' && ch !== '\\r') {\n if (/\\s/.test(ch)) continue;\n throw new TabularParseError(`Unexpected character '${ch}' after closing quote.`);\n }\n\n if (ch === '\"') {\n if (value.length > 0) throw new TabularParseError('Unexpected quote in an unquoted field.');\n quoted = true;\n } else if (ch === delimiter) {\n pushCell();\n } else if (ch === '\\n') {\n pushRecord();\n } else if (ch === '\\r') {\n pushRecord();\n if (text[i + 1] === '\\n') i++;\n } else {\n value += ch;\n }\n }\n\n if (quoted) throw new TabularParseError('Unclosed quoted field.');\n if (value.length > 0 || record.length > 0 || text.endsWith(String(delimiter))) pushRecord();\n return records.filter((r) => r.some((cell) => cell.value.length > 0));\n}\n\n/**\n * Parse CSV or TSV text with a header row into tidy data rows. Handles quoted\n * fields, escaped quotes, embedded delimiters, and embedded newlines.\n */\nexport function parseTabularText(text: string): TabularRow[] {\n const trimmed = text.replace(/^\\uFEFF/, '');\n const delimiter = detectDelimiter(trimmed);\n const records = parseRecords(trimmed, delimiter);\n if (records.length === 0) return [];\n\n const headers = records[0].map((cell) => cell.value.trim());\n if (headers.some((h) => h.length === 0)) {\n throw new TabularParseError('CSV/TSV header row must not contain empty column names.');\n }\n if (new Set(headers).size !== headers.length) {\n throw new TabularParseError('CSV/TSV header row must not contain duplicate column names.');\n }\n\n const dataRecords = records.slice(1);\n for (const [rowIndex, record] of dataRecords.entries()) {\n if (record.length !== headers.length) {\n throw new TabularParseError(\n `Row ${rowIndex + 2} has ${record.length} cells, expected ${headers.length}.`,\n );\n }\n }\n return coerceColumns(dataRecords, headers);\n}\n\n/**\n * Return a copy of a spec-like value with any `data: \"csv/tsv...\"` properties\n * parsed into tidy rows. Non-spec values are returned unchanged.\n */\nexport function parseInlineData(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(parseInlineData);\n if (typeof value !== 'object' || value === null) return value;\n\n const out: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n out[key] = key === 'data' && typeof child === 'string' ? parseTabularText(child) : parseInlineData(child);\n }\n return out;\n}\n","/**\n * Pure tool handlers — the generate → validate → repair → render → critique loop\n * exposed as plain functions so they can be unit-tested without a transport. Each\n * returns MCP-shaped content (`text` and/or `image` blocks). `createServer` wires\n * these into the `McpServer`.\n *\n * The handlers wrap `graphein`'s self-validating / self-repairing / self-explaining\n * core (`validateSpec`, `repairSpec`, `summarize`) and `@graphein/node`'s headless\n * `renderChart`, so an agent gets the chart **plus** a vision-free critique in one\n * call — and a one-step repair when its spec is slightly wrong.\n */\nimport {\n validateSpec,\n draft,\n repairSpec,\n recommendChart,\n profileData,\n listChartTypes,\n summarize,\n type AnySpec,\n type QualityOptions,\n type RecommendOptions,\n type RepairOptions,\n type ValidationError,\n} from 'graphein';\nimport { NodeRenderError, renderChart, validateRenderImageOptions } from '@graphein/node';\nimport { parseInlineData, parseTabularText } from './tabular.js';\n\n/** A subset of MCP content blocks the handlers emit. */\nexport type McpContent =\n | { type: 'text'; text: string }\n | { type: 'image'; data: string; mimeType: string };\n\n/**\n * The shape every handler returns — assignable to the SDK's `CallToolResult`\n * (which is an open/passthrough type, hence the index signature).\n */\nexport interface ToolResult {\n content: McpContent[];\n structuredContent?: Record<string, unknown>;\n isError?: boolean;\n [key: string]: unknown;\n}\n\n/** Options accepted by {@link renderChartHandler}. */\nexport interface RenderArgs {\n spec: unknown;\n width?: number;\n height?: number;\n dpr?: number;\n /** Auto-apply safe repairs before rendering when the spec is invalid. Default true. */\n repair?: boolean;\n /** Independent structural/data repair policy; defaults to safe. */\n repairLevel?: RepairOptions['level'];\n /** Opt-in presentation-default improvement, capped at three whole-visual renders. */\n quality?: boolean | QualityOptions;\n}\n\n/** Options accepted by {@link critiqueChartHandler}. */\nexport type CritiqueArgs = RenderArgs;\n\nexport interface RecommendChartArgs {\n data: Record<string, unknown>[] | string;\n intent?: string;\n maxResults?: number;\n /** Layout guidance only; never filters/groups the supplied rows to fit. */\n targetSize?: RecommendOptions['targetSize'];\n}\n\n/** Options accepted by {@link repairChartHandler}. */\nexport interface RepairChartArgs {\n spec: unknown;\n /** Repair level: safe fixes by default, or data-aware inference from inline rows. */\n level?: RepairOptions['level'];\n}\n\nfunction text(value: string): McpContent {\n return { type: 'text', text: value };\n}\n\nfunction json(value: unknown): McpContent {\n return text(JSON.stringify(value, null, 2));\n}\n\nfunction specType(spec: unknown): string {\n return typeof spec === 'object' && spec !== null && 'type' in spec\n ? String((spec as { type: unknown }).type)\n : '(missing)';\n}\n\nfunction isRecommendIntent(value: string | undefined): value is RecommendOptions['intent'] {\n return (\n value === undefined ||\n value === 'trend' ||\n value === 'comparison' ||\n value === 'distribution' ||\n value === 'relationship' ||\n value === 'composition'\n );\n}\n\nfunction parseErrorResult(e: unknown, quality?: RenderArgs['quality']): ToolResult {\n const payload = {\n ok: false,\n stage: 'parse-data',\n message: e instanceof Error ? e.message : String(e),\n ...(quality ? {\n rendered: false,\n quality: draft(undefined, { repair: false, quality }).quality,\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n}\n\nfunction optionErrorResult(e: unknown, quality?: RenderArgs['quality']): ToolResult {\n const payload = {\n ok: false,\n rendered: false,\n stage: 'options',\n message: e instanceof Error ? e.message : String(e),\n ...(quality ? {\n quality: draft(undefined, { repair: false, quality }).quality,\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n}\n\nfunction specWithParsedData(spec: unknown): unknown {\n return parseInlineData(spec);\n}\n\nfunction rowsWithParsedData(data: RecommendChartArgs['data']): Record<string, unknown>[] {\n return (typeof data === 'string' ? parseTabularText(data) : data) as Record<string, unknown>[];\n}\n\n/** Slim a validation error for an agent payload (drops nothing useful). */\nfunction tidyError(e: ValidationError) {\n const out: Record<string, unknown> = { path: e.path, message: e.message };\n if (e.rule) out.rule = e.rule;\n if (e.severity) out.severity = e.severity;\n if (e.fix) out.fix = e.fix;\n if (e.suggestion) out.suggestion = e.suggestion;\n if (e.evidence) out.evidence = e.evidence;\n if (e.requiresDecision !== undefined) out.requiresDecision = e.requiresDecision;\n return out;\n}\n\nfunction authoringMetadata(spec: AnySpec) {\n const types = listChartTypes();\n const capabilities = (type: AnySpec['type']) => types.find((t) => t.type === type)?.capabilities;\n if (spec.type !== 'dashboard') {\n return { profile: profileData(spec.data ?? []), capabilities: capabilities(spec.type) };\n }\n return {\n ...(spec.data ? { profile: profileData(spec.data) } : {}),\n capabilities: capabilities(spec.type),\n views: spec.views.map((view) => ({\n id: view.id,\n capabilities: capabilities(view.spec.type),\n ...(view.spec.data\n ? { profile: profileData(view.spec.data) }\n : { inheritsSharedData: true }),\n })),\n };\n}\n\n/**\n * **The flagship.** Validate a spec, auto-repair it if it's safely fixable, render\n * it to a PNG headless, and return the image alongside a machine-readable critique\n * (the render report + lint warnings + any repairs applied). When the spec can't be\n * made valid, returns the structured errors and JSON-Patch fixes instead of an image\n * so the agent corrects in one step rather than regenerating.\n */\nexport function renderChartHandler(args: RenderArgs): ToolResult {\n return renderOrCritique(args, true);\n}\n\n/**\n * Validate, optionally repair, render, and return only the machine-readable\n * render report + summary. This avoids sending a base64 PNG when an agent only\n * needs diagnostics.\n */\nexport function critiqueChartHandler(args: CritiqueArgs): ToolResult {\n return renderOrCritique(args, false);\n}\n\nfunction renderOrCritique(args: RenderArgs, includeImage: boolean): ToolResult {\n const { spec, width, height, dpr, repair = true, repairLevel, quality } = args;\n try {\n validateRenderImageOptions({ width, height, dpr });\n } catch (e) {\n return optionErrorResult(e, quality);\n }\n let working: unknown;\n try {\n working = specWithParsedData(spec);\n } catch (e) {\n return parseErrorResult(e, quality);\n }\n const prepared = draft(working, { repair, repairLevel, quality });\n const type = specType(prepared.spec);\n if (!prepared.valid) {\n const payload = {\n ok: false, rendered: false, stage: 'validate', type,\n errors: prepared.errors.map(tidyError),\n lint: prepared.warnings.map(tidyError),\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? { effectiveSpec: prepared.spec, quality: prepared.quality } : {}),\n hint: `Apply each error.fix JSON Patch (or the repair_chart tool), then call ${includeImage ? 'render_chart' : 'critique_chart'} again. See the graphein://agent-guide and graphein://schema resources.`,\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n }\n\n try {\n const rendered = renderChart(prepared.spec as AnySpec, { width, height, dpr, quality });\n const { report } = rendered;\n const payload = {\n ok: report.ok, rendered: true, type,\n pixelSize: { width: rendered.width, height: rendered.height },\n summary: report.summary,\n ...(includeImage ? {\n marks: report.markCount, series: report.seriesCount, colors: report.colorCount,\n diagnostics: report.diagnostics,\n } : {}),\n report,\n lint: validateSpec(rendered.spec).warnings.map(tidyError),\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? {\n effectiveSpec: rendered.spec, quality: rendered.quality,\n authoring: authoringMetadata(rendered.spec),\n } : {}),\n };\n return {\n isError: false,\n content: [\n ...(includeImage ? [{ type: 'image' as const, data: rendered.png.toString('base64'), mimeType: 'image/png' }] : []),\n json(payload),\n ],\n structuredContent: payload,\n };\n } catch (e) {\n const failed = e instanceof NodeRenderError ? e.result : undefined;\n const payload = {\n ok: false, rendered: false, stage: 'render', type,\n message: e instanceof Error ? e.message : String(e),\n summary: prepared.summary,\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? {\n effectiveSpec: failed?.spec ?? prepared.spec,\n quality: failed?.quality ?? { ...prepared.quality, stopReason: 'render-failed' },\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n }\n}\n\n/**\n * Validate a spec without rendering — fast structural + best-practice feedback.\n * Returns errors (each with a JSON-Patch `fix` when unambiguous and \"did you mean\"\n * suggestions) and lint `warnings`.\n */\nexport function validateChartHandler(args: { spec: unknown }): ToolResult {\n let spec: unknown;\n try {\n spec = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const result = validateSpec(spec);\n return {\n isError: false,\n content: [\n json({\n valid: result.valid,\n type: specType(spec),\n errors: result.errors.map(tidyError),\n warnings: result.warnings.map(tidyError),\n }),\n ],\n };\n}\n\n/** Recommend ready-to-render ChartSpecs from tidy rows and an optional intent. */\nexport function recommendChartHandler(args: RecommendChartArgs): ToolResult {\n if (!isRecommendIntent(args.intent)) {\n return {\n isError: true,\n content: [\n json({\n ok: false,\n message: 'Unsupported intent. Expected trend, comparison, distribution, relationship, or composition.',\n }),\n ],\n };\n }\n let data: Record<string, unknown>[];\n try {\n data = rowsWithParsedData(args.data);\n } catch (e) {\n return parseErrorResult(e);\n }\n const recommendations = recommendChart(data, {\n intent: args.intent, maxResults: args.maxResults, targetSize: args.targetSize, detailed: true,\n });\n const payload = { ok: true, ...recommendations };\n return { isError: false, content: [json(payload)], structuredContent: payload };\n}\n\n/**\n * List every supported chart family with its purpose, required channels, and a\n * minimal runnable starter spec.\n */\nexport function listChartTypesHandler(): ToolResult {\n const payload = { ok: true, chartTypes: listChartTypes() };\n return { isError: false, content: [json(payload)], structuredContent: payload };\n}\n\n/**\n * Apply every safe, unambiguous repair Graphein proposes and return the corrected\n * spec, the JSON Patch operations applied, and whether it is now valid.\n */\nexport function repairChartHandler(args: RepairChartArgs): ToolResult {\n let input: unknown;\n try {\n input = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const { spec, applied, appliedDetails, remaining } = repairSpec(input, { level: args.level ?? 'safe' });\n return {\n isError: false,\n content: [\n json({\n valid: remaining.length === 0,\n level: args.level ?? 'safe',\n applied,\n appliedDetails,\n remaining: remaining.map(tidyError),\n spec,\n }),\n ],\n };\n}\n\n/**\n * Return a deterministic, plain-English summary of what the chart's data shows —\n * doubles as alt-text, needs no LLM.\n */\nexport function summarizeChartHandler(args: { spec: unknown }): ToolResult {\n let spec: unknown;\n try {\n spec = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const result = validateSpec(spec);\n if (!result.valid) {\n return {\n isError: true,\n content: [\n json({\n summary: null,\n reason: 'Spec is invalid; fix it first (validate_chart / repair_chart).',\n errors: result.errors.map(tidyError),\n }),\n ],\n };\n }\n const validSpec = spec as AnySpec;\n const summary = validSpec.type === 'dashboard' ? undefined : summarize(validSpec);\n return {\n isError: false,\n content: [\n text(summary || `(No narrative summary is available for a '${specType(args.spec)}' chart.)`),\n ],\n };\n}\n","/**\n * The agent-facing knowledge Graphein serves as MCP **resources** — the schema\n * and the prose guides — so a model that has never seen Graphein's API can read\n * the contract at runtime instead of relying on training data. This is the core\n * of the MCP server's \"neutralize the training-data gap\" purpose.\n *\n * The files live in `../resources/` (committed copies of the repo's `docs/`, kept\n * in sync by `scripts/sync-resources.mjs`). They are read lazily and cached so the\n * server pays nothing until an agent actually asks for one.\n */\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\n/** Metadata describing one served resource. */\nexport interface GrapheinResource {\n /** Short registration name. */\n name: string;\n /** Stable `graphein://…` URI an agent reads. */\n uri: string;\n /** Human title. */\n title: string;\n /** What the resource is and when to read it. */\n description: string;\n /** IANA media type. */\n mimeType: string;\n /** File under `resources/`. */\n file: string;\n}\n\n/** Every resource the server exposes, in the order they should be advertised. */\nexport const RESOURCES: GrapheinResource[] = [\n {\n name: 'schema',\n uri: 'graphein://schema',\n title: 'Graphein ChartSpec JSON Schema',\n description:\n 'The machine-readable JSON Schema for every Graphein ChartSpec and DashboardSpec field — chart types, channels, transforms, annotations, and required properties. Generate or check a spec against this.',\n mimeType: 'application/json',\n file: 'chart-spec.schema.json',\n },\n {\n name: 'agent-guide',\n uri: 'graphein://agent-guide',\n title: 'Graphein Agent Guide',\n description:\n 'A task-oriented guide for producing correct Graphein charts: the one-rule workflow, choosing a chart type, encodings, transforms, the validate → repair → render → critique loop, and worked recipes. Read this first.',\n mimeType: 'text/markdown',\n file: 'agent-guide.md',\n },\n {\n name: 'spec-reference',\n uri: 'graphein://spec-reference',\n title: 'Graphein Spec Reference',\n description:\n 'The exhaustive field-by-field reference for every chart type, channel, transform, annotation, and modifier. Consult this for the precise shape of a specific field.',\n mimeType: 'text/markdown',\n file: 'spec-reference.md',\n },\n];\n\nconst cache = new Map<string, string>();\nconst allowedResourceFiles = new Set(RESOURCES.map((r) => r.file));\n\n/**\n * Read a bundled resource file's text, cached. Resolved relative to this module\n * so it works both from `dist/` (published) and `src/` (tests) — the committed\n * `resources/` dir always sits one level up from either.\n */\nexport function readResourceFile(file: string): string {\n if (!allowedResourceFiles.has(file)) {\n throw new Error(`Unknown Graphein MCP resource \"${file}\".`);\n }\n const hit = cache.get(file);\n if (hit !== undefined) return hit;\n const url = new URL(`../resources/${file}`, import.meta.url);\n const text = readFileSync(fileURLToPath(url), 'utf8');\n cache.set(file, text);\n return text;\n}\n\n/** Look up a resource by its `graphein://…` URI. */\nexport function resourceByUri(uri: string): GrapheinResource | undefined {\n return RESOURCES.find((r) => r.uri === uri);\n}\n","/**\n * `createServer()` — builds the Graphein MCP server: the generate → validate →\n * repair → render → critique loop as four tools, the schema + guides as resources,\n * and a `create_chart` prompt that teaches the workflow. Split from the stdio\n * entry point (`server.ts`) so it can be driven over any transport — including the\n * in-memory transport in tests.\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { RENDER_LIMITS } from '@graphein/node';\nimport { z } from 'zod';\nimport {\n critiqueChartHandler,\n listChartTypesHandler,\n renderChartHandler,\n validateChartHandler,\n repairChartHandler,\n recommendChartHandler,\n summarizeChartHandler,\n} from './handlers.js';\nimport { RESOURCES, readResourceFile } from './resources.js';\nimport { mcpToolMetadata } from './toolMetadata.js';\n\n/** Package version, surfaced as the MCP server version. */\nexport const VERSION = '0.21.0';\n\nconst SERVER_INSTRUCTIONS = `Graphein is an agent-first data-visualization library: you describe a chart as one JSON ChartSpec ({ type, data, encoding, ... }) and it renders. This server lets you build correct charts without prior knowledge of the API.\n\nWorkflow:\n1. Call list_chart_types to see every supported chart type with required channels, field roles, aggregation behavior, cardinality caveats, and starter specs; read graphein://agent-guide (and graphein://schema for exact fields) only when you need deeper detail.\n2. Shape data as tidy rows — one row per observation, one column per variable. Tools that accept rows also accept CSV/TSV text with a header row.\n3. Use recommend_chart when you want ranked specs from data, or start from a list_chart_types starter. Inspect profile, findings, and status: needs-decision/no-candidate are not permission to guess aggregation, date roles, missing values, or geometry.\n4. Emit a ChartSpec and call critique_chart for report-only diagnostics, or render_chart when you need the PNG plus critique. Both validate, auto-repair safe mistakes, render headlessly once by default, and return lint/report feedback. Opt in with quality:true for presentation-default improvements within three TOTAL whole-visual renders, including restoration. Read effectiveSpec, quality history and unresolved diagnostics; the loop never changes data or explicit settings.\n5. If a spec is invalid, validate_chart, critique_chart, and render_chart return structured errors with JSON-Patch fixes. Apply them or call repair_chart; use repair_chart level \"data\" to infer missing encodings or close field-name typos from the spec's own data.\nUse summarize_chart for deterministic alt-text. Every type rasterizes headlessly, including kpi, table, matrix, slicers and dashboard (static canvas snapshots).`;\n\n/** A permissive object schema for a Graphein spec — validateSpec does the real checking. */\nconst specSchema = z\n .record(z.string(), z.unknown())\n .describe(\n 'A Graphein ChartSpec or DashboardSpec object, e.g. { \"type\": \"line\", \"data\": [...], \"encoding\": {...} }. Any data property may be tidy rows or CSV/TSV text with a header row. See the graphein://schema and graphein://agent-guide resources.',\n );\n\nconst dataRowsSchema = z.union([\n z.array(z.record(z.string(), z.any())),\n z.string().describe('CSV or TSV text with a header row; quoted delimiters, quotes, and newlines are supported.'),\n]);\n\nconst intentSchema = z\n .enum(['trend', 'comparison', 'distribution', 'relationship', 'composition'])\n .optional()\n .describe(\n 'Optional analytical intent used to rank recommendations: trend, comparison, distribution, relationship, or composition.',\n );\n\nconst qualitySchema = z.union([\n z.boolean(),\n z.object({\n maxPasses: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional()\n .describe('Total whole-visual render ceiling including initial and rollback passes (default 3).'),\n }).strict(),\n]).optional().describe(\n 'Opt in to bounded presentation-default improvement. Default false: one render. Never alters data, encodings, explicit palettes/domains, or other caller settings. Returns effectiveSpec and quality history. Mutable targets reserve a rollback pass.',\n);\n\nconst repairLevelSchema = z.enum(['safe', 'data']).optional()\n .describe('Independent repair policy: safe (default), or explicitly opt in to data-aware field/encoding inference.');\nconst widthSchema = z.number().min(RENDER_LIMITS.minWidth).max(RENDER_LIMITS.maxWidth).optional()\n .describe(`Logical width in CSS px (default 800; ${RENDER_LIMITS.minWidth}-${RENDER_LIMITS.maxWidth}).`);\nconst heightSchema = z.number().min(RENDER_LIMITS.minHeight).max(RENDER_LIMITS.maxHeight).optional()\n .describe(`Logical height in CSS px (default 500; ${RENDER_LIMITS.minHeight}-${RENDER_LIMITS.maxHeight}).`);\nconst dprSchema = z.number().min(RENDER_LIMITS.minDpr).max(RENDER_LIMITS.maxDpr).optional()\n .describe(`Device pixel ratio for crisp output (default 2; ${RENDER_LIMITS.minDpr}-${RENDER_LIMITS.maxDpr}; total raster pixels capped at ${RENDER_LIMITS.maxPixels.toLocaleString('en-US')}).`);\n\nconst toolOptions = (name: string): { title: string; description: string } => {\n const { title, description } = mcpToolMetadata(name);\n return { title, description };\n};\n\n/**\n * Build a fully-configured Graphein MCP server. The caller connects it to a\n * transport (`server.connect(transport)`).\n */\nexport function createServer(): McpServer {\n const server = new McpServer(\n { name: 'graphein-mcp', version: VERSION },\n { instructions: SERVER_INSTRUCTIONS },\n );\n registerTools(server);\n registerResources(server);\n registerCreateChartPrompt(server);\n return server;\n}\n\nfunction registerTools(server: McpServer): void {\n // --- Tools: the runtime loop -------------------------------------------------\n registerRenderTools(server);\n registerSpecTools(server);\n}\n\nfunction registerRenderTools(server: McpServer): void {\n server.registerTool(\n 'render_chart',\n {\n ...toolOptions('render_chart'),\n inputSchema: {\n spec: specSchema,\n width: widthSchema,\n height: heightSchema,\n dpr: dprSchema,\n repair: z\n .boolean()\n .optional()\n .describe('Auto-apply safe repairs before rendering when the spec is invalid (default true).'),\n repairLevel: repairLevelSchema,\n quality: qualitySchema,\n },\n },\n async (args) => renderChartHandler(args),\n );\n\n server.registerTool(\n 'critique_chart',\n {\n ...toolOptions('critique_chart'),\n inputSchema: {\n spec: specSchema,\n width: widthSchema,\n height: heightSchema,\n dpr: dprSchema,\n repair: z\n .boolean()\n .optional()\n .describe('Auto-apply safe repairs before rendering when the spec is invalid (default true).'),\n repairLevel: repairLevelSchema,\n quality: qualitySchema,\n },\n },\n async (args) => critiqueChartHandler(args),\n );\n}\n\nfunction registerSpecTools(server: McpServer): void {\n server.registerTool(\n 'validate_chart',\n {\n ...toolOptions('validate_chart'),\n inputSchema: { spec: specSchema },\n },\n async (args) => validateChartHandler(args),\n );\n\n server.registerTool(\n 'recommend_chart',\n {\n ...toolOptions('recommend_chart'),\n inputSchema: {\n data: dataRowsSchema,\n intent: intentSchema,\n maxResults: z.number().int().positive().optional(),\n targetSize: z.object({\n width: z.number().positive(),\n height: z.number().positive(),\n }).optional().describe('Optional target CSS-pixel size for layout guidance only; does not filter or group data.'),\n },\n },\n async (args) => recommendChartHandler(args),\n );\n\n server.registerTool(\n 'repair_chart',\n {\n ...toolOptions('repair_chart'),\n inputSchema: {\n spec: specSchema,\n level: z\n .enum(['safe', 'data'])\n .optional()\n .describe('Repair aggressiveness. \"safe\" is default; \"data\" also infers from the spec data.'),\n },\n },\n async (args) => repairChartHandler(args),\n );\n\n server.registerTool(\n 'list_chart_types',\n {\n ...toolOptions('list_chart_types'),\n inputSchema: {},\n },\n async () => listChartTypesHandler(),\n );\n\n server.registerTool(\n 'summarize_chart',\n {\n ...toolOptions('summarize_chart'),\n inputSchema: { spec: specSchema },\n },\n async (args) => summarizeChartHandler(args),\n );\n}\n\nfunction registerResources(server: McpServer): void {\n\n // --- Resources: deliver the API knowledge at runtime -------------------------\n for (const r of RESOURCES) {\n server.registerResource(\n r.name,\n r.uri,\n { title: r.title, description: r.description, mimeType: r.mimeType },\n async (uri) => ({\n contents: [{ uri: uri.href, mimeType: r.mimeType, text: readResourceFile(r.file) }],\n }),\n );\n }\n}\n\nfunction registerCreateChartPrompt(server: McpServer): void {\n\n // --- Prompt: teach the workflow ---------------------------------------------\n server.registerPrompt(\n 'create_chart',\n {\n title: 'Create a Graphein chart',\n description:\n 'Scaffold the workflow for building a validated Graphein chart from a goal (and optional data).',\n argsSchema: {\n goal: z.string().describe('What the chart should show, e.g. \"monthly active users over the last year\".'),\n data: z\n .string()\n .optional()\n .describe('Optional: the data as a JSON array, or a description of the columns available.'),\n },\n },\n ({ goal, data }) => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Build a Graphein chart for this goal:\\n\\n${goal}\\n${\n data ? `\\nData:\\n${data}\\n` : ''\n }\\nSteps:\\n1. Call list_chart_types for available chart families and starter specs; read graphein://agent-guide or graphein://schema only for deeper details.\\n2. Shape the data as tidy rows — one row per observation, one column per variable. CSV/TSV text with a header row is accepted anywhere data rows are accepted.\\n3. Choose a chart type (or call recommend_chart) and write a single ChartSpec ({ type, data, encoding, title }).\\n4. Call critique_chart for report-only feedback or render_chart when you need the PNG too. Read the returned render report + lint to confirm it looks right.\\n5. If it reports errors, apply each error.fix patch (or call repair_chart, using level \"data\" when field/encoding inference from data is useful) and render again — do not regenerate from scratch.`,\n },\n },\n ],\n }),\n );\n}\n","export interface McpToolMetadata {\n readonly name: string;\n readonly title: string;\n readonly description: string;\n}\n\nexport const MCP_TOOL_METADATA = Object.freeze([\n {\n name: 'render_chart',\n title: 'Render a Graphein chart',\n description: 'The one-call loop: validate a ChartSpec, auto-repair safe mistakes, render it to a PNG, and return the image plus a vision-free critique (render report, lint warnings, repairs applied). If the spec cannot be made valid, returns structured errors with JSON-Patch fixes instead of an image. Every type rasterizes headlessly — kpi, table, matrix, slicers and dashboard render static canvas snapshots.',\n },\n {\n name: 'critique_chart',\n title: 'Critique a Graphein chart without an image',\n description: 'Validate a ChartSpec, auto-repair safe mistakes, render it headlessly, and return only the RenderReport, deterministic summary, lint warnings, and repairs applied — no base64 PNG. Use this when you need diagnostics but not an image.',\n },\n {\n name: 'validate_chart',\n title: 'Validate a Graphein chart spec',\n description: 'Validate a ChartSpec without rendering. Returns structural errors (each with a JSON-Patch fix when unambiguous, plus did-you-mean suggestions) and best-practice lint warnings. Fast feedback before rendering.',\n },\n {\n name: 'recommend_chart',\n title: 'Recommend Graphein chart specs',\n description: 'Profile tidy rows and return ranked ChartSpecs with rationale, profile evidence, alternatives, and explicit needs-decision/no-candidate findings. Use this before guessing a chart type or encoding; no supplied data is changed.',\n },\n {\n name: 'repair_chart',\n title: 'Repair a Graphein chart spec',\n description: 'Apply Graphein repairs and return the corrected spec, JSON Patch ops, per-patch rationales, and whether it is now valid. The default safe level applies validator-provided fixes; level \"data\" may infer missing encodings and field-name typo fixes from the spec\\'s own data.',\n },\n {\n name: 'list_chart_types',\n title: 'List Graphein chart types',\n description: 'Return every supported chart type with purpose, required channels/properties, field roles, aggregation semantics, cardinality guidance, supported features, and a minimal runnable starter. Use this before reading the full schema.',\n },\n {\n name: 'summarize_chart',\n title: 'Summarize a Graphein chart',\n description: 'Return a deterministic, plain-English description of what the chart\\'s data shows (e.g. \"Users grew 46% over six months, peaking in June\"). Doubles as alt-text; needs no LLM.',\n },\n] satisfies readonly McpToolMetadata[]);\n\nexport function mcpToolMetadata(name: string): McpToolMetadata {\n const tool = MCP_TOOL_METADATA.find((item) => item.name === name);\n if (!tool) throw new Error(`Unknown Graphein MCP tool: ${name}`);\n return tool;\n}\n"],"mappings":"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","names":["text","text"]}
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export { AnyRenderReport, AnySpec, ChartCapabilities, ChartSpec, DashboardRender
11
11
  */
12
12
 
13
13
  /** Package version, surfaced as the MCP server version. */
14
- declare const VERSION = "0.20.0";
14
+ declare const VERSION = "0.21.0";
15
15
  /**
16
16
  * Build a fully-configured Graphein MCP server. The caller connects it to a
17
17
  * transport (`server.connect(transport)`).
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  resourceByUri,
15
15
  summarizeChartHandler,
16
16
  validateChartHandler
17
- } from "./chunk-7DJMHUCG.js";
17
+ } from "./chunk-DNKOUF77.js";
18
18
  export {
19
19
  RESOURCES,
20
20
  TabularParseError,
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createServer
4
- } from "./chunk-7DJMHUCG.js";
4
+ } from "./chunk-DNKOUF77.js";
5
5
 
6
6
  // src/server.ts
7
7
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphein-mcp",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "type": "module",
5
5
  "description": "Model Context Protocol server for Graphein — wraps generate → validate → repair → render → critique into one tool call, and serves Graphein's schema + agent guide as resources so a model that never saw the API can still build correct charts.",
6
6
  "license": "MIT",
@@ -62,9 +62,9 @@
62
62
  "prepack": "npm run sync:version && tsup"
63
63
  },
64
64
  "dependencies": {
65
- "@graphein/node": "^0.20.0",
65
+ "@graphein/node": "^0.21.0",
66
66
  "@modelcontextprotocol/sdk": "^1.20.0",
67
- "graphein": "^0.20.0",
67
+ "graphein": "^0.21.0",
68
68
  "zod": "^3.23.0"
69
69
  }
70
70
  }
@@ -133,6 +133,12 @@ reference: [spec-reference → Transforms](./spec-reference.md#transforms).
133
133
  | Running total / bridge | `waterfall` | `stage`, `value` (signed deltas) |
134
134
  | Before / after by series | `slope` | `x`, `y`, `series` |
135
135
  | Gap between two groups | `dumbbell` | `category`, `value`, `group` |
136
+ | Profile across several measures | `radar` | `category` (spokes), `value`, optional `series` (+ `max?`) |
137
+ | Schedule / timeline of tasks | `gantt` | `task`, `start`, `end` (+ `group?`, `progress?`) |
138
+ | Nested part‑to‑whole in rings | `sunburst` | `value` (+ top‑level `levels`) |
139
+ | Price action (open/high/low/close) | `candlestick` | `x`, `open`, `high`, `low`, `close` |
140
+ | Sized points by coordinates | `bubbleMap` | `longitude`, `latitude` (+ `size?`, `color?`, `geo?`) |
141
+ | Progress rings / polar area | `radialBar` | `category`, `value` (+ `max?`, `layout?`) |
136
142
  | Single number / headline metric | `kpi` | `value` (+ `label`, `delta`, `sparkline`, `comparisons`) |
137
143
  | Raw/detail records | `table` | `columns` (+ optional totals, groups, bars/icons/rules) |
138
144
  | Aggregated cross‑tab | `matrix` | `rows`, `columns`, `values` (+ `showAs` percentages) |
@@ -674,7 +680,11 @@ export gets a plain-text fallback, and `chart.report()` still reflects the real
674
680
  - **`encoding` is required** for `line`/`area`/`bar`/`scatter`/`box` (`x`+`y`), `pie`
675
681
  (`theta`+`color`), `heatmap` (`x`+`y`+`color`), `sankey` (`source`+`target`+`value`),
676
682
  and `choropleth` (`key`+`color`, plus a `geo` FeatureCollection). `kpi`/`table`/`matrix`
677
- use their own field lists instead of `encoding`.
683
+ use their own field lists instead of `encoding`. `sunburst` needs a top‑level `levels`
684
+ array (innermost ring first) plus `encoding.value`; `bubbleMap` takes degrees in
685
+ `longitude`/`latitude` (never names — nothing is geocoded) with an optional `geo` basemap
686
+ and `projection` (`'albers'` for the United States); `gantt` annotations use `axis: 'x'`
687
+ for dates and `axis: 'y'` for task lanes.
678
688
  - **Field names must exist** in every `data` row (dotted paths like `a.b` read nested
679
689
  values).
680
690
  - **Don't pre‑pivot** for charts — pass tidy rows and split with `series`. Use `matrix`
@@ -890,7 +900,8 @@ await fs.writeFile('chart.png', png);
890
900
  ```
891
901
 
892
902
  It supports the entire catalog (line, area, bar, scatter, box, pie, heatmap, sankey,
893
- choropleth, combo, histogram, funnel, treemap, gauge, bullet, calendarHeatmap) **plus** the
903
+ choropleth, combo, histogram, funnel, treemap, gauge, bullet, calendarHeatmap, waterfall,
904
+ slope, dumbbell, radar, gantt, sunburst, candlestick, bubbleMap, radialBar) **plus** the
894
905
  formerly DOM-only kpi, table, matrix, slicers and dashboard — they paint a static canvas
895
906
  snapshot, so every type validates and rasterizes server-side. Core's dependency-free
896
907
  `renderToContext(target, spec)` paints onto any 2D context if you bring your own canvas