Reference · MCP server 0.2.0
ohmyartifact reference
Everything a model needs to read and write ohmyartifact artifacts: the markdown formats, the overlay JSON schema, and each MCP tool with its parameters, result and error messages. Style rules (what makes a good slide) are in the server's authoring guide, oma://guide, and are not repeated here.
endpoint http://localhost:8080/mcptransport Streamable HTTP, statelessauth none
Slide decks
A deck is one markdown string. Slides are separated by a line containing only ---. Each slide is markdown, optionally followed by exactly one fenced ```overlays block holding a JSON array of positioned elements on a 1280×720 canvas.
### Summary
# Three numbers that matter
Availability beat the SLO for the fourth straight quarter while request volume grew 2.4×.
```overlays
[
{"type":"stat","slot":"bottom","value":"99.97%","caption":"Availability · SLO 99.9%","color":"terracotta"},
{"type":"stat","slot":"bottom","value":"184 ms","caption":"p95 latency · −31% QoQ"},
{"type":"stat","slot":"bottom","value":"0","caption":"Sev-1 incidents · 2 last quarter"}
]
```
---
### Incidents
# One root cause behind both Sev-2s
…
Parsing rules
- A leading YAML frontmatter block (
--- … --- at the very top) is stripped and ignored.
- A
--- line inside any fenced code block is content, not a separator. Empty chunks between separators are dropped. A deck always has at least one slide.
- The overlays block is
```overlays on its own line, the JSON array, then ```. Only one per slide is parsed; whatever precedes and follows it is the slide body.
- A slide's body starts with an optional
<!-- background: URL --> line for a full-bleed background image (URL or data: URL). Removing the line removes the image.
Stored form
Every write re-serializes the deck: each slide is its trimmed body, then (if present) a blank line and the overlays fence with every element given an id; slides are joined with \n\n---\n\n and the deck ends with a newline. read_artifact returns this form, so old_text for edit_artifact must be copied from it.
How slide markdown renders
| Markdown | Renders as |
### Label directly above # Title | Small uppercase accent eyebrow. |
# Title | Serif headline; one per slide. |
| paragraph, bullets | Body copy in the left column at 22px. The body narrows to the left column when anything sits in a right-side slot. |
> quote | Accent callout. |
| pipe table | Card table. |
```mermaid | A diagram, converted to ```drawing on save. |
<!-- background: URL --> | Full-bleed background image behind the slide. |
Slide tools (replace_slide, insert_slide) take the markdown of one slide, without --- separators, and validate it the same way.
Overlays schema
The ```overlays block is a JSON array. Each element is one of five types, selected by type. The full JSON Schema (draft 2020-12) is served as the resource oma://schema/overlays; the server validates every write against it, choosing the variant by type so errors name the field that is wrong. Elements without an id get one on save. Keep the id of any element you were given so the app can tell an edit from a replacement.
Placement (all types)
| Field | Type | Description |
| id | string | Stable id; generated when omitted. Preserve it on edits. |
| slot | enum | Where to place the element. Use this instead of coordinates. Several elements in bottom sit side by side; several in right stack. |
| x | number 0–1280 | Left edge in px on the 1280×720 canvas. Only for exact placement; an element with x/y instead of slot was pinned by a person — leave it alone. |
| y | number 0–720 | Top edge in px. |
| width | number > 0 | Optional explicit width. |
| height | number > 0 | Optional explicit height. |
| rotation | number = 0 | Degrees clockwise. |
Slots
righttop-rightbottombottom-leftbottom-right
text
| Field | Type | Description |
| typerequired | "text" | |
| textrequired | string, non-empty | The text. |
| fontSize | number 12–120 = 32 | A label such as INTERNAL or DRAFT is a text in top-right at 16. |
| color | tone = none | none is plain text; terracotta an accent callout (at most one per slide); ivory/sand a neutral card; ink a dark card; blue/green/amber/red a tag or status. |
{"type":"text","slot":"top-right","text":"INTERNAL","fontSize":16,"color":"blue"}
stat
| Field | Type | Description |
| typerequired | "stat" | |
| valuerequired | string, non-empty | The big number, e.g. "99.97%". |
| caption | string | Small label under the value; carries the unit and the delta. |
| color | tone = ivory | Card tone. |
{"type":"stat","slot":"bottom","value":"184 ms","caption":"p95 latency · −31% QoQ"}
panel
| Field | Type | Description |
| typerequired | "panel" | |
| bodyrequired | string, non-empty | Markdown: paragraphs, **bold**, *italic*, `code`, ~~struck~~, - bullets, 1. steps. An indented line under a list item is that item's caption. |
| eyebrow | string | Small uppercase label above the title, e.g. COST OF CHANGE. |
| meta | string | Small mono text right-aligned on the eyebrow row, e.g. 3 files. |
| title | string | Headline; one line, states the point. |
| footer | string | Mono line under a divider at the bottom, e.g. events › actions › providers. |
| color | tone = terracotta | Accent of the edge, eyebrow and code. ink makes the whole panel dark. |
| edge | "top" | "left" = top | Which side carries the accent line. |
{"type":"panel","slot":"right","eyebrow":"OPTION B","meta":"3 files","title":"Read-through cache",
"body":"- Adds one hop on a miss\n ~4 ms at p95\n- Invalidation stays in the writer",
"footer":"edge › cache › api","color":"blue","edge":"left"}
image
| Field | Type | Description |
| typerequired | "image" | |
| srcrequired | string (uri) | Image URL or data: URL. |
| alt | string | Alternative text. |
{"type":"image","slot":"right","src":"https://example.com/architecture.png","alt":"Request path after the cache"}
card
| Field | Type | Description |
| typerequired | "card" | |
| itemsrequired | array of text | stat | panel | Independent items laid out side by side. Items carry their own type-specific fields (and an optional id) but no placement: no slot, x, y, width, height or rotation. |
| tone | tone = none | Background box around all items; none means no box, the items float together. |
{"type":"card","slot":"bottom","tone":"sand","items":[
{"type":"stat","value":"2.4×","caption":"Request volume YoY"},
{"type":"stat","value":"+0.8%","caption":"Infra spend QoQ","color":"green"},
{"type":"text","text":"Reserved capacity absorbed the growth.","fontSize":20}
]}
Tones
The one enum behind color on text/stat/panel and tone on card:
noneplain, no box
ivoryneutral card
sandneutral card, warmer
inkdark card, once per deck
terracottathe accent, once per slide
bluetag / status
greentag / status
ambertag / status
redtag / status
Validation
- The block must be a JSON array of objects. Each object's
type selects its schema; an unknown type is rejected.
- Required fields, enums and numeric ranges are enforced exactly as listed above. Fields outside the schema are not validated.
- Failures are collected per element and reported together as
invalid content, prefixed with slide N: in deck-wide writes. Nothing is saved.