Written with AI help (Claude), checked against the project's docs. We make Pixelbolt, so we're not neutral; every number below comes from a run on 10 November 2026 with Pixelbolt 0.15.0 from npm.
Pixelbolt is an MIT-licensed pixel art toolkit with a CLI and a local stdio MCP server. Its picture tools return a PNG contact sheet of the frames they draw. Version 0.12.0 added an MCP Apps preview: a host that supports the MCP Apps extension can show an inline player for the frames, with playback and frame stepping, rather than only a still sheet.
This post walks through the handshake, what the server sends back, and the limits, using a small Node client against the released 0.15.0 package. The feature is new. We checked it with our own client and a stand-in host page in headless Chromium, not inside a chat app, so treat host support as something to confirm in your own client.
What MCP Apps adds
MCP Apps is an extension to the Model Context Protocol. In the MCP Apps README's own summary: a tool declares a ui:// resource that holds its HTML, the host fetches that resource and shows it in a sandboxed iframe, and the host passes tool data to the page through notifications. The MCP Apps README links host documentation for several clients (Claude, ChatGPT, VS Code and Goose among them) and a client matrix at https://modelcontextprotocol.io/extensions/client-matrix; check your client's docs for whether it renders apps from local servers.
1. Add the server
Pixelbolt needs Node.js 20 or newer. The README's configuration for MCP clients is:
{
"mcpServers": {
"pixelbolt": {
"command": "npx",
"args": ["-y", "pixelbolt@latest", "mcp", "--out", "/absolute/path/to/pixelbolt-output"]
}
}
}
On Windows, a client that starts servers without a shell needs "command": "cmd" with "args": ["/c", "npx", ...]. Nothing else changes for previews: the server turns them on only when the client asks.
2. The handshake
The client opts in with the extension in its initialize capabilities. Pixelbolt checks that mimeTypes includes text/html;profile=mcp-app. These are the params of the initialize request:
{
"protocolVersion": "2025-11-25",
"capabilities": {
"extensions": {
"io.modelcontextprotocol/ui": { "mimeTypes": ["text/html;profile=mcp-app"] }
}
},
"clientInfo": { "name": "probe", "version": "0.0.1" }
}
With that, the server's reply lists "capabilities": { "tools": {}, "resources": {} }. Without it, the reply has only tools, and resources/list and resources/read answer "Unknown method".
3. Tools that point at the viewer
After the handshake, six of the eight tools carry the viewer's address: pixel_inspect, pixel_patch, pixel_render, pixel_compile, pixel_scene and pixel_import. Each has:
"_meta": { "ui": { "resourceUri": "ui://pixelbolt/viewer" }, "ui/resourceUri": "ui://pixelbolt/viewer" }
pixel_help and pixel_validate have none. In our run the tools/list reply grew from 19,788 to 20,364 bytes; with the _meta fields removed, the two tool lists were the same.
4. The viewer resource
resources/read for ui://pixelbolt/viewer returns one HTML document with MIME type text/html;profile=mcp-app and _meta.ui.prefersBorder: true. In 0.15.0 it is 22,054 bytes and contains no http:// or https:// URLs; the README says the viewer needs no network.
5. A tool call with a preview
We compiled the shipped campfire fluid preset with pixel_compile ({ "preset": "campfire" }) and rendered the package's examples/coin.json recipe with pixel_render. The normal content (a text summary and a PNG contact sheet) comes back as before. The preview sits in the result's _meta:
"_meta": {
"io.github.skulitom/pixelbolt": {
"preview": {
"version": 1, "width": 32, "height": 48, "scale": 6,
"frames": [{ "name": "campfire-0", "duration": 70, "png": "<base64>" }],
"animations": [{ "name": "campfire", "frames": [0, 1, 2], "loop": true }],
"truncated": 0
}
}
}
(Shortened: the real reply has all 24 frames and indices.) The numbers from the run:
| Call | Frames | Size | Suggested scale | Base64 PNG in preview | Reply with / without extension |
|---|---|---|---|---|---|
pixel_compile campfire |
24 | 32×48 | 6 | 10,700 bytes | 46,228 / 34,189 bytes |
pixel_render coin |
6 | 24×24 | 8 | 1,056 bytes | about 16.7 KB / 13.6 KB |
The compile sizes repeated exactly on every run; the render reply contains your output folder's path, so its size shifts a little with the path you pass to --out.
The render preview also carries files (15 absolute paths in this run) and verdict (not-checked here, since we passed no expect). Over three runs on one Windows machine, the compile call took 201 to 208 ms with or without the extension, and the render call 137 to 167 ms.
6. Clients without the extension
For the same compile call, the content array was byte-for-byte the same with and without the extension, and the result without it had no _meta at all. The README states it plainly: clients without MCP Apps receive exactly the same tool listings and results as before. They keep the static contact sheet, and the exported APNGs and preview.html still play the animation.
7. What a host shows
To see the page, we wrote a stand-in host: an HTML file that puts the viewer in a sandboxed iframe, answers its ui/initialize request, and sends the captured compile result as ui/notifications/tool-result. In headless Chromium the viewer drew the first campfire frame, with Previous, Play and Next buttons, a speed menu, a background menu and a "campfire-0 · 70 ms · 1/24" frame label. Chromium recorded no requests besides the host file itself.
Limits worth knowing
-
Frame cap. A preview keeps a prefix of at most 240 frames and 4 MiB of base64 PNG.
truncatedcounts the frames left out, and the viewer says so. The exported files stay complete. -
Paths. A render preview lists at most 64 file paths of at most 1,024 characters each;
filesOmittedcounts the rest. - Links. The viewer makes no network requests. Its optional playground button (shown when a render asked for a share link) asks the host to open the link, so it only works on hosts that allow opening links.
- Opt-in only. Nothing changes unless the client sends the extension with that MIME type.
- New. The preview arrived in 0.12.0 (November 2026). Host support for MCP Apps varies, and we have not checked this viewer inside a chat client, so confirm it in yours.
Try it
Pixelbolt's README has the section "Inline previews (MCP Apps)", the full tool reference and the install lines; the coin.json example is in the package's examples folder. The campfire above is simulated, not drawn frame by frame; the shared model behind Pixelbolt's fluids, fire included, is in its fluid physics model, a contributor document: https://github.com/skulitom/Pixelbolt/blob/main/docs/physics-model.md
The MCP Apps specification and SDK: https://github.com/modelcontextprotocol/ext-apps

Top comments (0)