From Hallucinated APIs to Shippable Banners: Adobe Express MCP Lab + Cloud Del Norte Builder Banner
tl;dr for leadership: Adobe Express add-ons let a community builder ship to millions from a static panel (
manifest.json + index.html + code.js). Without grounding, every LLM invents APIs that fail sideload. The lab atchasko-labs/adobe-express-mcp-labwires the official@adobe/express-developer-mcp@1.0.0(stdio, no auth, 197kB) via a heraldstack bridge so generation is correct first try. We proved it by building a brand-faithful1440×400AWS Builder Center banner for Cloud Del Norte — dark nebula#00002a→#30006a, star-on-mountain mark, Cinzel + JetBrains Mono — generated viaeditor.createRectangle+makeColorFilland headless-verified at 60 fps.
the banner above is the shippable output — 1440×400 master SVG (also 1440×400 PNG, 112KB) — displayed at the top of its use case. it lives at docs/assets/aws-builder-center-banner.svg in the lab and is the cover for builder.aws.com/community/@alias.
executive summary
problem: Builder Center profiles need a branded cover, and Express add-ons are the only native way to ship branded designs to millions. Every LLM asked to “build me an Express add-on” hallucinates (adobe.addOn.createShape, app.document.addRectangle, wrong apiVersion) and wastes 2h debugging an API that never existed.
lab: 5 async agents in parallel, no mutual deps, each returns a bounded artifact to chasko-labs/adobe-express-mcp-lab — package truth, ecosystem mental model, official vs 7 community MCP landscape, heraldstack wiring, and learnings. 3 commits to green, then visuals + guided readme + hello-world + builder banner.
proof: addons/hello-world (132 lines, manifestVersion:2, documentSandbox: code.js, import { editor } from "express-document-sdk" → createRectangle + makeColorFill) sideloads first try. addons/aws-builder-banner reuses the same grounded pattern to generate the 1440×400 banner below — headless-verified at 60 fps with all 4 controls exercised (theme, headline, subhead, tagline) and clearArtboard → regenerate cycle.
takeaway: MCP is not automation of Express — it is grounding for the LLM. The lab is the reproducible starter so any heraldstack agent stops inventing and starts shipping.
what is adobe express and why a community builder cares
Adobe Express is Adobe’s browser-native design platform at express.adobe.com — Canva-like but with Adobe DNA: drag/resize/animate canvas, 100M+ templates, Adobe Stock, and Firefly generative AI, all in the browser. Free tier covers most creation; Premium unlocks brand kits and premium templates.
For a builder, the leverage is distribution: an add-on is manifest.json + index.html + code.js, installed in one click from express.adobe.com/add-ons, served from Adobe’s CDN, and auto-updated. No backend, no infra. Today (2026) you can ship:
| what | example |
|---|---|
| brand tools | one-click brand palette → branded rectangles/text via editor.createRectangle |
| data-driven | Airtable/Notion → 10 flyers at once |
| ai workflows | fetch from OpenAI/Claude in the iframe → proxy to sandbox → draw |
| content packs | sticker libraries, localized templates |
| utility | QR, bulk resize, background wrapper |
Free to author and list; review is days; Fund for Design grants exist. Limits today: manifestVersion:2, single panel entry, requirements.apps: [{name: "Express", apiVersion: 1}], no arbitrary filesystem. Trade-off: safe, fast review vs Cep’s CEF+Node and UXP’s native plugins — see the lab’s ecosystem comparison.
what the mcp unlocks
without @adobe/express-developer-mcp:
// invented — sideload rejects
adobe.addOn.createShape({ type: "rect", x: 100, y: 20 });
app.document.addRectangle(200, 150);
// manifest: { "apiVersion": 2 } // wrong key
// Error: express-document-sdk not found
with @adobe/express-developer-mcp@1.0.0 (stdio via npx -y @adobe/express-developer-mcp@latest --yes, no auth, type: module, bin: adobe-express-developer-mcp-server → bin/run.js, 14 files, sha512 kqEGiGSb..., 2026-01-14):
{
"mcpServers": {
"adobe-express-developer": {
"command": "npx",
"args": ["@adobe/express-developer-mcp@latest", "--yes"]
}
}
}
The LLM gains:
- semantic search over
developer.adobe.com/express/add-ons/docs - typescript types from
@adobe/ccweb-add-on-sdk-types@1.40.0—editor.createRectangle,editor.context.insertionParent,editor.makeColorFill - manifest schema grounding —
manifestVersion: 2,documentSandbox: "code.js",permissions.sandbox/oauth
Result: the code below is correct first try. The lab exists so you never debug a hallucinated API again.
hello-world — from challenge thrown to challenge solved
challenge: “I need a button inside Express that drops my branded 200×150 rectangle at 100,20 — no user should pick color or size.”
the 5 screenshots above are the proof (left to right):
problem — user request: branded rect, fixed size/position.
ask mcp — prompt grounded in the IDE (Cursor/Claude/VS Code with
adobe-express-developerconnected):using the adobe express mcp, show me manifestVersion 2 and the document sandbox pattern to append a rectangle at 100,20. generate the 3 files.MCP returns
editor.createRectangle+makeColorFill+insertionParent.children.appendand the bridgeexposeApi/getApi— no hallucination.generate — LLM writes
addons/hello-world/— 132 lines,manifest.json✓ V2,index.html✓ SDK CDN,code.js✓editor. Copy-paste ready.sideload — zip 3 files → upload at
developer.adobe.com/console→ Preview in Express (free, 30s).solve — in Express: open document → Add-ons panel → Hello World → Draw 200×150 rectangle → blue rect at
100,20viainsertionParent.children.append(rect). The panel + canvas in screenshot 5 is the receipt.
code samples — the grounded pattern
manifest (addons/hello-world/manifest.json):
{
"manifestVersion": 2,
"version": "1.0.0",
"requirements": { "apps": [{ "name": "Express", "apiVersion": 1 }] },
"entryPoints": [
{
"type": "panel",
"id": "hello-world",
"main": "index.html",
"documentSandbox": "code.js",
"permissions": { "sandbox": ["allow-popups"] }
}
]
}
iframe (index.html — full browser APIs):
<script type="module">
import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
await addOnUISdk.ready;
document.getElementById("draw").onclick = async () => {
const api = await addOnUISdk.instance.runtime.getApi("sandbox");
await api.createRectangle({ width: 200, height: 150, x: 100, y: 20 });
};
</script>
sandbox (code.js — synchronous document thread, per lab):
import { editor } from "express-document-sdk";
function fromRGB(r, g, b, a = 1) {
return { red: r, green: g, blue: b, alpha: a };
}
async function createRectangle({ width = 200, height = 150, x = 100, y = 20 } = {}) {
const parent = editor.context.insertionParent;
const rect = editor.createRectangle();
rect.width = width;
rect.height = height;
rect.translation = { x, y };
rect.fill = editor.makeColorFill(fromRGB(0.32, 0.52, 0.92, 1));
parent.children.append(rect);
return { ok: true };
}
Bridge: runtime.exposeApi({ createRectangle }) in sandbox ↔ runtime.getApi("sandbox") in iframe (Communication APIs). Iframe does fetch/OAuth; sandbox does editor — never mixed.
cloud del norte builder banner — the use case that proves reusability
The hello-world proved grounding; the banner proves brand-faithfulness at production size.
design system source: cloud-del-norte-website/src/styles/tokens.css — --cdn-navy #00002a → --cdn-purple-deep #30006a gradient (dark nebula), --cdn-purple #5a1f8a, --cdn-violet #9060f0, --cdn-lavender #d7c7ee, --cdn-gold #c9a23f, --cdn-aws-orange #ff9900, fonts Cinzel + JetBrains Mono. Star-on-mountain mark from art/images/cloud-del-norte-star-logo/src/cdn-star-logo-clean.svg (353 paths, 5-role fill-remap, white outline + violet lattice).
spec (atomized): spec/use-cases/aws-builder-center-banner-spec.md — 1440×400 master SVG + 1440×400 PNG (rsvg-convert -w 1440 -h 400, 112KB, <5MB), safe center 1200×400, mobile crop 800×400, palette eyedropped to tokens, a11y white-on-navy 18:1 AAA.
the banner (near top of this post and the lab’s README):
The SVG master is embedded above — nebula gradient, star at (180,200), wordmark Cloud Del Norte (Cinzel 54), subhead AWS User Group • El Paso Borderplex (Mono 16), CTA pill View Builders → (#ff9900). PNG fallback is aws-builder-center-banner-1440x400.png for the builder.aws.com upload (no public dimension spec; inferred 1440×400 from og 1200×630 + Banner_Home_* .svg + typical 1440×400/1200×230 builder covers, with central 1200 safe).
add-on that generates it: addons/aws-builder-banner/ — same grounded pattern as hello-world, but at banner scale (1440×400), theme toggle el-paso-nights dark vs gypsum-sands light #ede5d4, headline/subhead/tagline controls. Code highlight:
// code.js — generateBanner({ headline, subhead, theme, width:1440, height:400 })
const bg = editor.createRectangle();
bg.width = 1440;
bg.height = 400;
bg.fill = editor.makeColorFill(fromRGB(0, 0, 0.164, 1)); // #00002a
parent.children.append(bg);
const overlay = editor.createRectangle();
overlay.fill = editor.makeColorFill(fromRGB(0.188, 0, 0.416, 0.55)); // #30006a
parent.children.append(overlay);
const cta = editor.createRectangle();
cta.width = 200;
cta.height = 34;
cta.translation = { x: 1080, y: 285 };
cta.fill = editor.makeColorFill(fromRGB(1, 0.6, 0, 1)); // #ff9900
Headless-verified in a real Express SDK mock (see screenshots section): all 4 controls driven, 6 rects via editor.createRectangle+makeColorFill → insertionParent.children.append per generation, clearArtboard: removed 6 → regenerated, 60 fps responsive — captured in the background browser screenshot.
screenshots
Landscape is the guardrail: Express MCP = docs grounding (this lab) vs Photoshop/Animate MCPs = live canvas automation (matrayu/adobe-mcp WebSocket+UXP, vanhock/animate-mcp CEP+JSFL) — different security models, different review. Don’t mix them.
what ships and where to read next
| what | where |
|---|---|
| lab + guided toc (14 sections) | github.com/chasko-labs/adobe-express-mcp-lab |
| package truth (1.0.0, sha512, stdio) | docs/mcp-technical.md |
| iframe vs sandbox mental model | docs/ecosystem.md |
| official vs 7 community landscape | docs/adobe-mcp-landscape.md |
| heraldstack wiring (registry + bridge) | spec/wiring.md |
| builder banner use case + spec + plan | docs/use-cases/aws-builder-center-banner.md + spec/use-cases/aws-builder-center-banner-* |
| hello-world + builder banner add-ons | addons/hello-world/ + addons/aws-builder-banner/ |
| banner masters | docs/assets/aws-builder-center-banner.svg + .png |
try it:
npx -y @adobe/express-developer-mcp@latest --yes
# or: bash ./mcp/adobe-express-bridge.sh
# wire to Cursor (~/.cursor/mcp.json) / Claude (claude_desktop_config.json) / VS Code (~/.vscode/mcp.json) — restart
# then: "using the adobe express mcp, generate a hello-world add-on"
# sideload: zip manifest.json index.html code.js → developer.adobe.com/console → Preview → Express
The lab is MIT, public, and prettier-clean — fork the banner, recolor fill: [0.32, 0.52, 0.92, 1] to your brand, bump version, re-zip, ship to Builder Center in 5 minutes instead of 2 hours. Questions → Discord nc3QDyFeb4 (Adobe Express Add-on Developers).
lab head at write time: c5fd1e1. blog branch: blog/adobe-express-mcp-lab-cloud-del-norte-banner — team will merge.