Skip to main content
This page is the get_authoring_guide tool rendered for people. The MCP server returns the same content as JSON.

Workflow

You (the agent) draft the JSON; your user publishes it. Produce a widget or theme following this guide, hand the JSON to your user, and direct them to https://widgentic.dev — sign in, open the widget, theme, or Data schemas designer, use Import, review, and save. The entry appears in their own MCP catalog on the next tool call with their API key.
There is deliberately NO MCP tool to register widgets or themes: API keys are read-only credentials that travel into third-party hosts, so writes require the user’s authenticated session in the designer. Do not look for or request a registration tool.
Call list_widgets to see what already exists (avoid kind collisions), list_schemas for the user’s saved shared data schemas, list_actions for the user’s saved shared actions, list_themes for registered themes, and list_theme_tokens for token semantics and presets.

Widget entry

A widget is one JSON object: { kind, template, descriptor }.

Descriptor fields

Reserved kinds

A custom kind must not collide with the built-in kinds: card, table, tree, group. Identifiers match ^[a-zA-Z0-9._-]+$.

Shared data schema entry

A shared data schema is one JSON object: { name, label?, description?, schema } — defined once, referenced by many widgets via descriptor.dataSchemaRef. The user imports it in the Data schemas section at widgentic.dev. Draft the entry, hand it to your user for Import in the Data schemas section, THEN draft widgets referencing it by name — the reference validates against the saved schema when the user saves the widget.

Shared action entry

A shared action is one JSON object: { name, label?, description?, definition } — defined once, bound by many widgets via “action”: { “ref”: “<name>” }. The user imports it in the Actions section at widgentic.dev, where an http action must pass a live test call before it can be saved. Call list_actions first: it lists what the user already has, as the CONTRACT (name, kind, method, input and output schemas) — the url, headers and query stay on the server, and you never need them to bind one. Bind a listed action by name, THEN hand the widget to your user. When nothing listed fits, DESCRIBE the action they should create and test in the Actions section; do NOT draft an inline http definition with a URL or credentials you cannot know.

Theme entry

A theme entry is one JSON object: { name, label?, description?, tokens, styles? }.

Custom variables

Names match ^x-[a-z0-9][a-z0-9-]*$. A custom variable x-foo becomes —wg-x-foo on the themed scope; reference it from widget styles as var(—wg-x-foo).

Value safety

Token values are plain CSS values. Rejected: anything matching [;{}<>\\], a comment marker (/* or */), an unclosed bracket or string, and calls to url(, expression(, image-set(, src( (case-insensitive, whitespace-tolerant). Keep values to colors, lengths, and font stacks. The full token table is on Theme tokens.

Styles

descriptor.styles is { “<selector>”: { “<cssProperty>”: “<value>” } } — each declaration is a separate key/value pair, e.g. { “.wg-roster-row”: { “display”: “flex”, “gap”: “var(—wg-spacing)” } }. Every selector part (split on top-level commas) must be held to .wg- classes: one of its compounds names a .wg- class itself, or through :is() or :where() whose every argument does. A .wg- class only inside :not(), :has(), an attribute test or a string does not count, and no part may open with a combinator — e.g. ‘.wg-card .wg-xcard-head’, ‘.wg-row:has(.wg-ok, .wg-warn)’ or ‘:is(.wg-btn, .wg-link):hover’. Selectors, properties, or values matching [;{}<>@\\], holding a comment marker (/* or */) or an unclosed bracket or string, or calling url(, expression(, image-set(, src( are dropped. Property names must match ^-?[a-zA-Z][a-zA-Z-]*$ (letters and hyphens, optionally leading ’-’); anything else is dropped. Reference theme tokens with var(—wg-<token>) and custom variables with var(—wg-x-<name>); prefer tokens over literals so themes restyle the widget. Every registry token is always DEFINED at render time (defaults, overridden by the active theme), so bare var(—wg-<token>) is safe — no fallback needed. Custom x-* variables are defined only by themes that set them, so give those a fallback: var(—wg-x-foo, <value>).

Data schema

Supported subset: type (object/array/string/number/integer/boolean/null, or an array of those), properties, required, items, enum, pattern. Unknown keywords are ignored. pattern is a bounded regex: max 256 chars, no nested quantifiers, applied only to strings and capped input length; unsafe or invalid patterns are ignored rather than enforced. Kinds with a dataSchema fail fast with dotted paths (e.g. data.lines.0.amount); schema-less kinds render leniently.

Data modeling

PREFER binding only properties declared in descriptor.dataSchema — schema-declared data is validated with dotted paths, so agents get correctable errors instead of silently blank output. A ‘$meta.x’ bind path exists (reads the payload’s meta) but meta is NOT covered by dataSchema validation: avoid it, or reserve it for genuinely out-of-band display like a caller-supplied heading. If the widget needs a title, declare `title` as an optional schema property instead. When the user names a SAVED schema, set descriptor.dataSchemaRef to its name (shape from list_schemas) and bind those properties — do NOT reconstruct the schema inline: the copy forks the moment the user edits the shared one. The template node forms and safety rules are on Template DSL; per-user limits on Limits.