Skip to main content
Glama
ericlewis

widget-studio

by ericlewis

widget-studio

An agent capability for creating and displaying rich UI widgets (cards, dashboards, task lists, charts, forms, tables) inline in conversations — packaged as a Claude Code plugin, an Agent Skill, standalone CLI scripts, and an MCP server with MCP Apps support. Widgets use the ChatKit widget JSON format, generated by prompting Widget Studio's hosted generator; the JSON is edited directly only for small tweaks.

Architecture

The MCP server is optional — the skills + CLI deliver the full generate→render loop on their own. The server is the layer that adds interactive inline widgets in MCP Apps hosts. Each host gets the richest rendering it supports:

Layer

What it provides

Who uses it

Skills (skills/)

/widget-studio:make — how to prompt the generator well; :tweak — instant JSON edits + re-display; :preview — render saved JSON to PNG/HTML; :doctor — install/render/API health checks

Any skills-capable agent

Reference (skills/make/references/chatkit-widgets.md)

ChatKit component schema for reading and making small edits to generated widgets before re-display

The model, on demand

Scripts (scripts/, bin/)

widget-generate (prompt → widget via hosted API), widget-render (JSON → PNG / standalone HTML), widget-export (→ .widget file for the Widget Studio editor) — self-locating, on PATH in plugin sessions

The full capability, no MCP needed

MCP server (src/)

generate_widget, display_widget, and export_widget (.widget files) tools; interactive MCP Apps iframe with a copy/export action bar in capable hosts, automatic PNG fallback elsewhere

MCP Apps hosts (interactive) + any other MCP client (PNG)

Evals (evals/)

Deterministic golden-render suite (npm run eval) + skill-creator-format LLM eval cases (skills/make/evals/evals.json)

CI / skill iteration

Rendering paths

  • MCP Apps hosts (Claude Desktop, claude.ai, ChatGPT): interactive iframe via the standard _meta.ui.resourceUriui://widget-studio/widget.html, a fully self-contained HTML renderer (CSP-safe, light/dark, actions post back to chat). Legacy openai/outputTemplate alias included for older ChatGPT builds.

  • Non-UI MCP clients (Claude Code CLI, others): the server detects the missing MCP Apps capability at initialize and attaches a PNG image of the widget to the tool result instead (see PNG rendering). Override with WIDGET_STUDIO_IMAGE=auto|always|never.

  • No MCP at all: widget-render (scripts/render-widget.mjs) produces the same PNG or a self-contained HTML preview from a widget JSON file.

Related MCP server: ggui

Install

Note: the npx forms and one-click badges below go live with the first npm release of widget-studio-mcp. Until then, use the from-source form — everything else is identical.

Install in Cursor Install in VS Code Install in LM Studio

/plugin marketplace add ericlewis/widget-studio-mcp
/plugin install widget-studio@widget-studio

The plugin registers the MCP server, puts widget-generate/widget-render/widget-export on PATH, and installs the skill family (/widget-studio:make, :tweak, :preview, :doctor). dist/ ships self-contained bundles — no npm install needed.

MCP server, per host

claude mcp add widget-studio -- npx -y widget-studio-mcp@latest

claude_desktop_config.json (Settings → Developer → Edit Config):

{ "mcpServers": { "widget-studio": { "command": "npx", "args": ["-y", "widget-studio-mcp@latest"] } } }

Use the install badge above, or .cursor/mcp.json:

{ "mcpServers": { "widget-studio": { "command": "npx", "args": ["-y", "widget-studio-mcp@latest"] } } }
code --add-mcp '{"name":"widget-studio","command":"npx","args":["-y","widget-studio-mcp@latest"]}'
codex mcp add widget-studio -- npx -y widget-studio-mcp@latest

Or ~/.codex/config.toml:

[mcp_servers.widget-studio]
command = "npx"
args = ["-y", "widget-studio-mcp@latest"]

As an extension (bundles the MCP server and skills):

gemini extensions install https://github.com/ericlewis/widget-studio-mcp

~/.codeium/windsurf/mcp_config.json:

{ "mcpServers": { "widget-studio": { "command": "npx", "args": ["-y", "widget-studio-mcp@latest"] } } }
goose session --with-extension "npx -y widget-studio-mcp@latest"
amp mcp add widget-studio -- npx -y widget-studio-mcp@latest

ChatGPT connects to remote MCP servers only. Run the HTTP transport behind a tunnel or deploy, then add the URL under Settings → Connectors (developer mode):

npx -y widget-studio-mcp@latest --http 3400   # stateless streamable HTTP, POST /mcp

ChatGPT implements the MCP Apps standard natively, so widgets render interactively; in --http mode the server also always attaches the PNG. Bridge for stdio-only hosts hitting a remote: npx -y mcp-remote https://your-host/mcp.

git clone https://github.com/ericlewis/widget-studio-mcp && cd widget-studio-mcp
npm install && npm run build
claude mcp add widget-studio -- node "$(pwd)/dist/index.js"   # or the equivalent for your host

PNG rendering

Built in — pure JS/WASM (satori + resvg with bundled Inter fonts). No browser, no playwright/puppeteer, no native dependencies, nothing to install.

Develop

npm run build   # typecheck + bundle the iframe app and self-contained server into dist/
npm test        # protocol smoke test (incl. one real API generation)
npm run eval    # render golden fixtures to PNG + offline protocol checks

Manual preview of any widget JSON:

node scripts/render-widget.mjs --in evals/golden/sales-dashboard.json --png dashboard.png
node scripts/render-widget.mjs --in evals/golden/sales-dashboard.json --html dashboard.html

dist/ is committed on purpose: plugin installs copy the repo as-is, so the bundles must ship prebuilt. Rebuild before committing changes under src/.

Notes

  • The Widget Studio API is the unauthenticated hosted service behind the public editor; requests carry a stable random user ID (WIDGET_STUDIO_USER_ID to pin).

  • The renderer covers the full ChatKit component set; unknown components degrade to rendering their children. External images are blocked by host CSP in interactive mode (placeholder shown) but fine in PNG/HTML output.

Available Tools

3 tools
display_widgetDisplay a widgetA
Read-only

Instantly re-render a widget JSON tree from a previous generate_widget result — as-is, or with small edits (fix a label, change a color, update a value). Pass the complete widget node tree as JSON. For new widgets or layout changes, prefer generate_widget.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoDisplay name for the widget.
widgetYesChatKit widget node tree as a JSON string. Root must be {"type":"Card"|"ListView"|"Basic",...}.

TDQS

A4.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation already declares this as read-only; the description adds that it re-renders instantly and takes a complete widget node tree, but does not disclose potential error behavior or edge cases. This matches the calibration example where annotations lower the burden and a score of 3 is appropriate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise, front-loaded sentences with no redundant information. Every phrase earns its place, and the alternative tool is mentioned efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple display tool with two well-documented parameters and a clear description, all necessary context is provided. The description explains purpose, usage, and data format; no output schema is needed for a display operation, and the read-only annotation covers safety.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description adds meaningful context beyond the schema by specifying the widget must be a 'complete widget node tree' from a previous generate_widget result and that small edits (fix label, change color) are supported, enhancing the semantic understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the tool re-renders a widget JSON tree from a previous generate_widget result, with specific use cases (as-is or small edits). It distinguishes itself from siblings by explicitly saying 'For new widgets or layout changes, prefer generate_widget.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use context: from a previous generate_widget result, and with small edits. It also names the alternative tool for new widgets or layout changes, giving clear guidance on when not to use this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_widgetExport a .widget fileA

Export a generated widget as a .widget file — the Widget Studio editor's format (importable at widgets.chatkit.studio). Pass the generationId from a generate_widget result. Optionally pass a path to also write the file to disk (recommended in local sessions; defaults to .widget in the current directory when path is 'auto').

ParametersJSON Schema
NameRequiredDescriptionDefault
pathNoWhere to write the file. 'auto' = <widget-name>.widget in the current directory; omit to skip writing and just return the file contents.
generationIdYesThe generationId returned by generate_widget in this session.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint=false annotation, the description discloses important behaviors: it can write a file to disk, defaults to '<widget-name>.widget' when path is 'auto', and omitting path skips writing (implied by 'also write'). It also notes the file is importable at widgets.chatkit.studio. This adds useful context, though it doesn't mention overwrite behavior or permissions, so it is strong but not perfect.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is exceptionally concise—two sentences that immediately state the purpose, then provide key usage details. Every clause carries essential information: the format, the required input, the optional path behavior, and the default filename. There is no fluff or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with only two parameters and a straightforward export function, the description covers the main workflow: pass generationId, optionally provide a path, and know the default filename. The return behavior (file contents) is only implied in the description but is explicitly stated in the schema's path description. Given the availability of that schema, the description is adequately complete, though it could explicitly state what the tool returns when no path is given.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides detailed descriptions for both parameters (generationId and path), covering their meaning and special values. The description essentially restates this information without adding new parameter semantics. Since schema coverage is 100%, a baseline score of 3 is appropriate; the description adds no extra clarity beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('Export a generated widget as a .widget file'), which clearly states the tool's function. It also distinguishes this from siblings by referencing the Widget Studio editor's format and the import location, making it unique from generate_widget and display_widget.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: it is meant to be used after generate_widget, since it instructs to 'Pass the generationId from a generate_widget result.' It also provides guidance on the optional path parameter, recommending it for local sessions and explaining the 'auto' behavior. However, it does not explicitly mention when not to use it or contrast with display_widget, so it earns a 4 rather than a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

generate_widgetGenerate a widgetA
Read-only

Generate a rich inline UI widget from a natural-language prompt using the Widget Studio designer. This is the primary way to create widgets. Prompt recipe: name the widget kind ('a weather card', 'a leaderboard', 'a boarding pass'), enumerate ALL real data it should show (every number, name, and label — the generator renders exactly what you give it and invents placeholders for what you omit), and add layout/style hints when you care ('use the Table component', 'with a bar chart', 'dark-themed', 'compact'). For static widgets add 'display only, no buttons' — otherwise the generator may invent buttons with made-up action types. Takes 20-60 seconds. To iterate, call again with a refined prompt that restates everything plus the changes (the service is stateless); for tiny tweaks, edit the returned widget JSON and use display_widget instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
promptYesNatural-language description of the widget, including the data it should show.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses many behavioral traits beyond the annotations: it takes 20-60 seconds, the service is stateless, it renders exactly what you provide and invents placeholders for omissions, and it may invent buttons with made-up action types unless 'display only' is specified. These notes enrich the openWorldHint annotation and add practical expectations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact yet dense, with every sentence earning its place. It starts with the core purpose, then a prompt recipe, critical caveat about buttons, timing, and iteration guidance. It is well-structured and front-loaded, with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with one parameter and no output schema, the description covers all necessary context: the purpose, how to craft input, timing, statelessness, iteration behavior, and when to prefer display_widget. It is sufficiently complete for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Though the schema fully covers the single 'prompt' parameter, the description adds extensive guidance on how to compose the prompt: naming the widget kind, enumerating all real data, adding layout hints, and the 'display only' flag for static widgets. This goes far beyond the schema's one-line description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Generate a rich inline UI widget from a natural-language prompt using the Widget Studio designer.' It also positions this as 'the primary way to create widgets,' distinguishing it from the sibling tools, especially display_widget which is explicitly mentioned for tweaks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit when-to-use guidance and contrasts with alternatives: 'This is the primary way to create widgets,' and 'for tiny tweaks, edit the returned widget JSON and use display_widget instead.' It also gives conditional advice for static widgets and iteration, making the usage context crystal clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.2.0
    • First observeddisplay_widget
    • First observedexport_widget
    • First observedgenerate_widget

TDQS

A4.6/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a distinct role: generate_widget creates new widgets from prompts, display_widget re-renders or lightly edits existing widget JSON, and export_widget persists to a file. The descriptions clearly delineate when to use display instead of generate, avoiding overlap.

Naming Consistency5/5

All three tools follow the consistent verb_noun pattern: generate_widget, display_widget, export_widget. Naming is predictable and uniform.

Tool Count5/5

Three tools cover the entire widget workflow—creation, editing/rendering, and export—without unnecessary extras. Each tool earns its place, and the count is well-scoped for the server's purpose.

Completeness5/5

The tool surface fully covers the widget lifecycle: generate from natural language, display/iterate on JSON, and export to a file. There are no dead ends or obvious missing operations for the stated domain.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers