flint-chart-connector
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@flint-chart-connectorchart my last six months of revenue by segment"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Flint charts for Claude and Codex
Flint is Microsoft Research's chart compiler. You hand it a compact semantic spec (chart type, which field goes on which channel, and what each field means), and it derives the scales, axes, tick formats, colour schemes, label rotation, legends and layout, emitting native Vega-Lite, ECharts or Chart.js. It works well with models, because semantic types are much easier to infer correctly than a full chart config.
This repo packages Flint as a remote MCP server you deploy yourself, tuned for chat hosts. It's verified working in Claude (web, desktop, mobile, Code) and OpenAI Codex.
There is no shared instance to join, so you'll want to deploy your own. It takes about a minute and sits comfortably inside the free tier.
Deploy it
Or from a clone:
git clone https://github.com/jmilinovich/flint-chart-connector
cd flint-chart-connector
npm install
npx vercel deploy --prodEither way you end up with a URL. Your connector endpoint is that URL plus /mcp:
https://<your-deployment>.vercel.app/mcpOpen the root URL in a browser and the landing page shows you that endpoint, already filled in, with a copy button.
Nothing here is Vercel-specific except vercel.json. It's a plain Node HTTP handler
(src/http.js), so any host that runs Node 20+ will do. npm run dev serves it on
localhost:8787.
Related MCP server: Code Box
Connect it
Claude web, desktop, mobile. Settings → Connectors → Add custom connector, paste the
/mcp URL. No authentication. Claude connects from Anthropic's cloud rather than from your
machine, which is why the endpoint has to be publicly reachable, and why this is hosted
rather than run locally.
Claude Code.
claude mcp add --transport http flint https://<your-deployment>.vercel.app/mcpCodex.
codex mcp add flint --url https://<your-deployment>.vercel.app/mcpor in ~/.codex/config.toml:
[mcp_servers.flint]
url = "https://<your-deployment>.vercel.app/mcp"Then ask for a chart: "chart my last six months of revenue by segment."
Or run it locally instead
For stdio hosts, meaning Claude Code and Claude Desktop, Microsoft's own server runs locally with no deployment at all:
claude mcp add flint -- npx -y flint-chart-mcpThat's the better option if local stdio is all you need. Deploy this one when you want a URL, for Claude web and mobile or for Codex, or when you want the tuned surface described below.
Tools
Tool | Use |
| Show a chart. Live and editable in Claude, a PNG everywhere else. The default. |
| Backend-native Vega-Lite / ECharts / Chart.js JSON, for artifacts and embedding. |
| Chart types with the channels and properties each accepts. |
What's different from upstream
The charts are unmodified. This calls flint-chart and flint-chart-mcp/render straight
off npm, and the interactive UI is upstream's own prebuilt flint-app.html. What changes
is the surface presented to the host.
One render_chart that is both interactive and static. Upstream ships five tools,
including a separate create_chart_view for the interactive path, and tells the model to
prefer it. On a host without MCP Apps that means announcing a chart and then displaying
nothing. Here a single tool is always registered as an MCP App and always returns a
rendered PNG. Claude draws the live widget with Flint's editing panel, while Codex and
everything else get the image, so neither ends up without a chart.
The catalogs live in the schema. Flint's 44 semantic types and its chart-type list are
declared as enums, read out of the installed package at import time so they cannot drift.
This matters because an unrecognised semantic type is ignored silently, with no warning,
and you quietly lose behaviour. { month: "YearMonth" } gives you a temporal axis, while a
plausible-looking "Month-Year" gives you unordered categories and says nothing. Both
hosts preserve the enums: Claude as JSON Schema, Codex as TypeScript string-literal unions.
Guidance lives in the server instructions, not in an MCP resource and not only in per-parameter descriptions. Neither host auto-reads resources, and Codex drops parameter descriptions entirely (see the gotchas below). Upstream ships a 567-line authoring skill as a resource that a chat host will never load.
No local file reads. This is a remote server, so its disk is not yours. Data is inline rows only.
/view is a static page that renders a spec client-side with tooltips and PNG/SVG export,
and render_chart links to it. The spec is raw-deflated into the URL fragment, which
browsers never send to a server.
Layout
api/mcp.js Vercel function → src/http.js
src/http.js Stateless Streamable HTTP transport
src/server.js Tools, schemas, instructions
src/catalog.js Semantic types + chart types, read from the installed flint-chart
src/app-ui.js Locates upstream's prebuilt MCP App UI bundle
src/share.js Spec → URL-fragment packing for the viewer
public/ Landing page, viewer, vendored Vega bundlesDevelopment
npm install
npm run dev # http://localhost:8787/mcp
npm test # 19 tests, no network
npm run vendor # refresh public/vendor after bumping flint-chartGotchas
Never gate MCP App registration on client capability over a stateless transport.
Claude declares io.modelcontextprotocol/ui only in initialize and never repeats it, so
on a stateless server every later request looks incapable:
initialize uiDeclared=true
tools/list uiDeclared=false <-- registers the plain tool
tools/call uiDeclared=falseThe app tool then never gets advertised and the widget never renders, however well the host
supports it. Register unconditionally instead, since the _meta is inert on hosts that
ignore it.
Always return the image too. Skipping the raster on app hosts to avoid a duplicate view sounds efficient right until the widget doesn't render, at which point the answer has a link and no chart. Claude renders the widget and ignores the image content, so the duplicate never materialises anyway, and Codex has no widget at all and needs the image.
Codex rewrites your schema as a TypeScript signature. Enums survive as string-literal
unions, which is what you want. Per-parameter description text does not survive at all,
though the server instructions and the tool description both do. Any guidance that has
to reach the model belongs in the instructions rather than in a parameter description.
GET /mcp must not return JSON. A GET carrying Accept: text/event-stream is a client
opening the optional server-to-client stream. A stateless server has nothing to push and
should answer 405. Returning 200 application/json instead can put the official MCP
TypeScript SDK client into a reconnect loop. Plain GETs still get a health blob.
framework: null in vercel.json is load-bearing. Left to auto-detect, Vercel reads a
bare package.json as its Node server preset, bundles the repo root into one function, and
every route including static files 500s into a lambda with no entrypoint (Invalid export found).
includeFiles is load-bearing too. The render path needs @resvg/resvg-js for
rasterising, @napi-rs/canvas for text metrics so label widths match the browser, and
flint-chart-mcp/assets/fonts for Liberation Sans. The font directory is resolved at
runtime by walking up from the module, which dependency tracing cannot see. Without it you
get charts with mismeasured labels.
Locking it down
The endpoint is open by default, which is what keeps setup to one paste. Anyone who learns
your URL can render charts on your account. Set FLINT_MCP_SECRET and the URL becomes the
credential:
vercel env add FLINT_MCP_SECRET productionThen use https://…/mcp?k=<secret> as the connector URL. Authorization: Bearer <secret>
works too, which suits Claude Code and Codex. The query form exists because some connector
dialogs accept nothing but a URL.
Data handling
Rows are compiled and rasterised in memory and returned as an image. Nothing is written to disk or a database, and the server reads no local files and fetches no URLs. The viewer is a static page whose spec rides in the URL fragment.
Flint is MIT-licensed, by Microsoft Research with IDEAS Lab, Renmin University of China. This connector is an independent wrapper and is not affiliated with Microsoft.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server that enables AI assistants to create, update, and publish Datawrapper charts through natural language. It provides tools for data synchronization, visual configuration, and retrieving chart images or editor links.Last updated8MIT
- Alicense-qualityDmaintenanceA self-hosted MCP server providing stateful code execution (Python/JavaScript) with SQL query support, file I/O, and artifact management, replacing Azure Code Interpreter.Last updatedMIT
- Alicense-qualityDmaintenanceMCP server that renders interactive Chart.js charts (bar, line, pie, doughnut, etc.) inline in Claude's UI.Last updated1MIT
- Flicense-qualityBmaintenanceA self-hosted MCP server that lets claude.ai delegate tasks to OpenAI Codex CLI, billed through the ChatGPT subscription, with tools for job submission, status polling, and result retrieval.Last updated
Related MCP Connectors
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Cloud-hosted MCP server for durable AI memory
Connect AI agents to Flato's editable canvas runtime through a hosted MCP server.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jmilinovich/flint-chart-connector'
If you have feedback or need assistance with the MCP directory API, please join our Discord server