Give your model a deterministic, reviewable creative layer instead of asking it to hallucinate pixels. A tool invocation is just a URL with parameters - a few tokens that produce a press-quality file, the same way every time. No image model, no creative drift - and driven locally (URL or CLI), no data leaving the device. The hosted MCP endpoint is the one server-side path, covered below and inventoried on Server Surface.
Machine-readable entry points
Start here rather than scraping pages. Each file is generated by the docs build from the same sources the human pages come from, and each is served at the site root as well as under /info/.
| File | What it is for |
|---|---|
/agents.md | The short version of this page for a machine reader: entry points, the URL grammar, how to get bytes and the rules that save a round trip. |
/llms.txt | The docs index in the llms.txt convention - one line per page, linking its markdown twin. |
/llms-full.txt | Every docs page in one file, in the index's order, for a reader that wants the whole corpus in one fetch. |
/.well-known/lolly.json | The discovery record: where the catalog, the manifests, the render route, the MCP endpoints and the files above live on this deployment. |
/openapi.json | The HTTP surface in OpenAPI 3.1 - the hot-link render route with its refusals, the catalog and manifest reads and the MCP endpoint's transport. |
/info/capabilities.json | Format claims: what Lolly reads and writes per format and what each format's own metadata carries. |
/catalog/tools/index.json | The generated tool index; /tools/<id>/tool.json is one tool's manifest with every input, default and format. |
/info/skills/lolly/SKILL.md | The agent skill: one page an agent loads to drive Lolly across every surface, with references for URL mode, the surfaces, the whole catalogue, the three document tools (chart, design, deck) and renovating an old deck into the design system (Rebrand). |
The same set exists on every deployment, so an agent pointed at a self-hosted instance discovers that instance's own endpoints from its own well-known record.
Fast path for a model
When a model points at one Lolly instance, use the smallest path that answers the task:
- Read the instance discovery record and request only the relevant tool or format.
- Describe the chosen tool or template and build a stack plan from its declared inputs.
- Validate and render in one workflow when the instance supports that combined call.
- Return the artifact, editable recipe, checks and one next action.
For a known recipe, do not enumerate the whole catalog or repeat validation as a separate call. For a revision, send stable layer patches or changed inputs instead of the whole document. A result is complete when its declared checks pass. Ask for human review only when the task states a requirement this instance cannot measure, such as physical print appearance or subjective approval. Otherwise report the result and continue.
Keep these outcomes distinct: complete, partial, approximate, blocked, failed and unknown. Say what changed, what was preserved, what was checked and what remains unknown. Never describe an unchecked property as passed.
The model: a URL is the API
Every tool is fully described by its URL. The agent's job is to build that URL (or the equivalent CLI command) from structured inputs:
https://<host>/#/tool/<tool-id>?<input>=<value>&<input>=<value>Open it and the tool renders with those inputs applied. Add reserved params to control output and trigger a download. For a pinned tool, profile, asset set and supported format, the same inputs reproduce the same recipe result; formats with timestamps, browser encoding or external resources have narrower guarantees described by the format documentation.
signed by Lollyvector SVGCheck it yourselfGet the signed file1 path~1.4k nodes12 KBTry it in the app
Use Lolly to generate a QR code:
tool: qr-code
url: "https://example.com"
format: svg
Return the editable file URL and the exact inputs used.Discover a tool's inputs
Don't guess parameters - read them. The tool's manifest (tools/<id>/tool.json) lists every input id, type and default, or use the CLI:
pnpm run cli qr-code # prints inputs, defaults, and supported formats
pnpm run cli # lists every available toolFeed that schema to the model so it only emits valid inputs.
Reserved parameters
These are the common ones; anything outside the full reserved set is a tool input. (Full reference: URL Mode.)
| Param | Effect |
|---|---|
format | Output format (png, svg, pdf, mp4, …) |
export | Presence flag - render and download immediately on load |
copy | Presence flag - copy the result to the clipboard on load |
width / w, height / h | Output size (value in unit) |
unit, dpi | Physical sizing (mm/cm/in/pt) + raster resolution |
bleed, marks | Print bleed and crop marks |
profile | Colour profile - raster ICC (srgb/none) or CMYK press condition |
filename, output | Download filename / CLI output path |
password | Lock the exported PDF |
_v | Pin the tool version for stable output |
slot | Open a saved session |
The complete reserved set also includes full, options, c2pa, imprint, durable, meta, hdr, depth, cuts, lang, designv, template, nostage, z and zx; everything else is forwarded to the tool as an input. (The engine's RESERVED set in engine/src/url-mode.ts is the source of truth - see URL Mode.)
So a one-shot, ready-to-download link is just:
/#/tool/qr-code?url=https://suse.com&format=svg&exportGetting an actual file
- Interactive / in a browser session: append
&export(or©) - the file downloads (or goes to the clipboard) on load. - Headless / server-side automation: use the CLI - it's the same parameter surface and writes bytes to a file or stdout:
pnpm run cli qr-code --url=https://suse.com/kubecon --color=0c322c \ --export=svg --output=./qr.svg
(The lean node CLI renders SVG and text/data formats; raster/PDF/video need the desktop-bundled build - see CLI.)
Pipe stdout straight into another step in your pipeline.
A few tools won't hand back a file this way:
- Non-exporting utilities (
countdown-timer,strip-data,text-helper,compress-pdf) setrender.export: false-&export/©are no-ops. (color-paletteis not one of them: the community Palette Lab declaressvg,png,jpg,webp,csv,json,css,scss,gplandase. A brand pack can narrow any community tool's declared formats, so read the manifest - orlolly_describe_tool- rather than assuming.) - Experimental tools (those with
status: "experimental"in their manifest) watermark every export until they're promoted, so their output isn't press-clean yet. - File-input tools like
strip-datatransform the user's own bytes in memory; they need a file the agent can't supply through a URL (see the device-local note below).
The MCP server (native endpoint)
Beyond building URLs by hand, Lolly ships an optional Model Context Protocol server - a native endpoint any MCP client (an agent runtime, an IDE, a CLI, a hosted assistant) connects to directly. It exposes the catalogue and the render path as callable tools, so an agent can discover a tool, fill its declared inputs and get back a finished file plus an editable lolly.tools link - with no app update, because tools sync to the server as data.
Core workflow verbs:
| Tool | Does |
|---|---|
lolly_list_tools | List / search the catalogue (by text, status, category, format or capability); use limit to keep discovery small. |
lolly_describe_tool | One tool's full input JSON Schema, built-in templates/presets, supported formats, canvas size and examples. |
lolly_validate | Validate inputs and return path-specific errors before a compile, URL build or render. Design also returns its artboard/layer tree and structural findings. |
lolly_compile / lolly_inspect / lolly_measure | Compile once, inspect the semantic document and measure it without rasterising. |
lolly_measure_text | Where a Design text box's lines break and how tall it is, before it is drawn, with the faces the canvas loads. The same measure as lolly measure --text. |
lolly_package | A Design document as a .lolly the app reopens as the same document, with the pictures you supply and its name. The same writer as lolly package. |
lolly_compose | Slides laid out from the design system's slide master: name an archetype per slide and fill its slots, and get a Design document with the master's margins, type, furniture and bindings, so its PowerPoint export has real slide layouts and placeholders. mode: "list" gives the archetypes, mode: "suggest" drafts a spec from a deck. The same composer as lolly compose. A hosted server receives a deck passed as source. |
lolly_build_url | Build a shareable, editable link + raw render URL - without rendering. |
lolly_render | Render a tool to a file (returns the bytes plus the editable link). |
lolly_transform | Run an on-device file utility (strip-data, compress-pdf) on a file you supply. |
lolly_redact | Redact regions of an image, SVG or PDF on-device - covered content is destroyed and the file rebuilt, so nothing is recoverable underneath. |
lolly_verify | Verify a file's Content Credentials (C2PA) - the verdict, signer identity, edit history and embedded metadata. Checked in-process, never stored. |
lolly_rebrand | Renovate an old .pptx deck into the active design system, in stages (capabilities, plan, compile, inspect) - see reference/rebrand.md. Processed in memory, never stored; capabilities states where a deck you send would go before you send one. |
lolly_read | Read what a deck says (.pptx, PDF or .psd), slide by slide: text in reading order with roles, speaker notes with their paragraphs, pictures by hash with placement, tables and charts. The same reader as lolly read. Processed in memory, never stored. |
lolly_check | Check a Design document, a .lolly or an export in one findings list: structure, render, brand and house rules, Verify, and fidelity to the source deck. Each finding has a stable code, the layer id and the message the app shows; exitCode matches lolly check. Read the lolly://design-context resource first for the design brief. |
lolly_look | Look at a render with a labelled grid in document units (for Design, a layer's own x, y, w, h), or one region of it enlarged. Never an export. |
lolly_sample_color | Read the colours at points and name the nearest design-system colour with its distance. |
lolly_trace_edges | A render's or image's edges as polylines, optionally as ready Design path layers. |
For Design, prefer templateId plus an optional presetId and a small set of input overrides. lolly_describe_tool lists those starting points; the same arguments work with validate, compile, inspect, measure, URL building and render. Inspect the template once to discover its stable layer IDs, then send layerPatches: [{ "id": "s1title", "set": { "text": "Your title" } }] to replace content without resending layer geometry. This lets an agent start from, for example, a slide deck or square poster without inventing raw coordinates.
Use layerOperations to change the layer set itself. It supports strict stable-ID add, duplicate, remove, reparent and reorder operations. Reorder anchors must be siblings. Reparent preserves the layer's geometry and accepts a destination artboardId (null means the pasteboard), plus an optional destination sibling anchor. Every duplicate takes an explicit newId; duplicating a non-empty artboard also requires a complete childIds map. Removing a non-empty artboard requires cascade: true. Operations run before layerPatches, so a newly created or moved layer can be patched in the same call:
{
"toolId": "design",
"templateId": "slide-deck",
"layerOperations": [
{
"op": "add",
"layer": { "id": "s1-kicker", "kind": "text", "frame": "slide1", "text": "Draft" },
"afterId": "s1title"
}
],
"layerPatches": [
{ "id": "s1-kicker", "set": { "text": "Agent-added context" } }
]
}Design layers may also carry authoring keys, which start with $ and are lowered to ordinary layers before anything else runs: $in gives a position relative to an artboard, $style sets text by a named style from the design brief, $points and $d draw a path in px, and $stack, $grid and $table lay out repeated rows. The stored document stays in global canvas coordinates with every field written out. The agent skill's Design reference describes every key.
Any format, transparently
lolly_render returns whatever format the tool declares - the server picks how to produce it, and the agent never has to know which engine ran:
- Vector -
svg,pdf,pdf-cmyk,eps,emf,dxf(cut file) - Raster -
png,jpg,webp,avif,tiff,cmyk-tiff,ico - Animation -
gif,apng,webp-anim,svg-anim(vector),webm,mp4 - Documents & data -
pptx(PowerPoint),html,md,txt,json,csv,ics,vcf,zip
Formats are per-tool - you can only request one a tool declares (lolly_describe_tool lists them). Ask a QR tool for svg and you get vector; ask an animated-ad tool for mp4 and you get video - the call is identical either way.
Connect a client
The open endpoint, no token. Anyone can connect to https://lolly.tools/api/mcp: vector and data output, plus png for SVG-native tools, with no sign-in. Calls are limited per address and by a daily budget for the whole endpoint. In Claude Code:
claude mcp add --transport http lolly https://lolly.tools/api/mcpAny other client takes a config entry like:
{
"mcpServers": {
"lolly": { "type": "http", "url": "https://lolly.tools/api/mcp" }
}
}The full endpoint, with a token. https://mcp.lolly.tools/mcp renders every format, and authenticates against a shared access token that your Lolly operator holds (the token is never printed in a link or a log). Connect it one of two ways. Full reference, including the open endpoint's limits: the MCP Server page.
A custom connector (OAuth). The full endpoint is also a stateless OAuth 2.1 authorization server, so it drops straight into any MCP client that supports custom connectors:
- In your client's connector settings, add a custom connector pointing at
https://mcp.lolly.tools/mcp. (Hosted assistants usually expose this under a Connectors or Integrations panel; on team/enterprise plans an admin typically adds it once for everyone.) - Leave the OAuth Client ID / Secret blank - the server registers your client automatically (dynamic client registration).
- The client auto-discovers the OAuth server and opens a consent page. Paste the access token and approve - done.
Nothing is stored server-side: the client registration, the authorization code and the tokens are all short-lived signed values verified with a shared secret on each call (PKCE-protected, so a leaked link can't be replayed).
A bearer token (CLI / any HTTP client). The full endpoint also accepts the raw token directly, so scripted clients skip the OAuth dance. Most MCP clients take a config entry like:
{
"mcpServers": {
"lolly": {
"type": "http",
"url": "https://mcp.lolly.tools/mcp",
"headers": { "Authorization": "Bearer <your-access-token>" }
}
}
}(Or run it locally over stdio during development - no token needed.)
A hosted add-on - not offline or edge
The MCP server is the one part of Lolly that is a server-side add-on, not an on-device component. Producing the full format range - animations, print PDF, HTML-layout raster - means driving a headless browser against a built web shell, so the full endpoint runs as a hosted service and is not suitable for offline or edge deployments. That full endpoint is live at https://mcp.lolly.tools/mcp; the lightweight serverless endpoint at lolly.tools/api/mcp runs the browser-free tier only (vector, data and PNG for SVG-native tools). The on-device shells - web PWA, desktop, mobile and CLI - remain the offline / air-gapped path. See the MCP Server page for the full reference.
Why this beats prompting an image model
- Quality doesn't drift. Layout, type, colour and spacing are structural - hard-coded by the tool author, not prompted. A lazy model can't degrade them.
- Cheap. A parameterised URL is a handful of tokens versus thousands for a brief + generation - and the result is production-grade.
- Deterministic & auditable. Every output is reproducible from its inputs; pin
_vfor byte-stable results across tool updates. - Private by default. It runs on the device - no customer data sent to a third-party model or service.
Tips
- Pin
_vin automation so a tool update can't silently change output. - Compact encodings: some tools define short
urlKeyaliases and tilde-delimited arrays to keep links short - see URL Mode. - Call
lolly_validatebefore rendering. MCP compile/build/render calls now reject unknown fields and invalid values with exact paths. Hand-authored URL mode remains tolerant for backward compatibility, so validate explicitly before emitting a raw URL yourself. - Device-local images (user uploads) can't travel in a URL - agents should reference catalog assets by id, not local uploads.
- One tool, many outputs: change
format/unit/widthto emit the same design as SVG, print PDF and social MP4 from one set of inputs. - Portable embed URL: an agent can emit
https://lolly.tools/tool/<id>.<ext>?<inputs>(image extensionspng,jpg,jpeg,webp,svg, plus animatedgifandapng) and drop it straight into HTML as an<img src=…>. Inside the live web view it renders locally - nothing fetched. On the open web the same URL is served for real by deployments that leave hot-link renders enabled (live onlolly.tools) for the browser-free formats (svgfor every tool,pngfor SVG-native ones), so those links work as plain hot-linked images in READMEs and wikis - see MCP Server for that endpoint's scope and current state.