Skip to content
Connect an agent
Workflows

draw_diagram

Checks, describes, and draws a diagram. It is a workflow of the MCP server and the HTTP API, with the title "Draw diagram".

TL;DR

QuestionAnswer
What is it?A workflow: one call does the work of several tools and returns one combined answer.
What does it do?Checks, describes, and draws a diagram.
What does it replace?validate_diagram, outline_diagram and render_diagram calls.
How do I call it over HTTP?POST /v1/diagrams/draw
Does it change anything?No. It is read-only and idempotent, and it talks to nothing outside itself. It saves no file and returns its answer as data.
Which bounds apply?maxSummaryOutlineLines. See the bounds below.
Where do I read its schema as data?An MCP client gets the name, description, and JSON Schema of every tool from tools/list.

What it does

Workflow. Checks, describes, and draws a diagram. With errors it returns each one with line, column, and a fix hint and draws nothing: fix the source and call again. When valid it returns the quality warnings (take the icon and group-type suggestions), an outline to check the meaning, the size, and the SVG for light, dark, or both. The pictures are most of an answer and you cannot see them: pass svg "never" to check, and draw only to save, show, or publish. Give viewUrl to the person, even after svg "never"; pngUrl and svgUrl download it; saveCommand, when given, saves it in a repository. A big drawing (about 30 nodes) loses its SVGs, dark first, and picturesOmitted says so; svg "always" forces them. Set embedSource true to save an SVG in a repository or publish one to edit later, so read_diagram gives the source back (anyone with the file can read it). detail "full" adds the whole outline. To change an existing diagram use edit_diagram, or read_diagram for a picture. Saves no file; never throws on bad source. Replaces the validate_diagram, outline_diagram and render_diagram calls.

Steps

OperationRunsWhat it does
validatealwaysParse the source and lint it: every error, and the quality, icon, and group-type warnings.
outlineonly when neededDescribe a valid diagram as plain text.
renderonly when neededLay out and paint a valid diagram in one color scheme.

One call performs at most 4 operations.

Example call

The arguments of the call, as JSON:

json
{  "source": "flow \"Login\" direction=right\nnode user person \"User\"\nnode api service \"Auth API\"\nnode db database \"Users DB\"\nuser -> api : \"POST /login\"\napi -> db : \"look up user\"",  "themes": "both"}

The source argument, written out one line at a time:

Plotwork
flow "Login" direction=rightnode user person "User"node api service "Auth API"node db database "Users DB"user -> api : "POST /login"api -> db : "look up user"

Prompts that lead to it

  • Draw a diagram of how a user signs in through an API that checks a database.
  • Check this diagram and draw it in light and dark.

Arguments

FieldTypeRequiredDescription
sourcestringyesDiagram source. The first line is the header: flow "Title", sequence "Title", schema "Title", git "Title", gantt "Title", class "Title", state "Title", timeline "Title", journey "Title", mindmap "Title", treemap "Title", pie "Title", quadrant "Title", layers "Title", c4 "Title", matrix "Title", sankey "Title", xychart "Title", tree "Title", or swimlane "Title". at least 1 character; at most 50000 characters.
themes"light" | "dark" | "both"nolight, dark, or both (the default): the light picture and the dark one a dark page needs. default "both".
detail"summary" | "full"nosummary (the default), or full: the whole outline, and the source embedded in each SVG. default "summary".
svg"auto" | "always" | "never"noauto (the default) returns the SVGs, but over MCP leaves them out when the answer would be too big for a client (picturesOmitted). always returns them at any size. never draws nothing, which is cheaper. The HTTP API treats auto as always. default "auto".
embedSourcebooleannoWrite the source into each SVG so read_diagram can give it back. Set it when you save the SVG in a repository or publish it to edit later; anyone with the file or link can then read the source. default false.
settingsobjectnoThe repo's plotwork.config.json, if any. Schema: https://docs.plotwork.dev/schemas/plotwork.config.json (opens in a new tab).

Result

FieldTypeRequiredDescription
validbooleanyesTrue when the source has no errors. When false, nothing was drawn: fix the errors and call again.
kindstring | nullyesThe diagram kind, or null when the header could not be read.
errorsDiagnostic[]yesEvery error found in one pass, each with line, column, and a hint. Empty when valid.
errors[].code"E100" | "E101" | "E110" | "E111" | "E120" | "E121" | "E122" | "E123" | "E124" | "E125" | "E130" | "E131" | "E132" | "E133" | "E134" | "E135" | "E136" | "E137" | "E138" | "E139" | "E140" | "W200" | "W201" | "W202" | "W203" | "W204" | "W205" | "W206" | "W207" | "W500" | "M100" | "M101" | "M102" | "M103" | "M104" | "M110" | "M200" | "M201" | "M202" | "M203" | "M204" | "M205" | "M206" | "M207" | "M208" | "M209" | "M210" | "M211" | "M212" | "M213" | "M214" | "M215" | "M216" | "M217" | "M218" | "E300" | "E301" | "E302" | "E303" | "E304" | "W300" | "W301" | "W302" | "W303" | "M120" | "M220" | "M221" | "M222" | "E340" | "E341" | "E342" | "E343" | "E344" | "E345" | "W320" | "W321" | "W322" | "W323" | "M240" | "M241" | "M242" | "E360" | "E361" | "E362" | "E363" | "E364" | "E365" | "E366" | "E367" | "W330" | "W331" | "W332" | "W333" | "W334" | "M250" | "M251" | "E400" | "E401" | "E402" | "E403" | "W350" | "W351" | "W352" | "W353" | "M270" | "M271" | "E420" | "E421" | "E422" | "E423" | "E424" | "W360" | "W361" | "W362" | "W363" | "W364" | "M180" | "M280" | "M281" | "M282" | "E320" | "E321" | "E322" | "E323" | "E324" | "E325" | "E326" | "E327" | "E328" | "E329" | "E330" | "W310" | "W311" | "W312" | "W313" | "W314" | "M130" | "M131" | "M132" | "M230" | "M231" | "M232" | "M233" | "M234" | "M235" | "M236" | "M237" | "M238" | "E380" | "E381" | "E382" | "E383" | "W340" | "W341" | "W342" | "W343" | "M260" | "I100" | "I101" | "I102" | "I103" | "I104" | "I105" | "I200" | "I201" | "I202" | "I203" | "I204" | "I206" | "R100" | "R101" | "R200" | "R201" | "R202" | "R203" | "R204" | "R205" | "R206" | "R207" | "S100" | "S200" | "S101" | "S102" | "S103" | "S104" | "S201" | "S202" | "S203"yesStable code to branch on; E-codes are errors, W-codes are warnings.
errors[].severity"error" | "warning"yesErrors stop rendering; warnings never do.
errors[].messagestringyesWhat is wrong, in one sentence.
errors[].lineintegeryes1-based line in the submitted source. minimum 1.
errors[].columnintegeryes1-based column in that line. minimum 1.
errors[].lengthintegeryesNumber of characters the problem covers. minimum 1.
errors[].hintstring | nullyesA concrete suggestion for fixing it, or null.
warningsDiagnostic[]yesQuality warnings for a valid diagram: too dense, too wide, text cut, unconnected nodes, and suggestions for an icon or a group type. Empty when invalid.
warnings[].code"E100" | "E101" | "E110" | "E111" | "E120" | "E121" | "E122" | "E123" | "E124" | "E125" | "E130" | "E131" | "E132" | "E133" | "E134" | "E135" | "E136" | "E137" | "E138" | "E139" | "E140" | "W200" | "W201" | "W202" | "W203" | "W204" | "W205" | "W206" | "W207" | "W500" | "M100" | "M101" | "M102" | "M103" | "M104" | "M110" | "M200" | "M201" | "M202" | "M203" | "M204" | "M205" | "M206" | "M207" | "M208" | "M209" | "M210" | "M211" | "M212" | "M213" | "M214" | "M215" | "M216" | "M217" | "M218" | "E300" | "E301" | "E302" | "E303" | "E304" | "W300" | "W301" | "W302" | "W303" | "M120" | "M220" | "M221" | "M222" | "E340" | "E341" | "E342" | "E343" | "E344" | "E345" | "W320" | "W321" | "W322" | "W323" | "M240" | "M241" | "M242" | "E360" | "E361" | "E362" | "E363" | "E364" | "E365" | "E366" | "E367" | "W330" | "W331" | "W332" | "W333" | "W334" | "M250" | "M251" | "E400" | "E401" | "E402" | "E403" | "W350" | "W351" | "W352" | "W353" | "M270" | "M271" | "E420" | "E421" | "E422" | "E423" | "E424" | "W360" | "W361" | "W362" | "W363" | "W364" | "M180" | "M280" | "M281" | "M282" | "E320" | "E321" | "E322" | "E323" | "E324" | "E325" | "E326" | "E327" | "E328" | "E329" | "E330" | "W310" | "W311" | "W312" | "W313" | "W314" | "M130" | "M131" | "M132" | "M230" | "M231" | "M232" | "M233" | "M234" | "M235" | "M236" | "M237" | "M238" | "E380" | "E381" | "E382" | "E383" | "W340" | "W341" | "W342" | "W343" | "M260" | "I100" | "I101" | "I102" | "I103" | "I104" | "I105" | "I200" | "I201" | "I202" | "I203" | "I204" | "I206" | "R100" | "R101" | "R200" | "R201" | "R202" | "R203" | "R204" | "R205" | "R206" | "R207" | "S100" | "S200" | "S101" | "S102" | "S103" | "S104" | "S201" | "S202" | "S203"yesStable code to branch on; E-codes are errors, W-codes are warnings.
warnings[].severity"error" | "warning"yesErrors stop rendering; warnings never do.
warnings[].messagestringyesWhat is wrong, in one sentence.
warnings[].lineintegeryes1-based line in the submitted source. minimum 1.
warnings[].columnintegeryes1-based column in that line. minimum 1.
warnings[].lengthintegeryesNumber of characters the problem covers. minimum 1.
warnings[].hintstring | nullyesA concrete suggestion for fixing it, or null.
summarystring | nullyesOne-line description of the diagram, usable as alt text; null when invalid.
outlinestring[]yesThe diagram as plain text in reading order, to check it says what you meant; empty when invalid.
outlineTruncatedbooleanyesTrue when the summary level cut the outline short. Call again with detail "full" to read all of it.
sizeSize | nullyesNatural size of the laid-out diagram; null when invalid.
qualityQualitynoHow clean the picture looks (score, grade, measures) and up to three changes that would help; read it instead of looking. Absent when invalid.
quality.scoreintegeryes0 to 100; 100 is a picture with nothing to fix. The same diagram always gets the same score. minimum 0; maximum 100.
quality.grade"clean" | "fair" | "cluttered"yesclean is 85 or more, fair 60 or more, cluttered below.
quality.measuresobjectyesWhat the score is made from: crossings, lineOverBox, labelOverlaps, smallestTextPx (in an 880px column), aspectRatio, emptySpace (0 to 1), longestLine (px), detour (1 is straight), the counts of boxes, lines, labels, series, and slices, and any measure the kind adds.
quality.hintsstring[]yesUp to three changes, the one worth most first, each naming the statement or option to edit.
quality.linestringyesThe grade, the score, and the first hint in one line.
noticesNote[]noInformation notes, such as an icon alias drawn as the real icon; absent when there is none.
notices[].codestringyesA stable code, such as I122 for an icon alias.
notices[].severity"info"yesA note never stops a drawing and is not a warning.
notices[].messagestringyes
notices[].lineintegeryesminimum 1.
notices[].columnintegeryesminimum 1.
notices[].lengthintegeryesminimum 1.
notices[].hintstring | nullyesThe text to write instead.
rendersobject[]yesOne picture per requested color scheme, light first; empty when invalid, when svg is never, and when every picture was left out (see picturesOmitted).
renders[].theme"light" | "dark"yesThe color scheme this picture is drawn in.
renders[].svgstringyesSelf-contained SVG markup with an accessible title and description.
renders[].sizeSizeyesNatural size of a rendered diagram in px.
renders[].size.widthintegeryesWidth in px. minimum 1.
renders[].size.heightintegeryesHeight in px. minimum 1.
picturesOmittedobjectnoPresent only when pictures were left out because the answer would have been too big for an AI client to read in one piece.
picturesOmitted.themes("light" | "dark")[]yesThe color schemes whose pictures were left out.
picturesOmitted.charactersintegeryesHow many characters the pictures left out came to.
picturesOmitted.limitintegeryesThe most characters one answer may hold before the pictures are left out.
picturesOmitted.whystringyesWhy they were left out, and what to do.
viewUrlstringnoA link that shows a valid diagram in a browser; give it to the person who wants to look. The source is in the part after #, never sent to a server, but anyone with the link can read it. Absent when too long; next says so.
pngUrlstringnoThe viewUrl with &download=png: opening it in a browser saves the diagram as a PNG for Slack, email, or a wiki. The PNG is drawn in the person's browser, not on a server, so it is a link to open, not an image address to embed. Absent when too long.
svgUrlstringnoThe viewUrl with &download=svg: a person opens it to download the SVG. Not a file address for curl; use saveCommand. Absent when too long.
saveCommandstringnoRun in a shell to save the SVG into the repository: the CLI decodes the link locally, fetches nothing, and embeds the source. Set --out to the path; add --theme dark for dark. Absent when too long.
nextstringyesThe next step in one sentence.

Behavior hints

HintValue
readOnlyHinttrue
destructiveHintfalse
idempotentHinttrue
openWorldHintfalse

Bounds

A bound that is reached is reported in the result; nothing is cut silently.

BoundValueWhat it limits
maxSummaryOutlineLines40Outline lines in a summary; detail "full" returns all of them.

See also

DocWhy
Tool referenceEvery tool, with the workflows first
POST /v1/diagrams/drawThe same operation over HTTP
Language referenceWhat the diagram source may contain
Writing diagrams with an agentThe loop in practice