described MCP cross-service orchestration in general terms -- how form responses become Slack messages, Linear issues, or GitHub PRs through LLM-mediated chains. This post is a concrete implementation of that pattern: a structured client hearing form whose responses auto-generate a landing page wireframe in Figma.
The test case is GreenLeaf Analytics, an AI-powered SaaS for e-commerce cart recovery. A 28-question hearing form captures business context, target audience, content, design preferences, and assets. The responses feed into the Figma Plugin API to produce a multi-section wireframe in about 3 minutes.
The Architecture
Two MCP servers, one client, zero integrations.
MCP Client (Claude Desktop / Cursor)
|
|-- 1. FORMLOVA MCP: get_responses(form_id)
| → Structured JSON: 28 hearing answers
|
|-- 2. LLM: Interprets responses, builds Figma API commands
|
|-- 3. Figma MCP: create_new_file(name)
| → Empty Figma file
|
|-- 4. Figma MCP: use_figma(commands)
→ Wireframe sections built via Plugin API
FORMLOVA does not know about Figma. Figma does not know about FORMLOVA. The LLM reads the output of step 1 and constructs the input for steps 3-4. This is the same pattern from the cross-service orchestration post, but applied to a specific, testable workflow.
The Hearing Form: 5 Steps, 28 Questions
The hearing sheet is a multi-page form designed from the experience of
Figma Plugin API: Key Implementation Patterns
The Figma MCP's use_figma tool executes code in the Figma Plugin API sandbox. There are specific constraints that shape the implementation.
Sandbox Limitations
- No
fetch()-- no external network requests - No external image loading -- all images become gray placeholders
- No
require()or module imports - Only fonts installed in the Figma environment are available
This is why the output is a wireframe, not a finished design. Images cannot be inserted programmatically, so every image position is a labeled placeholder frame.
The appendChild-then-FILL Constraint
This is the most important thing to know about Figma Plugin API Auto Layout. layoutSizingHorizontal: "FILL" only works after the frame has been added to an Auto Layout parent.
// Works
mainFrame.appendChild(section);
section.layoutSizingHorizontal = "FILL";
// Does not work -- FILL is silently ignored
section.layoutSizingHorizontal = "FILL";
mainFrame.appendChild(section);
This constraint applies to every FILL assignment in the entire wireframe -- sections, text nodes, card rows, everything.
Font Loading Is Mandatory
Text node manipulation requires pre-loaded fonts. Setting characters without loading the font throws an error.
await figma.loadFontAsync({ family: "Inter", style: "Regular" });
await figma.loadFontAsync({ family: "Inter", style: "Bold" });
await figma.loadFontAsync({ family: "Inter", style: "Semi Bold" });
// Must complete before any text creation
The Main Frame Structure
const mainFrame = figma.createFrame();
mainFrame.resize(1440, 100);
mainFrame.layoutMode = "VERTICAL";
mainFrame.primaryAxisSizingMode = "AUTO"; // Height grows with content
mainFrame.counterAxisSizingMode = "FIXED"; // Width stays at 1440px
mainFrame.itemSpacing = 0; // Sections touch edge-to-edge
Each section is a full-width child frame with its own padding, background color, and internal layout.
Mapping Hearing Responses to Wireframe Elements
The GreenLeaf Analytics test produced these mappings:
| Hearing Item | Wireframe Element | Implementation |
|---|---|---|
| Headline: "Stop losing sales. Start recovering them." | Hero heading | Direct text placement |
| CTA: "Start free trial" | Nav + Hero + Final CTA | Same text in 3 button instances |
| Main color: #059669 | CTA buttons, accents | hexToRgb() → fills property |
| First view: "split" | Hero layout | layoutMode: "HORIZONTAL" |
| Mood: "Modern & tech-forward" | Spacing, dark sections | Config lookup table |
| 5 metrics (2,800+, 35%, $48M, etc.) | Numbers section | Parsed into large display text |
| Avoid: "No stock photos" | Placeholders only | No illustration elements generated |
| 3-tier pricing (Growth highlighted) | Pricing cards | Center card gets dark background + badge |
| Security badges: SOC 2, GDPR | Final CTA section | Badge elements in trust row |
Of 28 hearing items, 14 map directly to wireframe elements. The remaining 14 are used indirectly -- business description generates FAQ questions, target audience influences section copy, competitive advantages shape the solution section narrative.
Mood-to-Design Parameter Translation
The "mood" dropdown answer translates to concrete design parameters:
const moodConfigs = {
modern_tech: {
sectionPadding: 96,
cardBorderRadius: 12,
useDarkSections: true
},
warm_friendly: {
sectionPadding: 72,
cardBorderRadius: 16,
useDarkSections: false
},
luxury_refined: {
sectionPadding: 96,
cardBorderRadius: 4,
useDarkSections: true
},
minimal_clean: {
sectionPadding: 112,
cardBorderRadius: 8,
useDarkSections: false
}
};
This lookup table eliminates LLM interpretation variance. "Modern & tech-forward" always produces 12px border radius and dark sections.
Dynamic Section Construction
Only sections selected in the hearing form are generated. The builder pattern:
const builders: Record<string, (data: Response) => FrameNode> = {
hero: buildHero,
problem: buildProblem,
solution: buildSolution,
features: buildFeatures,
numbers: buildNumbers,
pricing: buildPricing,
cases: buildCases,
faq: buildFaq,
cta_bottom: buildCtaBottom,
// ... all 13 section types
};
for (const key of response.selectedSections) {
const builder = builders[key];
if (builder) {
const section = builder(response);
mainFrame.appendChild(section);
section.layoutSizingHorizontal = "FILL";
}
}
Each builder function reads from the hearing response to populate its content. The hero builder switches layout direction based on the first-view selection. The numbers builder parses metric strings into large display text. The pricing builder highlights the recommended tier.
Interactive prototype: . Recipe 1 generates the hearing form. Recipe 2 takes the latest response and builds the Figma wireframe. Copy and paste to run.
The full article with embedded Figma prototypes:
SOCIAL SHARE CARD GENERATOR