The open chart format an LLM writes and the browser renders — to interactive, accessible SVG.
Model Context Protocol Server: io.github.blueprint-chart/mcp
The io.github.blueprint-chart/mcp server is a Model Context Protocol server for authoring Blueprint Chart .bpc files with LLMs. It describes an open chart format that an LLM writes and a browser renders, producing interactive, accessible SVG. The workflow emphasizes a tight parse + render feedback loop.
🛠️ Key Features
Author Blueprint Chart .bpc files with LLMs
Uses an open, plain-text chart format
Renders to interactive, accessible SVG
Tight parse + render feedback loop
Self-contained (no backend)
🚀 Use Cases
Generate chart definitions via an LLM
Render resulting charts in a browser as SVG
Support authoring with immediate parse and render feedback
⚡ Developer Benefits
Plain-text .bpc artifacts suitable for tooling
Browser-rendered SVG output
No account required
⚠️ Limitations
Source material does not specify a tool list, authentication, or supported integration details.
Model Context Protocol server for authoring Blueprint Chart .bpc files with LLMs, grounded in real dataviz pedagogy with a tight parse + render feedback loop. An open, plain-text chart format an AI can write and any browser can render. Self-contained, no backend, no account required.
The MCP exposes Blueprint Chart's dataviz handbook, DSL grammar reference, chart-type docs, and canonical samples as MCP resources, plus eleven deterministic tools: validate_dsl, inspect_dsl, recommend_chart_type, render, list_chart_types, describe_chart_type, get_example, get_grammar, export_chart, search_examples, and list_palettes. Your LLM writes the .bpc; the MCP grounds it in real dataviz pedagogy and gives it a tight feedback loop.
Install
bash
npx @blueprint-chart/mcp # stdio (for Claude Desktop, Claude Code, Cursor)
npx @blueprint-chart/mcp --http # HTTP/SSE on 127.0.0.1:4321
Parse .bpc; returns { valid, errors[], warnings[] } — each error has code, message, suggestion
inspect_dsl
Parse and summarize: chartType, scenes, seriesCount, rowCount, hasHighlights, hasColorizes, etc.
recommend_chart_type
Rank chart types for a given column shape and row count
render
Render to SVG (default), PNG, or HTML; with format:"png" returns an inline image both you and the user can see. Always returns structured frame metadata. When MCP_PUBLIC_URL is set, includes urls ({png,svg,bpc}) — stateless links where the chart data travels inside the URL. Set modelVisible:false to drop the inline image from the response entirely, spending no image tokens. Pass save:<path> to write the output to disk (requires MCP_FS_WRITE_DIR; writes are confined to that directory). Width/height capped at 1600; PNG is 2× retina.
list_chart_types
List all renderable chart types (tool equivalent of bpc://handbook/choosing)
describe_chart_type
Properties, when-to-use, when-NOT-to-use, and data-shape for one chart type (tool equivalent of bpc://chart-types/{slug})
get_example
Fetch a canonical .bpc sample by chart type or sample name (tool equivalent of bpc://samples/{id})
search_examples
Find canonical examples by topic keywords and/or chart type (returns pointers; fetch full DSL with get_example)
get_grammar
Full DSL syntax reference (tool equivalent of bpc://grammar)
list_palettes
List named colour palettes with hex colours for colorPalette
export_chart
Validate a .bpc and return shareable URLs plus an inline preview. Returns { copyUrl, embedUrl, urls?, frame } — copyUrl is editable in the editor, embedUrl is a read-only iframe target, urls.{png,svg,bpc} are stateless rendered/source links (when MCP_PUBLIC_URL is set). Set modelVisible:false to drop the inline preview from the response entirely, spending no image tokens. Requires BLUEPRINT_CHART_EDITOR_URL; preview failures never block the export.
The discovery tools (list_chart_types, describe_chart_type, get_example, search_examples, get_grammar, list_palettes) let clients without MCP resource support access the same reference material that the bpc:// URIs expose.
Saving rendered output
The render tool can write its output to disk via save: <path>. This is disabled by default. Set MCP_FS_WRITE_DIR to a directory to enable it — ideally an absolute path; a relative value is resolved from the server's working directory at startup. Every write lands inside that directory (a sandbox), so you never have to worry about where a client puts files: relative save paths are joined to it, an absolute path already inside it is used as-is, and any other absolute path is re-anchored under it (the leading slash is stripped and the rest joined on, so save: "/tmp/foo.png" becomes <dir>/tmp/foo.png). Only paths that still escape via ../ traversal are rejected. Missing subdirectories are created automatically. Containment is checked lexically (no realpath), so a symlink whose lexical path is inside the sandbox still passes the check and is then resolved by the OS at write time — if its target is outside the sandbox, the write reaches it. Avoid placing symlinks in the sandbox if isolation matters to you.
Once the MCP is connected, ask Claude to make a chart:
You: Make a horizontal bar chart of English letter frequencies — top 10, highlight E.
Claude:(calls list_chart_types, get_example({ chartType: "bar-horizontal" }), writes the .bpc, calls validate_dsl to confirm it parses, calls render with format: 'png' and shows you the image and the source)
Here's the chart:
![image]
code
chart bar-horizontal {
title = "E is the most frequent letter in English"
sort = descending
valueLabels = true
highlight "E"
data { "E" = 12.70; "T" = 9.06; "A" = 8.17; ... }
}
The MCP grounds Claude in real dataviz pedagogy (the handbook) before it writes a single line of DSL, then closes the loop with deterministic parse + render feedback.
What .bpc looks like
text
chart bar-vertical {
title = "E is the most frequent letter in English"
description = "How often each letter appears in typical English text"
source = "Lewand, Cryptological Mathematics"
colorPalette = "London"
sort = descending
valueLabels = true
highlight "E"
data {
"E" = 12.70
"T" = 9.06
"A" = 8.17
"O" = 7.51
...
}
}
Full grammar at bpc://grammar; 17 canonical samples at bpc://samples/<id> (letter-frequency, co2-emissions, quarterly-revenue, browser-market, temperature-anomaly, population-stacked-bar, ...).
validate_dsl — parse with structured diagnostics
Request:
json
{"name":"validate_dsl","arguments":{"source":"chart bar-vertical {\n title = \"oops\n}"}}
Response — valid is false; each entry in errors[] carries a code, human-readable message, and an actionable suggestion:
json
{"valid":false,"errors":[{"code":"E_PARSE","message":"Expected \"\\\"\" but end of input found.","suggestion":"Close the string literal on line 2."}],"warnings":[]}
{"ok":true,"data":{"recommendations":[{"chartType":"line-multi","label":"Multi-Line Chart","fitness":"best","reason":"1 date + 3 numeric columns — compare trends"},{"chartType":"bar-multi","label":"Grouped Bar Chart","fitness":"alternative","reason":"Can also show as grouped bars"}]}}
The urls field is only present when MCP_PUBLIC_URL is configured; every render and export_chart response then includes these stateless links, with the chart data travelling inside the URL (as bpc64, a URL-safe base64 encoding of the .bpc source) — no session, no server state required. Set modelVisible:false in the request to drop the inline image from the response entirely, spending no image tokens.
If rasterization fails (rare), errors[] is non-empty — each entry has a code ("E_RENDER") and a suggestion — and the response still includes the SVG that was successfully produced, so partial success is preserved.
/render.bpc serves the raw .bpc source — it's "view source" for any chart URL, handy for sharing or reproducing a chart from its link alone.
Sources whose encoding exceeds 8 KB return 413 from the endpoints (and the tool omits urls, returning urlsOmitted: "source-too-large" instead) — use the inline PNG for very large charts.
Reading a resource
json
{"uri":"bpc://handbook/choosing"}
Returns the full Markdown of the "Choosing the Right Chart" handbook page (same content as docs.blueprintchart.com).
json
{"uri":"bpc://samples/letter-frequency"}
Returns the raw .bpc source for the letter-frequency sample as text/plain — exactly what the LLM should imitate.