Skip to main content
The MCP exposes the same theming model the editor uses — palette + ~3 section ambiences + typography + radii — through a layered set of tools that match the agent’s intent.

The three layers

A proposal references a theme via theme_id. If absent, it falls back to a legacy proposal_style jsonb on the proposal row.

Three modes of creating a theme

1. Preset (assisted)

Pick from the catalog and snapshot it. Lowest effort — the catalog has ~25 curated palettes (matcha, ocean, ink, midnight, …) covering most use cases.

2. Smart palette (generated)

Provide a mini-palette, the server generates a full WCAG-compliant theme via chroma-js — including accent solid/subtle variants, badges, and 3 section ambiences automatically derived from the section backgrounds.
The same input can be validated without persisting:

3. Advanced (full control)

When the agent needs to set every token explicitly — e.g. matching a brand guideline that doesn’t fit smart-mode generation — use create_theme with the typed colors and section_styles arrays.
Patch later with update_theme (full PATCH semantics) or with the more targeted update_theme_section_style:
Each entry in section_styles[] accepts an optional id (1-32 chars, [a-zA-Z][a-zA-Z0-9_-]*). Reserved values: "default" and any digit-only string. Ids must be unique per theme. When sections reference a slot by id (section_style: "deep"), the server resolves it to the positional index before assembly. Survives reordering: if you later reorganize section_styles[], sections that use named refs keep pointing at the same ambience. Sections that use positional refs ("1", "2") silently shift. The reverse mapping is also done in get_proposal_tree: positional refs are converted back to ids in the response when ids exist.

Apply / detach

If snapshot_style: false, the proposal falls back to its legacy proposal_style (or defaults if absent) — useful when you want to “reset” a proposal to a different visual baseline.

Read the resolved style

The resolution chain:
  1. If proposal.theme_id is set → build the style from the theme row.
  2. Else if proposal.proposal_style is set → parse it.
  3. Else → defaults from @propal/core/theming.

Per-section overrides

Sometimes you want one section to break the theme — e.g. a hero with a background image and a different ambience. Use set_proposal_section_attrs:
This is a patch — only the keys you provide are merged onto the section’s attrs. Children are untouched.

Tips

  • Generate first, refine later. generate_theme_from_palette produces WCAG-safe results in seconds. Use update_theme_section_style to tweak individual slots if needed.
  • Always name your slots. It’s a 5-character habit (id: "deep") that saves debugging when you reorder slots later.
  • Check the warnings. generate_theme_from_palette returns WCAG warnings inline — surface them to the user before persisting if contrasts are weak.
  • Don’t mix advanced and smart in one go. If you start with generate_theme_from_palette and want to tweak, prefer update_theme_section_style for surgical changes; full update_theme PATCH still works but rewrites are noisier.