drawspec
drawspec
Declarative diagram spec → clean, themeable SVG. Writable by an LLM with no coordinates to get wrong.
For anyone — person or language model — who puts diagrams in docs, specs and READMEs and is tired of arrows that miss their boxes:
pip install drawspec && drawspec render diagram.json -o diagram.svgSee every kind drawn in the gallery →
Status: it draws. All thirty-six kinds render —
flow,tree,cycle,stack,timeline,columns,matrix,pyramid,rings,funnel,chart,quadrant,scatter,curve,files,states,sequence,lanes,entities,gantt,board,fishbone,venn,journey,treemap,sankey,numberline,barmodel,waterfall,pie,mindmap,argument,familytree,meter,ragandclock— and each of the eleven failure families below has a test asserting it cannot be expressed. The vocabulary opened from nine to thirteen on evidence: seedocs/kinds-wanted.md, which sorts all 89 hand-drawn originals by the kind that would have to draw them.scatteris the fourteenth, added on a different kind of evidence: a real consumer's need for two continuous, ticked axes, whichquadrantrefuses.filesis the fifteenth: a directory listing drawn from its paths, as pictures or as thetree-style text a code block wants.statesis the sixteenth: a state machine, with its initial and final dots, labelled transitions, self-loops, and a refusal for any state nothing reaches.sequenceis the seventeenth: messages between participants, in order, with activation bars inferred from each call and its reply.lanesis the eighteenth: aflowdocument whose actors are drawn as swimlanes, so every hand-off between parties is an arrow crossing a lane.entitiesis the nineteenth: ER models, database schemas and class diagrams as one kind — boxes of fields, relations that can land on one row, crow's feet or multiplicities at the ends, and inheritance with a hollow triangle.ganttis the twentieth: a plan, one row per task, with phases, milestones, finish-to-start dependencies and marks such as today — on a numbered axis in a unit you name, never dates.boardis the twenty-first: cards sorted into columns — a kanban board with work-in-progress limits drawspec counts, a retrospective, or a story map whose releases are slices across the columns with a heavy cut under the first.fishboneis the twenty-second: one effect and the causes investigated, grouped by category on bones slanting into a spine — the root cause drawn heavy.vennis the twenty-third: two or three equal circles (four equal ellipses), each region's words named by the sets it is in and placed inside it — no coordinates, no sizes.journeyis the twenty-fourth: one person's feeling, a named level per stage, drawn as a line through every stage over what they do there — no scores.treemapis the twenty-fifth: the parts of one known total, each a rectangle by its area with its label inside it — a few proportions stated, not explored.sankeyis the twenty-sixth: where a known quantity goes, each flow a band as thick as its amount, columns derived from the flows — a few flows stated, not explored.numberlineis the twenty-seventh: values and ranges on one scale, each end of a range in or out of it — an inequality, the pH scale, a spectrum; not when, which istimeline.barmodelis the twenty-eighth: a word problem as bars of parts in proportion, braced with their checked totals — the bar model, or tape diagram, of primary maths.waterfallis the twenty-ninth: how one total became another, step by step, every subtotal checked against the running sum — the bridge chart of a budget paper.pieis the thirtieth: the shares of one known total as labelled sectors — a few proportions stated, as on atreemap, with a donut as a theme's choice.mindmapis the thirty-first: a topic in the middle and its branches round it as peers, nested three deep and balanced on two sides — where atreewould rank them.argumentis the thirty-second: a claim and the points for and against it, tagged and hatched by stance, co-premises under one bracket — the argument map of a law or critical-thinking course.familytreeis the thirty-third: people, the couples they form and their children, a generation to a row and numbered for you (II-3), in the standard's symbols — the pedigree of a genetics clinic, and the family tree of a history lesson.meteris the thirty-fourth: one amount against its scale — a progress bar, a fundraising thermometer, a dial or a bullet graph, alone or a few to a panel, every band named in words.ragis the thirty-fifth: workstreams or risks rated red, amber or green — a highlight report, a risk register — each rating a word and a shape, never colour alone, with its trend written in words.clockis the thirty-sixth: analogue clock faces showing a time, for teaching it — the hour hand moving on with the minutes, the time in words under each face or hidden for a worksheet, and how long since an earlier time shaded round the face. Aflowalso draws a causal loop diagram: a sign on every arrow, delay marks, and named loops marked R or B, the type derived from the signs, never written.
The problem
Language models draw diagrams by emitting SVG with absolute x/y
coordinates, and they fail at the same things every time: arrows with a head
but no shaft, text that escapes its box, lines that stop short of the shape
they point at, a different font size in every element.
These are not failures of judgement. In a corpus of 87 LLM-written diagrams
reviewed by a human, 63 drew a complaint, and every one was about placement,
not content — nobody disputed what the diagram said, only where things ended
up. See docs/brief.md for the measured breakdown.
Placement failures cannot be reviewed away: a cheap mechanical check over finished SVG catches 17 of those 63 and misses 46. They have to be made impossible to express.
Related MCP server: diagram-mcp
The approach
The author writes what the diagram means — nodes, edges, labels, and a semantic role for each. Everything that can be got wrong without seeing the result is not in the format at all:
The author writes | The tool decides |
Nodes, edges, labels | Coordinates, box sizes, canvas size |
A semantic role per node | Font family and size, colour, stroke weight |
Grouping and diagram type | Edge routing, anchor points, arrowheads |
An optional size budget | Overlap resolution, label placement |
Output is SVG that can be pasted inline into a Markdown document: colour
inherited from the surrounding page, no global <style>, no ids that collide
when two diagrams share a page, and no information carried by colour alone —
so it survives dark mode and greyscale printing. For anywhere an SVG cannot go —
a chat, a slide, an attachment — the same drawing comes out as a PNG on a light,
dark or transparent background (pip install 'drawspec[png]', one self-contained
wheel; no PDF, no JPEG). And for where no picture draws — a terminal, a commit
message, a code block — twelve kinds, flows and state machines among them, come out
as plain text, box-drawing or ASCII: 80 columns, 100 for swimlanes and sequences,
or whatever --width you give.
A small sequence, sequence-terminal.json, as
drawspec render docs/reference/sequence-terminal.json --format text draws it, and
with --charset ascii added:
┌───────┐ ┏━━━━━━━━━━┓
│ Shell │ ┃ drawspec ┃
└───┬───┘ ┗━━━━┯━━━━━┛
│ flow.json │
├─────────────▶┃
│ the drawing ┃
│◁┄┄┄┄┄┄┄┄┄┄┄┄┄┤
│ │+-------+ #==========#
| Shell | # drawspec #
+---+---+ #====#=====#
| flow.json |
+------------->#
| the drawing #
|<<............+
| |What it looks like
Three documents and the drawings they produced. Nothing was positioned by hand,
and every one of these is a file in docs/reference/ that
make gallery renders — so the picture is always the render of the spec beside
it.
A flow
{
"version": 1,
"kind": "flow",
"title": "Triaging a report",
"nodes": [
{"id": "arrive", "text": "A report arrives", "role": "start"},
{"id": "repro", "text": "Does it reproduce?", "role": "decision"},
{"id": "fix", "text": "Schedule a fix", "role": "step"},
{"id": "ask", "text": "Ask for the document", "role": "terminal"}
],
"edges": [
{"from": "arrive", "to": "repro"},
{"from": "repro", "to": "fix", "label": "yes"},
{"from": "repro", "to": "ask", "label": "no"}
]
}The role on each node is the only appearance decision in the file, and it is a
semantic one: start and terminal came out as pills and decision as a
diamond because the theme says those roles look like that. Change the theme and
every diagram in your project changes with it.
A timeline
The thirty-six kinds are the part people do not expect, so here is one that is not a box-and-arrow diagram at all:
{
"version": 1,
"kind": "timeline",
"title": "How the work went",
"items": [
{"text": "Brief", "note": "March"},
{"text": "Specification", "note": "April"},
{"text": "Plan", "note": "May"},
{"text": "Foundation", "note": "June to July"},
{"text": "Kinds", "note": "August"}
]
}Above the line is what happened; below it is when. That is what note means on a
timeline, and it is the only kind that draws one.
A chart
{
"version": 1,
"kind": "chart",
"title": "Where the tickets went",
"axes": {
"horizontal": { "label": "Quarter", "min": 0, "max": 5 },
"vertical": { "label": "Incidents" }
},
"series": [
{ "name": "Platform", "mark": "bar", "data": [[1, 34], [2, 41], [3, 28], [4, 22]] },
{ "name": "Service desk", "mark": "bar", "data": [[1, 52], [2, 47], [3, 55], [4, 38]] },
{ "name": "Still open", "mark": "line", "data": [[1, 12], [2, 18], [3, 9], [4, 6]] }
]
}No colours are named anywhere in that file. The series are told apart by fill
pattern as well as by hue, which is what lets the same drawing survive greyscale
printing — a theme is checked against that invariant by drawspec theme check.
There are no coordinates in any of them, and none may be written. x,
font_size, stroke and twenty-odd other fields are refused by name, with the
JSON pointer of the place they were written. A document may size the whole canvas
— width and height at the top level — and may not size one box in it.
Try it
pip install drawspec # or drawspec[png] for PNG export
drawspec render diagram.json -o diagram.svg # or to stdout
drawspec render diagram.json -o diagram.png # needs drawspec[png]; --background dark, --scale 3
drawspec render diagram.json --theme blueprint -o sheet.png # on a drafting sheet, like the banner
drawspec render diagram.json --format text # plain text, 80 columns; --charset ascii
drawspec validate diagram.json # every violation, by JSON pointer
drawspec theme check default # including the greyscale invariant
drawspec theme from site.css -o house.toml # a theme from your brand's CSS or design tokens
drawspec schema --out drawspec-v1.schema.json # for editor completionPut "$schema": "https://nuncaeslupus.github.io/drawspec/schema/drawspec-v1.schema.json" at the top
of a document and any editor with JSON Schema support completes the fields and
flags a refused one while you type it, rather than after a render.
The gallery
Every kind, drawn, on one page →
One document per kind lives in docs/reference, and make gallery renders every one of them into docs/gallery/index.html, which is what
that link publishes. It is the fastest way to see the whole vocabulary, and the
fastest way to see what a change did — looking at it is how four rendering
defects were found that no gate had caught.
It is committed as well as published, so a diff shows what a change did to the pictures.
Every kind is drawn to the theme's one canvas width, and a diagram narrower than
it is centred in it rather than cropped to its own ink. That is what makes the
three above the same type size at the same column width — and it is the whole
reason the width belongs to the theme. Set [canvas] width_mode = "ink" for a
diagram meant to be sized on its own.
Every kind is also framed alike: [canvas] margin is the blank between the
drawing and the edge of the figure, one number applied in one place. Before it
existed each family invented its own, so a timeline above a flow chart bled to
the edge beside the flow's quarter-inch of white.
What it is not
drawspec draws simple, declarative diagrams well, and it is the wrong tool for several jobs it might look like it does.
It is not a Graphviz replacement. Graphviz is a graph-layout engine with decades of work behind its layered and force-directed placement, and it will lay out a hundred-node graph that drawspec refuses. drawspec's layout exists to serve thirty-six named diagram shapes at the sizes a document reads at; past each kind's readability budget (fifteen boxes on a
flow) it will tell you to split the diagram into an overview and details rather than produce something dense and unreadable, which is deliberate but is not what a graph tool does.It is not charting software.
charthas lines, bars, areas, stacks, point labels and a legend. It has no statistics, no interactivity, no dates, no log scales, no error bars, and no second axis. If you are exploring data, use a plotting library; if you are stating a small number you already know, this draws it in the same ink and at the same type size as every other diagram on the page, which a plotting library will not.treemapandsankeyare held to the same line: ten parts and one level of groups at most, every part labelled inside itself; fourteen nodes in four columns, every flow balanced and thick enough to see — a few proportions and flows you already know, not a disk-usage explorer or a flow analyser.It is not a drawing program. A document has no coordinates in it, on purpose — see The approach above. Anything whose whole point is where things are (a floor plan, a map, a picture of two overlapping Wi-Fi cells) has no declarative description, and drawspec should decline it rather than pretend.
It is not a rich-text system. Text carries
**bold**and`code`spans and nothing else.
What it is good at is the long tail of ordinary explanatory diagrams — the kind that fills a set of course notes, a design document or a runbook — drawn consistently, reviewably, and without an author ever choosing a coordinate.
Documentation
The guide is the way in, and it is meant to be enough on its own — install, a first diagram, choosing a kind, embedding the output, validating in a build, and writing a theme. Under it sit three references, each generated from the code it describes, so none of them can quietly go out of date:
Page | What it answers |
Every field a document may carry, by kind — and every field that is refused, with the reason | |
Every command, argument and exit code | |
Every key a theme may set, and what the default sets it to |
make docs regenerates all three; a test fails if what is committed is not what
the code would write, which is the same arrangement the published JSON Schema
has.
If you are an agent, or pointing one here
AGENTS.md is the whole format on one page — whether to draw
at all, which kind fits what the reader must understand, the readability budget,
the roles, worked examples, and what each refusal is telling you to do. It is written to be read in a single pass rather than navigated, which is
what the guide and the references are for. llms.txt is the index
that points at it.
And if your client speaks MCP, pip install 'drawspec[mcp]' gives you
drawspec-mcp: validate, render and kinds as tools, so a refusal arrives as
{"pointer": "/edges/0/to", "message": …} in the model's own loop instead of as
prose on stderr it has to read. Same checks, same messages, no shell. See
the guide.
For agents that load Agent Skills, copy
skills/drawspec/ into your skills directory: a
short pointer that installs drawspec, reads AGENTS.md, and validates before rendering.
It cannot drift either: a test asserts that every kind in the vocabulary is named in it, that every role the theme declares appears, and that every example in it is a document that still validates. An agent copying from a stale brief is the failure that file exists to prevent, so it is held to the same standard as the generated references.
Repository layout
Everything you would look in, and the two directories you can ignore.
Path | What |
| The library and CLI — |
| Everything written. The four entries below are the ones worth knowing apart |
| Using drawspec in another project: install, first diagram, embedding, theming |
| The three generated references. |
| One document per kind — the examples, and what the gallery and the acceptance suite both render |
| The rendered gallery: |
| The originating brief: the problem, the measured failure taxonomy, the acceptance tests. |
| The published JSON Schema, versioned and addressable. Copied into the wheel from here, so there is only ever one of it |
| 87 anonymized LLM-written diagrams and their measurements, as evidence |
| An Agent Skill that points an agent at drawspec — install, read |
| The suite. |
| Development scripts, not shipped: the docs generator, the gallery builder, and the checkers — |
| The origin documents: the specification this was built from, and its plan. Kept because |
| Development machinery for the agent workflow this is built with — task queue, session protocol, vendored skills. Nothing here affects the package; skip both if you are reading the project rather than working on it |
Development
make sync # install with dev extras
make lint # ruff + strict mypy
make test # pytest
make gallery # render every reference document and look at it
make docs # regenerate the format, CLI and theme references
make schema # regenerate the published JSON SchemaRelated projects
Built with claude-arsenal, the spec-driven Claude Code workflow and gated task queue this repo is developed on — whose spec and design skills draw their diagrams as drawspec documents. Same author:
claude-arsenal — a Claude Code skill and plugin marketplace: specs before code, failing tests first, gates with numbers.
integral-job-search — a candidate-centred job search run as a conversation in Claude Code.
literary-critic — lets an LLM index, analyse and advise on a full novel manuscript the way a professional editor would.
doc-control — a deterministic tool for AI agents to edit Word documents as tracked changes (in development).
License
MIT — see LICENSE.
Available Tools
3 toolskindsList the diagram kindsARead-onlyIdempotent
The vocabulary: every value kind may take and what each one is for. Takes no arguments. Read this before choosing a kind — several of them are not box-and-arrow diagrams and are easy to miss.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, so safety is covered; the description adds genuine behavioral context by warning that several kinds 'are not box-and-arrow diagrams and are easy to miss,' steering the agent away from a wrong assumption. It does not describe the return format, but the annotations and the 'vocabulary' framing carry most of that burden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with what the tool is, then the arity, then the usage directive. Every sentence earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter enumeration tool with no output schema, the description tells the agent what the tool returns ('every value `kind` may take and what each one is for') and when to consult it. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are no parameters, so the baseline is 4. The description correctly states 'Takes no arguments,' matching the empty schema, adding no confusion.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific resource — 'the vocabulary: every value `kind` may take and what each one is for' — which is unambiguous and distinct from the sibling tools validate and render. It lacks an explicit verb of its own (the title supplies 'List'), but the intent is clear without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear directive: 'Read this before choosing a kind,' which tells the agent exactly when to call it. No when-not condition or named alternative is offered, but for a zero-argument vocabulary lookup the trigger is fully sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
renderRender a drawspec document to SVG, PNG or textA
Draw the document and return the SVG. The output is safe to paste inline into a Markdown page: no global styles, no colliding ids, and no meaning carried by colour alone. With format png it returns a PNG image instead, for a chat, a slide or an attachment (needs the server's drawspec[png] extra); with format text, the diagram as plain text, for the kinds that have a text form. Refuses with located violations exactly as validate does.
| Name | Required | Description | Default |
|---|---|---|---|
| scale | No | png only: pixels per SVG unit (default 2). | |
| theme | No | A bundled theme name or a path to a theme file. Omit for the default. | |
| width | No | Override the document's width. With format `text`, the most terminal cells a line may take (default 80, or 100 for `lanes` and `sequence`). | |
| format | No | svg (default), png, or text: the diagram as plain text for a code block or a terminal, for the kinds files, tree, sequence, gantt, timeline, board, stack, rag, meter, flow, states, lanes. | |
| height | No | Override the document's height. | |
| charset | No | text only: box-drawing characters, or ASCII only (default unicode). | |
| document | Yes | A drawspec document, as JSON. The full field list is published at https://nuncaeslupus.github.io/drawspec/schema/drawspec-v1.schema.json, and `kinds` names the 36 values `kind` may take. | |
| background | No | png only: the page the drawing is on (default light). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the inline-paste safety properties (no global styles, no colliding ids, no colour-only meaning), the optional `drawspec[png]` server extra required for PNG, and the failure mode (refuses with located violations like validate). It stops short of stating idempotence/read-only nature or any cost/size limits on large renders.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the default behavior ('return the SVG') and the safety guarantee before covering the png/text variants and error behavior. Every clause earns its place; the png parenthetical is dense but necessary information, not padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter tool with a nested `document` object, no output schema and no annotations, the description covers output formats, the external schema URL for the document shape, safety characteristics, and error behavior. It leaves the actual return payload structure (what the SVG response object looks like) unstated, which is the main remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter including scale, theme, width, height, charset, background and format is already documented in the schema. The description only reinforces the format branches and the png extra requirement, adding no syntax or format detail beyond structured fields, which matches the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Draw the document and return the SVG') and immediately enumerates the three output modes with their formats. It also positions itself against a sibling by noting it refuses with violations 'exactly as `validate` does', so an agent can tell render apart from validate/kinds without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for each format branch: png 'for a chat, a slide or an attachment', text 'for a code block or a terminal'. However it never explicitly says when to call this instead of validate (e.g. 'call validate first if you want errors without output'), so the routing against the primary sibling is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validateValidate a drawspec documentA
Answer whether render would refuse this document, and if so exactly where. Returns every violation, not the first — each located by JSON pointer, so one pass is one edit. Call this before render while a document is being written.
| Name | Required | Description | Default |
|---|---|---|---|
| theme | No | A bundled theme name or a path to a theme file. Omit for the default. | |
| document | Yes | A drawspec document, as JSON. The full field list is published at https://nuncaeslupus.github.io/drawspec/schema/drawspec-v1.schema.json, and `kinds` names the 36 values `kind` may take. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and delivers the key behavior: it reports every violation rather than stopping at the first, and each is located by JSON pointer for single-pass editing. It doesn't state that the operation is non-mutating or describe the shape of an individual violation object, but the behavioral essentials are present.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core question ('would render refuse this, and where'), then return semantics, then timing. Every sentence earns its place; nothing is repeated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must cover return values, and it does convey that all violations come back with JSON pointer locations. For a nested-object validator it could go slightly further on the per-violation fields, but an agent has enough to invoke and interpret it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both `document` and `theme` are already documented — including the schema URL and the 36 `kind` values. The description adds no parameter-level detail beyond what the schema provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (validate/answer) and resource (a drawspec document), and frames it precisely against the sibling `render` — it answers whether render would refuse the document and where. An agent can distinguish this from `render` and `kinds` without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to call it before `render` while a document is being written, which names the alternative and the triggering condition. It stops short of stating when not to call it (e.g., after a clean validation or on already-rendered output), so it is clear context rather than full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
kinds - First observed
render - First observed
validate
TDQS
Scored across 3 tools
validate and render are mostly distinct (one checks, one draws), but both return located violations, so an agent could plausibly reach for render while drafting and lose the stated benefit of validate. kinds is clearly separate as the vocabulary lookup. The boundary is workable but not perfectly crisp.
All three names are single lowercase tokens with no style mixing (no camelCase/snake_case clash), which is predictable. However, the set mixes parts of speech—two imperative verbs (validate, render) and one bare noun (kinds)—so it is not a true verb_noun convention.
Three tools is on the lean side but each earns its place: validate for pre-flight checks, render for output, kinds for discovery. For a focused document-to-SVG service this is well-scoped rather than padded or thin.
The core lifecycle—learn the vocabulary (kinds), check the document (validate), produce output (render)—is fully covered, and documents live outside the server so CRUD is unnecessary. Minor gaps remain, such as no way to introspect the full document schema beyond the kind vocabulary or to fetch worked examples.
Maintenance
Related MCP Connectors
Render, validate, encode/decode PlantUML diagram-as-code; 22 diagram types. Free, no auth.
Create, validate, edit, export (markdown/svg/png/mermaid), and search JSON Canvas files.
- mcpOAuthcom.slickfast
JSON in. Chart or Page out. Same picture forever. Scientific plots included.
Immutable agent diagrams: create, edit, validate and render versioned diagrams over MCP.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables creating and iterating on animated SVG diagrams from text input, photos of sketches, and YAML specifications, with support for shapes, connections, SMIL animations, and file output.16 PyPI1MIT
- AlicenseAqualityCmaintenanceRenders diagram-as-code to PNG files on your disk, and also provides text-art previews and syntax validation, all locally without a browser or network.48 npmMIT
- FlicenseBqualityBmaintenanceEnables creating and maintaining technical diagrams from .dot sources, with validation, rendering to SVG/PNG/PDF, and publishing into Markdown while automatically partitioning oversized graphs.6-
- AlicenseNot gradedqualityBmaintenanceTurns structured JSON content into resolved, audited infographic plans and renders them as SVG or executable Figma Plugin API scripts, exposing theme packs, grammars, planning, auditing and export tools over stdio. Also lets hosts inspect theme provenance and layout decisions so different tools produce identical frames.MIT