| Status | |
|---|---|
| CI checks | |
| Latest version | |
| Release date | |
| Open issues | |
| Websites | |
| Smithery |
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
npx @blueprint-chart/mcp # stdio (for Claude Desktop, Claude Code, Cursor)
npx @blueprint-chart/mcp --http # HTTP/SSE on 127.0.0.1:4321
Use with Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"blueprint-chart": {
"command": "npx",
"args": ["-y", "@blueprint-chart/mcp"]
}
}
}
Use with Claude Code
claude mcp add blueprint-chart \
-e BLUEPRINT_CHART_EDITOR_URL=https://blueprintchart.com \
-e BLUEPRINT_CHART_DOCS_URL=https://docs.blueprintchart.com \
-- npx -y @blueprint-chart/mcp
Tools
| Tool | Purpose |
|---|---|
validate_dsl | 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 show the image to the user without spending model 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 scene-0 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 show the preview to the user only. 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.
Add the -e flag to your claude mcp add command:
claude mcp add blueprint-chart \
-e MCP_FS_WRITE_DIR=/path/to/output \
-- npx -y @blueprint-chart/mcp
Resources
bpc://grammar— full DSL syntax referencebpc://handbook/<slug>— dataviz pedagogy (choosing, design-principles, color, typography, annotations, accessibility, ...)bpc://guide/<slug>— usage guides (scenes, palettes, data-transforms, ...)bpc://chart-types/<slug>— per-chart-type docsbpc://samples/<id>— canonical.bpcexamplesbpc://reference/dsl/<slug>,bpc://reference/api/<slug>— full reference
Prompts
author_chart— primes the LLM end-to-end (read → write → validate → render → iterate)
Examples
Quickstart with Claude
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, callsvalidate_dslto confirm it parses, callsrenderwithformat: 'png'and shows you the image and the source)Here's the chart:
![image]
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
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:
{
"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:
{
"valid": false,
"errors": [
{
"code": "E_PARSE",
"message": "Expected \"\\\"\" but end of input found.",
"suggestion": "Close the string literal on line 2."
}
],
"warnings": []
}
inspect_dsl — structured summary
Request:
{ "name": "inspect_dsl", "arguments": { "source": "<.bpc source>" } }
Response:
{
"ok": true,
"data": {
"chartType": "bar-vertical",
"scenes": [{ "index": 0, "hasTransition": false }],
"hasAnnotations": false,
"hasColorizes": false,
"hasHighlights": true,
"hasAreaFills": false,
"seriesCount": 0,
"rowCount": 26
}
}
recommend_chart_type — ranked suggestions
Request:
{
"name": "recommend_chart_type",
"arguments": { "columnTypes": ["date", "number", "number", "number"], "rowCount": 24 }
}
Response:
{
"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" }
]
}
}
render — SVG (default), PNG, or HTML
Request:
{
"name": "render",
"arguments": { "source": "<.bpc source>", "format": "png", "width": 800, "height": 500 }
}
Response:
{
"ok": true,
"data": {
"svg": "<svg ...>...</svg>",
"png": "<base64-encoded image>",
"mimeType": "image/png",
"urls": {
"png": "https://mcp.blueprintchart.com/render.png?bpc64=…",
"svg": "https://mcp.blueprintchart.com/render.svg?bpc64=…",
"bpc": "https://mcp.blueprintchart.com/render.bpc?bpc64=…"
}
}
}
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 display the inline image to the user without spending model 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.
Hosted render URLs
Embed a chart directly in a page:
<img src="https://<your-mcp-host>/render.png?bpc64=<bpc64value>&width=800&height=500" alt="My chart" width="800" height="500">
/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
{ "uri": "bpc://handbook/choosing" }
Returns the full Markdown of the "Choosing the Right Chart" handbook page (same content as docs.blueprintchart.com).
{ "uri": "bpc://samples/letter-frequency" }
Returns the raw .bpc source for the letter-frequency sample as text/plain — exactly what the LLM should imitate.
License
MIT