{
  "name": "drawnui-fiddle",
  "version": "1.0.0",
  "protocol_version": "2025-06-18",
  "description": "Search, read and publish DrawnUI snippets: C# or React that compiles in the browser and draws a user interface on a real canvas - the C# runs unmodified on .NET MAUI, Blazor and OpenTK, the React in any web app.",
  "documentation": "https://drawfiddle.com/docs/",
  "capabilities": {
    "tools": true,
    "resources": false,
    "prompts": false,
    "logging": false,
    "streamable_http": true
  },
  "endpoints": {
    "jsonrpc": "https://drawfiddle.com/mcp"
  },
  "authentication": {
    "type": "none"
  },
  "tools": [
    {
      "name": "search_snippets",
      "description": "Search the DrawFiddle community catalogue: published C# and React snippets that draw a user interface on a real canvas. Use it to find a working example of a control, a layout or an effect before writing DrawnUI code from scratch.",
      "input_schema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Words to look for in the title and description. Omit to list everything."
          },
          "tag": {
            "type": "string",
            "description": "Restrict to one tag, e.g. \"game\", \"ui\", \"chart\", \"shaders\"."
          },
          "kind": {
            "type": "string",
            "enum": [
              "all",
              "fiddle",
              "app"
            ],
            "description": "Default all."
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "description": "Default 10."
          }
        }
      }
    },
    {
      "name": "get_source",
      "description": "Return the complete C# source of one snippet, with its title, description and links. The code compiles as-is in the fiddle and runs unmodified in .NET MAUI, Blazor and OpenTK.",
      "input_schema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Snippet id, as returned by search_snippets."
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "create_fiddle",
      "description": "Publish a snippet and get back a permanent link that anyone can open, run and edit. It does NOT check that the code compiles — call validate first, because every distinct source publishes to its own permanent link and there is no delete. No account needed. Two languages: C# compiled by Roslyn in the browser (the default), or TSX drawn by DrawnUi.React, the same controls under the same PascalCase names. C#: the last expression returns the control, `return new SkiaLabel { Text = \"hi\" };`. TSX: the module exports the component, `export default function App() { return <SkiaLabel Text=\"hi\" />; }` - no import lines, the controls and the React hooks are already in scope. Identical code always yields the same link, so re-publishing is safe.",
      "input_schema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The source."
          },
          "lang": {
            "type": "string",
            "enum": [
              "csharp",
              "tsx"
            ],
            "description": "Which language the code is in; default csharp. A TSX snippet gets an id starting with \"r\", and every reader takes the language from that."
          },
          "description": {
            "type": "string",
            "description": "One line describing what it draws. Shown on the share preview."
          },
          "tags": {
            "type": "string",
            "description": "Comma separated, e.g. \"ui,chart\"."
          }
        },
        "required": [
          "code"
        ]
      }
    },
    {
      "name": "create_draft",
      "description": "Start a piece of work in progress. Returns one draft id you can overwrite as many times as you like — the equivalent of the editor tab a person works in before pressing share. A draft is private to whoever holds its id, is not listed anywhere, has no preview image and disappears 24 hours after the last edit. THIS IS THE RIGHT PLACE TO ITERATE: publishing every attempt instead mints a separate permanent link each time, and there is no delete. The draft runs at /d/{id} — OPEN THAT IN YOUR OWN BROWSER AND SCREENSHOT IT if you can. That is free, unlimited, live and interactive, and it always shows the current code.",
      "input_schema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Starting C#. Optional — you can create an empty draft and fill it in."
          }
        }
      }
    },
    {
      "name": "update_draft",
      "description": "Replace the code in a draft. Same id, as many times as you need, and each edit resets its 24-hour life. Reload /d/{id} in your browser afterwards to see the change — nothing is cached, so it always runs what you just wrote.",
      "input_schema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Draft id from create_draft."
          },
          "code": {
            "type": "string",
            "description": "The new C#, replacing what was there."
          }
        },
        "required": [
          "id",
          "code"
        ]
      }
    },
    {
      "name": "preview_draft",
      "description": "NOT A MOTION-QUALITY TOOL: the clock is sampled coarsely (a 320 ms tween may be seen at 0.00, 0.14 then 1.00), so this answers \"what state did it reach\", never \"is the curve smooth\". Render a draft on the server and return the image itself, plus anything the snippet printed with Console.WriteLine WHILE IT RAN — including from gesture handlers and animation callbacks, not just at startup — so you can check which branch ran or what a value came out as, the things a picture cannot show. Optionally drive it first with taps, drags and scrolls (see `actions`) to reach state that is behind a gesture. USE THIS ONLY IF YOU HAVE NO BROWSER: opening /d/{id} yourself is free, unlimited, interactive and shows the live animation, while this spends server compute and shares a small hourly budget. Nothing is stored either way — a draft never gets a thumbnail or a link preview.",
      "input_schema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Draft id."
          },
          "at_ms": {
            "type": "integer",
            "minimum": 0,
            "maximum": 5000,
            "description": "Where to capture on the animation timeline, in milliseconds. Default 1000. A point on a synthetic clock, not a wait — 3000 costs exactly what 0 costs. Use it when your snippet fades, slides or builds up, because at 0 those draw an empty canvas."
          },
          "width": {
            "type": "integer",
            "minimum": 16,
            "maximum": 1600,
            "description": "Canvas width, default 900. Use a real target width when you are checking a layout."
          },
          "height": {
            "type": "integer",
            "minimum": 16,
            "maximum": 1600,
            "description": "Canvas height, default 600."
          },
          "actions": {
            "type": "array",
            "description": "Drive the interface BEFORE the picture is taken, so you can photograph a drawer that is open, a sheet that is up, a tab that is selected — state that does not exist at any point in time on its own. Do NOT edit the snippet to start in that state instead: that changes the thing you are measuring. Actions run in order on the same synthetic clock, so the same list always produces the same frame, and at_ms is then measured from the end of the last one. Every action reports what it actually hit — the control type, or \"nothing\" — so a mistyped coordinate is distinguishable from a handler that does not work.",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "tap",
                    "pan",
                    "wheel",
                    "key",
                    "wait"
                  ],
                  "description": "tap: press and release. pan: a drag — drawers, sheets, swipes, scrolls. wheel: mouse wheel. key: keyboard, for snippets that read arrows or WASD. wait: just advance time."
                },
                "x": {
                  "type": "number",
                  "description": "tap/wheel: x in canvas pixels from the left."
                },
                "y": {
                  "type": "number",
                  "description": "tap/wheel: y in canvas pixels from the top."
                },
                "fromX": {
                  "type": "number",
                  "description": "pan: where the finger goes down."
                },
                "fromY": {
                  "type": "number"
                },
                "toX": {
                  "type": "number",
                  "description": "pan: where it lifts."
                },
                "toY": {
                  "type": "number"
                },
                "durationMs": {
                  "type": "number",
                  "description": "pan: how long the drag takes, default 200. Shorter means faster, which matters for flings."
                },
                "steps": {
                  "type": "integer",
                  "description": "pan: how many move events, default 12."
                },
                "delta": {
                  "type": "number",
                  "description": "wheel: negative scrolls down, default -120."
                },
                "key": {
                  "type": "string",
                  "description": "key: which key. Names as you would say them — \"left\", \"right\", \"up\", \"down\", \"w\", \"a\", \"s\", \"d\", \"space\", \"enter\", \"esc\", \"shift\" — or the exact InputKey name such as \"ArrowLeft\" or \"KeyW\"."
                },
                "action_type": {
                  "type": "string",
                  "enum": [
                    "press",
                    "down",
                    "up"
                  ],
                  "description": "key: default \"press\" (down then up). Use \"down\" and a later \"up\" to hold a key while time passes, which is how a game reads movement."
                },
                "after_ms": {
                  "type": "integer",
                  "description": "Time to let run after this action before the next one — use it to let an animation finish. Default 0, or 300 for wait."
                }
              },
              "required": [
                "type"
              ]
            }
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "publish_draft",
      "description": "Turn a finished draft into a real fiddle: a permanent link anyone can open, run and edit. This is the only step that creates something lasting, so do it once, at the end. The draft itself stays until it expires. Identical code always produces the identical link.",
      "input_schema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Draft id."
          },
          "description": {
            "type": "string",
            "description": "One line describing what it draws. Shown on the share preview."
          },
          "tags": {
            "type": "string",
            "description": "Comma separated, e.g. \"ui,chart\"."
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "validate",
      "description": "Does this C# compile as a DrawnUI snippet? Returns the exact errors the editor would show, with line numbers. Nothing is published, nothing is stored, nothing is rendered and not a line of the code is executed — so it can never return Console.WriteLine output; use preview_draft for that. USE THIS WHILE YOU ITERATE — it is the cheap call. Publishing or asking for a picture to find out whether code builds is the expensive way round.",
      "input_schema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The C# source, same shape as create_fiddle."
          },
          "lang": {
            "type": "string",
            "enum": [
              "csharp",
              "tsx"
            ],
            "description": "Only C# can be checked here: the compiler is Roslyn on our server. Pass \"tsx\" to be told so plainly instead of receiving C# errors about a React component."
          },
          "draft_id": {
            "type": "string",
            "description": "Validate the current contents of a draft instead of passing code."
          }
        }
      }
    },
    {
      "name": "get_preview",
      "description": "Return the preview image of a snippet: an actual frame of what the code draws. If the snippet has no picture yet — which is the case for anything created through create_fiddle — one is rendered on the server, stored as that snippet's thumbnail and reused by everyone from then on (the community card, link previews, the /show page). IF YOU CAN RENDER LOCALLY, DO THAT INSTEAD: open the player URL this tool returns in a browser you control and screenshot it. That path is free, unlimited and gives you a live canvas you can interact with; this one spends server compute and is capped.",
      "input_schema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Snippet id."
          },
          "at_ms": {
            "type": "integer",
            "minimum": 0,
            "maximum": 5000,
            "description": "Where to capture on the animation timeline, in milliseconds. Default 1000. This is a point on a synthetic clock, not a wait: the renderer advances the animation to that moment and draws one frame, so asking for 3000 costs the same as asking for 0. Use it when your snippet fades, slides or builds up — at 0 those draw an empty canvas."
          }
        },
        "required": [
          "id"
        ]
      }
    }
  ]
}