A Model Context Protocol server exposing the Nodality declarative UI library's two-array API (E for elements, N for nodes/effects) to agent IDEs. Provides tools for validating UI specifications, discovering vocabulary, checking rendered pages, and parsing HTML back into element arrays.
Five tools with detailed descriptions (194 - 500+ chars, well above baseline 194 avg) and clear vocabulary documentation. All tools are READ_ONLY and well-scoped. However, input schemas are present but minimal, most parameters lack type constraints and validation rules. Parameter descriptions exist but are sparse relative to the complex domain. No output schemas documented. Error handling is mentioned (validate_nodes returns machine-readable reports) but recovery guidance is absent from tool descriptions. Tool naming is clear (verb_noun pattern: list_ops, validate_nodes, check_page, get_schema, parse_html) and follows conventions. Composition is good, tools chain naturally (list_ops → validate_nodes, get_schema for discovery). Missing: enum constraints on parameters, explicit output schema documentation, and error recovery hints in descriptions.
What the page actually DOES, once it has real layout. Everything else here checks the input: validate_nodes checks vocabulary, get_schema says what a type accepts, parse_html says what a page was made from. None of them can tell you the page you just produced scrolls sideways, clips its own text, or is unreadable — a spec can be perfect and the page still wrong. Give it `html` (or `path` to a file `preview` wrote) and it drives a real browser at a phone and a desktop width and reports horizontal overflow, elements past the viewport, clipped content, images with no description, tap targets under 24px, controls with no accessible name, skipped heading levels and text below the WCAG contrast minimum. Same report shape as validate_nodes; `path` in an error is a CSS selector into the rendered page. It reports facts, never taste — it will not tell you whether a design is good.
One element type's parameters, on demand. This is the other half of list_ops: that returns the vocabulary of N, this returns the vocabulary of E. Call it for the type you are about to write rather than carrying every type's parameters in context — that is the difference between paying for a schema once and paying for it in every request. Each entry names the mapper, the components it builds and every parameter recovered from the source those components actually read, so it cannot describe a parameter the library does not have. Omit `type` for the whole schema. Composites carry content in a slot — `items` for cards, nav, sideNav, table and ulist; `children` for row, form, stack and wrap — and declaring it in the other one renders the placeholders instead. The library warns on the console when it happens.
The vocabulary, as data: every raster op with its pipeline stage and its parameters (name, default, unit, whether changing it rebuilds the shader), plus the parameters every node inherits (target, by, side, ease...), the driver names, the easing names and the unit names. Read this before writing nodes — it is assembled from the live registry, so it cannot drift from what the pipeline accepts. Also returns `presets` (the transition effects a morph may name) and `elementTypes` (the vocabulary of E), so both halves of the pair are discoverable from one call.
Input schemas lack type constraints and validation rules. Parameters like 'nodes' and 'elements' are typed as 'array' with 'items: {type: object}' but contain no property definitions, enums, or format constraints. LLMs cannot infer valid structure without explicit schema details.
No output schemas documented for any tool. Descriptions mention what tools return (e.g., 'machine-readable report', 'facts never taste') but do not specify field names, types, or structure. LLMs cannot plan downstream operations without knowing response shape.
Error handling guidance missing from tool descriptions. validate_nodes is noted to return 'machine-readable report' with codes and suggestions, but tool description does not explain how to interpret error codes or what recovery steps are available. Agents need explicit recovery guidance.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 57 | 2026-07-28+ | v2 |
Read a rendered page back into an E array, so a page can be EDITED rather than only generated: parse it, change the one thing, render again.
Check an N array before applying it, and return a machine-readable report. Never throws: malformed input IS a report. Each error carries a code, the path that failed, the offending value, did-you-mean suggestions and the valid vocabulary for that position — enough to repair without re-reading the docs. Pass elements too and targets are checked against real ids, which catches the other silent failure: a correctly spelled op aimed at an element that does not exist. Passing elements also validates E itself, so an element type that names nothing is reported rather than throwing at render time. Where an op is a near miss its parameters are checked against the op that was meant and reported with an `assuming` field, so one call returns every error rather than revealing them one round-trip at a time.
Parameter descriptions are minimal. 'nodes' parameter in validate_nodes has a 500+ char description of the N array structure, but lacks guidance on when to call it vs. check_page, or what happens if validation fails. Descriptions should answer: WHAT, WHEN, and WHAT NEXT.
get_schema parameter 'type' lacks enum constraint. Description says 'e.g. "cards"' but does not list valid types. LLMs will hallucinate invalid type names. Should include enum of all valid element types or reference list_ops output.