Press enter or click to view image in full size
Most LLMs answer with a wall of text. On a good day you get a Mermaid diagram, and every Mermaid diagram looks like every other one: the same boxes, the same right angles, the same corporate blue. scribbleviz-mcp hands the model a different pen. It’s six tools that turn structured input into sketch-style graphics, the wobbly notebook look you get from matplotlib’s plt.xkcd(). Everything is drawn procedurally, including the icons, and rendered straight to an in-memory PNG. Nothing is ever written to disk. The result comes back as a native MCP ImageContent the client can show inline.
Picking a diagram is really picking a decision. A line says “watch this trend”, a 2×2 says “these are your options”, a concept map says “this causes that”. When the model can reach for the right shape instead of defaulting to prose, its answers get easier to scan. The clearest way to show what the tools do is to make them explain something real, so I asked for the one thing every keyboard runs on: coffee. One field guide, one page per tool, all in the warm sepia palette so it reads like a single notebook rather than seven screenshots.
How it works, in one paragraph
It’s a small, single-file Python MCP server with two dependencies (mcp and matplotlib) and no database, no browser, no temp files. Point any MCP client at it (Claude Desktop, Cursor, Cline, Continue, Zed, Windsurf) and the tools show up automatically. Each one takes plain structured arguments such as labels and values, dated events, nodes and edges, or quadrant contents, picks a palette, and hands back a PNG. There's no templating language to learn and no headless Chrome to babysit; the whole thing is stateless. The JSON snippets below are the exact tool calls that produced each picture in this post, so you can paste any of them into an MCP client and get the same image back.
1. The curve
Press enter or click to view image in full size
Caffeine hits fast and leaves slowly. It’s almost fully absorbed within 45 minutes, peaks in the blood roughly 30 to 60 minutes after a cup, and then decays on a half-life of about five hours. That long tail explains a lot of bad nights: an innocent 4 p.m. espresso still has about a quarter of its punch in your system at 9 p.m. A line chart is a good fit here, because the eye reads the steep climb and the slow fade as one gesture in a way a table of numbers never manages.
The star marks the peak. Any data point can carry a marker, either through the parallel icons list (one entry per value, "" to skip) or with an inline [icon] token. The same twenty hand-drawn glyphs are available on every tool, so a star here is stroked with the same wobble as a star on the timeline three sections down.
{
"chart_type": "line",
"title": "Caffeine in your bloodstream",
"labels": ["0h", "1h", "2h", "4h", "6h", "8h", "10h", "12h"],
"values": [0, 95, 88, 68, 52, 39, 30, 22],
"x_label": "hours after a cup",
"y_label": "caffeine (mg)",
"palette": "sepia",
"icons": ["", "star", "", "", "", "", "", ""],
"background": "white"
}2. The comparison
Press enter or click to view image in full size
Same tool, one different argument. Flip chart_type from line to bar and the caffeine story turns into a ranking instead of a trajectory: which drink actually hits hardest? A single shot of espresso (about 63 mg) carries less caffeine than a mug of drip coffee (about 95 mg), because drip uses far more water and contact time. Cold brew tops the chart by a wide margin, since long steeping extracts a lot, and decaf isn't zero, just close to it. Bars are the right shape when the question is "which is biggest", where a line would imply a trend that isn't there.
The bars are sorted low to high so the eye lands on the winner, and the bolt icon flags it. This is the same icons mechanism as the line chart, which is the practical benefit of one tool covering four chart types: you learn the arguments once and they carry over.
{
"chart_type": "bar",
"title": "Caffeine per serving",
"labels": ["Decaf", "Instant", "Espresso", "Latte", "Drip", "Cold brew"],
"values": [3, 62, 63, 68, 95, 165],
"x_label": "",
"y_label": "caffeine (mg)",
"palette": "sepia",
"icons": ["", "", "", "", "", "bolt"],
"background": "white"
}3. The history
Press enter or click to view image in full size
Coffee’s story is a chain of happy accidents. The legend starts in 9th-century Ethiopia with Kaldi, a goatherd who noticed his flock wouldn’t sleep after nibbling certain berries. From there it travels. Sufi shrines in Yemen brewed qahwa to stay awake through night prayers, coffee houses reached Europe in the 1600s and became hubs of gossip and business, the first espresso machine arrived in 1884, and a little shop opened in Seattle in 1971. Each beat is a when and a what, exactly the two fields a timeline wants.
generate_timeline alternates milestones above and below a single spine so the labels never collide, and each event carries its own icon through an inline [token] dropped into the text ([leaf], [drop], [home], [gear], [flag], [star]). The tool sizes the canvas to the number of events and leaves headroom for those icons, so nothing crowds the edges however many beats you pass in.
{
"title": "A short history of coffee",
"events": [
["9th c.", "Kaldi & the dancing goats [leaf]"],
["1450s", "Sufi shrines brew qahwa [drop]"],
["1600s", "Coffee houses reach Europe [home]"],
["1884", "First espresso machine [gear]"],
["1971", "A little shop in Seattle [flag]"],
["2000s", "Third-wave craft coffee [star]"]
],
"palette": "sepia",
"background": "white"
}4. The methods
Press enter or click to view image in full size
There is no single “right” way to make coffee. There’s a whole radial family of them, and they trade the same three levers in different proportions: pressure, contact time, and filtration. Espresso is all pressure and almost no time; cold brew is all time and no heat; pour-over leans on a paper filter for a clean cup; the French press skips the filter entirely for a heavier, sediment-rich body. A mind map fits a set of siblings like this: one central idea in the middle, variations spraying out around it, none of them first.
Get Carmine De Stefano’s stories in your inbox
Join Medium for free to get updates from this writer.
generate_mind_map takes a central_topic and a list of branches, where each branch is a label plus a short note, and lays them out evenly around the hub with no positioning math on your side. Reach for it when the relationship is "these all belong to that", as opposed to the ordered, this-then-that chain in the next section.
{
"title": "Ways to brew",
"central_topic": "Brewing",
"branches": [
["Espresso", "9 bar; ~30 s; crema"],
["Pour-over", "paper filter; clean cup"],
["French press", "full immersion; bold"],
["Moka pot", "stovetop; strong"],
["Cold brew", "12-24 h; low acidity"],
["AeroPress", "quick; forgiving"]
],
"palette": "sepia",
"background": "white"
}5. Bean to cup
Press enter or click to view image in full size
The mind map showed siblings; a process is different, because it has direction. A coffee cherry is picked and milled into a green bean, roasted into the brown bean you recognize, ground, hit with hot water, and poured. Each step transforms the one before it, and you can’t reorder them. When the story is a chain like that, this becomes that which becomes the next, a concept map with directed edges says it best, because the arrows carry meaning a plain list can’t. Every arrow here is labelled with the verb that gets you from one node to the next.
generate_concept_map takes nodes and edges, where each edge is [from, to, label], plus a directed flag that turns the connectors into arrows. It's the most general of the six tools, since anything you could draw as a labelled graph fits, which also makes it the one to reach for last, once you've ruled out the more specific shapes above.
{
"title": "From bean to cup",
"nodes": ["Cherry", "Green bean", "Roasted bean", "Grounds", "Brew", "Cup"],
"edges": [
["Cherry", "Green bean", "pick & mill"],
["Green bean", "Roasted bean", "roast"],
["Roasted bean", "Grounds", "grind"],
["Grounds", "Brew", "hot water"],
["Brew", "Cup", "pour"]
],
"directed": true,
"palette": "sepia",
"background": "white"
}6. The cheat-sheet
Press enter or click to view image in full size
Some knowledge just wants to be a sticky note on the wall. Not a trend, not a graph, just a handful of numbers you glance at while the machine warms up. The classic espresso recipe is exactly that: an 18 g dose in, about 36 g of liquid out (a 1:2 ratio), pulled in 25 to 30 seconds, with grind size as the dial you turn to hit that window. Too fast and it’s sour and thin; too slow and it’s bitter. That’s four labelled ideas with a couple of lines each, a cheat-sheet rather than a chart.
generate_sketch_note renders each section as its own labelled box, laid out in two columns and packed to fit, with an icon per heading (target, gear, clock, bulb). Use it for reference material like a recipe, a checklist, or a set of definitions, where the items don't connect to each other and you just want them legible at a glance.
{
"title": "How to pull a good shot",
"sections": [
["Dose [target]", "18 g in; 36 g out"],
["Grind [gear]", "fine; adjust to taste"],
["Time [clock]", "25-30 seconds"],
["Tips [bulb]", "fresh beans; clean basket; even tamp"]
],
"palette": "sepia",
"background": "white"
}7. Pick your brew
Press enter or click to view image in full size
Two questions decide most cups: how much time you’re willing to give it, and how much body you want. Cross those as axes and the brewing methods sort themselves into four corners: quick-and-intense espresso in one, slow-and-heavy French press in another, fast-and-clean AeroPress for travel, delicate pour-over and cold brew for a nuanced cup. A 2×2 works as a small decision tool, because it doesn’t only list the options, it also shows why each one lands where it does.
generate_quadrant takes the two axis labels and the four quadrants (each a heading plus a few lines), and it's the same engine behind a SWOT, an Eisenhower matrix, or any "compare on two dimensions" prompt. Flags like headings_outside and icon_focus let it swing from a text-heavy analysis to an all-icon poster, but the core idea stays the same: position carries the argument.
{
"title": "Pick your brew",
"x_axis": "contact time: quick -> slow",
"y_axis": "body: light -> full",
"quadrants": [
["Espresso", "9 bar; ~30 s; intense"],
["French press / Moka", "full immersion; heavy"],
["AeroPress", "fast; clean; travel"],
["Pour-over / Cold brew", "delicate; nuanced"]
],
"palette": "sepia",
"background": "white"
}Why sketch-style?
A crisp, precise chart says dashboard: this is final, audited, don’t touch. A wobbly one says notebook: here’s a rough idea, follow along, question it. That lower-stakes feeling is what you want when an assistant is explaining something rather than reporting it. It reads like thinking out loud, not like a finished report you’re expected to accept.
It also keeps things consistent. Because the icons are drawn with the same jittered stroke as the boxes, the lines and the arrows, nothing looks pasted in from a different app, and there’s no clip-art star sitting awkwardly on a clean vector chart. Seven pictures, one hand. And since it all renders through matplotlib to an in-memory buffer, there’s no browser to launch and no file to clean up. The model calls a tool and gets a picture back.
Try it yourself
git clone https://github.com/cadeos/scribbleviz-mcp.git
cd scribbleviz-mcp
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txtThen register it in your MCP client, using the same command and args shape everywhere. Point command at the venv's Python so mcp and matplotlib are on the path, and use absolute paths:
{
"mcpServers": {
"scribbleviz": {
"command": "/absolute/path/to/scribbleviz-mcp/.venv/bin/python",
"args": ["/absolute/path/to/scribbleviz-mcp/server.py"]
}
}
}Restart the client and the generate_* tools appear. Hand your model a brief such as "explain X" and let it reach for the right page.
Contribute
The project is open source and small enough to read in one sitting, which makes it easy to extend. If you have an idea, the repo welcomes pull requests. A few directions that would fit well: new color palettes, more hand-drawn icons, extra chart types, better auto-layout for dense diagrams, or examples in other languages. Bug reports and issues are just as useful, so open one if something renders wrong or a tool signature trips you up. Star the repo if it was handy, fork it, and send your changes back.
Repo: github.com/cadeos/scribbleviz-mcp · MIT licensed