Discover, compose, run, publish, and save Adobe Firefly workflows through the run-workflow MCP server.
93
96%
Does it follow best practices?
Impact
83%
1.25xAverage score across 3 eval scenarios
High
Do not use without reviewing
Run pre-built marketing and production workflows bundled with the MCP server. Never compose from scratch when get_featured_workflow finds a match.
TRIGGER when the user:
DO NOT TRIGGER when:
compose_workflowinspect_run via run-workflow skill| Step | Tool |
|---|---|
| Find predefined workflow | get_featured_workflow |
| Upload images, fonts, custom templates, CSV data | upload_asset |
Extract merge tags from custom .indd | get_indesign_tags |
| Submit (large / multi-banner) | run_workflow_submit |
| Poll progress and outputs | run_workflow_get_status (always includeOutputs: true) |
| Re-wire graph after tag diff | compose_workflow (custom templates only) |
| Diagnose failure | inspect_run |
get_featured_workflow({ query: "<keyword>" }).prepared is absent. List matched names, ask user to pick, retry with exact name.mergeNodes, required inputs, sizes. Confirm with user..indd)..otf/.ttf files — upload via upload_asset..csv (data-merge workflows like product-banners-at-scale), upload it and wire it to the input-files node (type: "file" in prepared.inputNodes) — see Data/CSV inputs below.Distinct asset types route to distinct input nodes: images → input-images, fonts → defaults.fonts, CSV/data → input-files (which feeds parse-data). Never collapse them onto one node.
When user wants default templates and default text:
upload_asset.run_workflow_submit:{
"session_id": "<prepared.session_id>",
"useSessionDefaults": true,
"defaults": {
"fonts": [{ "presignedUrl": "...", "name": "Font.otf", "storageType": "azure" }]
},
"inputs": [
{
"node_id": "<input-images id from prepared.inputNodes>",
"content": [{ "type": "image", "url": "..." }]
}
]
}compose_workflow.actions/connections when session_id is present.content array — one submit call.Some featured workflows (e.g. product-banners-at-scale) have a CSV branch: input-files → parse-data → merge-data. prepared.inputNodes surfaces the CSV node with type: "file", and prepared.inputs carries the workflow's baked sample CSV as inline content.
input-files entry needed.upload_asset, then add an inputs[] entry for the input-files node id so it overrides the baked default:{
"node_id": "<input-files id from prepared.inputNodes>",
"content": [{ "url": "<uploaded csv url>", "mimeType": "text/csv" }]
}The CSV columns drive the parse-data fan-out (e.g. headline, subcopy, CTA) — do not also wire those as separate text inputs. A product image that's constant across every row (not a per-row CSV column) wires input-images directly into merge-data, bypassing parse-data entirely — this is the privileged default; only route an image through parse-data's media-override port when it genuinely varies per row.
When user provides custom .indd templates:
get_indesign_tags on each template.prepared.mergeNodes[].tags:
compose_workflow re-wire.background in retargeting), stop — offer defaults, different template, or build from scratch.Merge-data vs scene prompts: Only InDesign merge-port tags need user-facing text/image inputs. Keep gen-object-composite scene prompts at their defaults unless user asks to change them.
After run_workflow_submit, poll run_workflow_get_status every ~5 seconds with includeOutputs: true.
Running — N/M complete (X%) · Ns elapsed using elapsedSeconds from response.inspect_run, summarize, stop — do not auto-retry.| Slug / keyword | Use case |
|---|---|
product-banners-at-scale | Product banners from a CSV (data merge), one template + constant image, per-row copy |
retargeting | Retargeting ads |
localization | Localization |
generic-banner-advertising | Generic banners |
contextual-or-native-advertising | Native ads |
catalogs-and-circulars | Catalogs |
promotional-pricing-or-discounting | Pricing promos |
packaging-variants-2d | Packaging |
standardized-packshots-2d / 3d | Packshots |
refreshed-product-imagery-2d | Product imagery refresh |
composite-imagery-3d | 3D composite |
3d-spin-video | 360 spin video |
compose_workflow when featured workflow exists and tags matchsession_id is availablefonts on every merge-data input — use defaults.fontsuseSessionDefaults: true suffices