A durable PNG URL
Served from GET /api/v1/charts/[id]?format=png with a one-year immutable cache header. Paste it into chat, an email, or a Slack message.
ChartRelay ships an MCP server with one tool, render_chart. The model sends a small JSON spec and gets back durable PNG and SVG URLs, alt text, and a structural quality review it can act on before anyone sees the chart.
Free plan: 1,000 renders a month once you confirm your email (100 before that). No card. The server runs from this repository today — it is not on npm yet.
Every successful call returns a block of text the model can read and quote, plus an inline PNG so it can see what it made.
Served from GET /api/v1/charts/[id]?format=png with a one-year immutable cache header. Paste it into chat, an email, or a Slack message.
The same chart at ?format=svg, for web pages and documents. The SVG carries a <title> and <desc> from the chart's title and alt text.
A sentence generated from the data: the peak, the low, and the first-to-last change for time-ordered charts. Pie charts get their largest shares instead.
Structural findings with a severity and a concrete fix — missing title, too many pie slices, a crowded chart, weak colour contrast, over-long axis labels.
The server fetches its own PNG and attaches it to the tool result, so the model can look at the chart rather than trust the spec. Turn it off with one environment variable.
Each result ends with the renders used against this month's quota, so an agent working in a loop can tell how much room is left.
Chart rendered (id kR2pQ7mXa4Tb9F).
PNG: http://localhost:3000/api/v1/charts/kR2pQ7mXa4Tb9F?format=png
SVG: http://localhost:3000/api/v1/charts/kR2pQ7mXa4Tb9F?format=svg
Alt text: Monthly recurring revenue. MRR peaks at 33,900 for Sep and bottoms at 18,400 for Apr. It increased 84.2% from first to last point.
Quality review: no structural problems found. Still verify the data and the takeaway in the title.
Usage this month: 42/1000.Generated on this page by the same renderer the API uses; the id and host are illustrative. URLs point at whatever CHARTRELAY_API_URL you configure.
The server lives in the mcp/ directory of the ChartRelay repository and speaks MCP over stdio.
Register for a free account and copy the key that is shown once. It starts with cr_live_.
Clone the repository, then run cd mcp && npm install. It needs Node 20 or newer.
Run the app you want to render against — npm run dev in the repository root serves it on http://localhost:3000 — and set CHARTRELAY_API_URL to it. The app itself needs Node 22 or newer, a step above the MCP server.
Use the config below, then ask the assistant for a chart. It will call render_chart and reply with the URLs.
{
"mcpServers": {
"chartrelay": {
"command": "node",
"args": ["/absolute/path/to/chartrelay/mcp/index.js"],
"env": {
"CHARTRELAY_API_KEY": "cr_live_...",
"CHARTRELAY_API_URL": "http://localhost:3000"
}
}
}
}Use an absolute path to index.js. Restart Claude Desktop after editing the file.
claude mcp add chartrelay \
-e CHARTRELAY_API_KEY=cr_live_... \
-e CHARTRELAY_API_URL=http://localhost:3000 \
-- node /absolute/path/to/chartrelay/mcp/index.jsAdds the same server to Claude Code. The API key is stored by your MCP client, never by this page.
These three are the whole configuration surface; the server reads nothing else.
| Variable | Default | What it does |
|---|---|---|
CHARTRELAY_API_KEY | Required — no default | Sent as a Bearer token on every render. Without it, the tool returns an error telling the model to create a key instead of failing silently. |
CHARTRELAY_API_URL | https://chartrelay.example | The ChartRelay instance to call. The built-in default is a placeholder domain, so set this explicitly — to your own deployment or to http://localhost:3000. |
CHARTRELAY_INCLUDE_IMAGE | true | Set it to false to skip the inline PNG preview and return only the text block. Useful when you are paying for image tokens you do not need. |
Each render_chart call counts as one render against your plan's monthly quota, the same as a direct API call.
Every finding carries a severity, a plain description of the problem, and a suggested fix. The tool description tells the model to revise the spec and call again when the review reports issues, so a bad chart can be caught before it reaches a person.
// First attempt: a pie chart with eleven slices.
Quality review found 1 issue(s). Consider fixing and re-rendering:
- [warning] Too many slices make the chart hard to scan. Fix: Keep the
largest six categories and group the rest as Other.
// The model groups the tail into "Other" and calls render_chart again.
Quality review: no structural problems found. Still verify the data and
the takeaway in the title.Both messages are the exact strings in src/lib/charts/qa.ts. Nothing here is automatic: the model chooses whether to re-render.
A pie chart with more than one series, or with negative values — cases the chart type genuinely cannot represent.
A missing or placeholder title, more than seven pie slices, more than forty points on a non-pie chart, more than seven series, or a series colour under 3:1 against the background.
Category labels over twelve characters, which get shortened on the axis. When nothing else fires, a single tip says no structural problems were found.
Worth reading before you let a model publish charts on your behalf.
Bar, line, area, pie, and scatter. Colours, light or dark theme, legend on or off, and values printed on the marks are all part of the spec.
Up to 12 series of up to 100 points each, at any size from 320x240 to 2400x1600 pixels.
GET /api/v1/charts/[id] needs no key, so the PNG and SVG URLs work in an email or a public page. Renders are immutable: the same id always returns the same image.
Read the quality review, adjust the spec, and call render_chart again — no human in the loop for a mis-shaped chart.
The review inspects the chart's structure — series counts, slice counts, density, contrast, labels. It never sees your source system and cannot check that a number is right.
Scatter places each value as a dot at its category label, in input order. There is no numeric x-axis, so it will not show a correlation.
The axis always includes zero. That rules out the exaggerated-difference chart, and it also rules out zooming in on a narrow range on purpose.
The v1 API is POST to create and GET to read. There is no edit and no delete, and no way to make a published URL private after the fact.
Any client that can launch a stdio MCP server, which includes Claude Desktop and Claude Code. The server uses the official @modelcontextprotocol/sdk and exposes a single tool, so there is nothing client-specific in it.
Not yet. The package @chartrelay/mcp is in this repository but has not been published, so run it with node mcp/index.js from a checkout. Publishing is planned; nothing on this page depends on it.
No. The MCP server is a thin wrapper over one HTTP endpoint. If you are writing your own code, post to /api/v1/charts with a Bearer key instead — the API docs cover the request and response in full.
The tool returns an error the model can read, saying the monthly limit was reached, with a link to the pricing page. It does not silently return an old chart, and a server error is never reported as a quota problem.
Both, by default. The tool result carries the text block and an inline PNG of the chart. Set CHARTRELAY_INCLUDE_IMAGE to false if you only want the text.
Yes. CHARTRELAY_API_URL takes any base URL, so the same server works against a local dev instance or your own hosted copy.
Create a free key, add the server from the repository, and ask for your first chart. If you would rather call the API yourself, the docs have the endpoint.
1,000 renders a month on the free plan once your email is confirmed (100 before). No card required.