MCP
Generate files with MCP tools
Learn how to list templates, generate images and PDFs, and compose images from shapes with the Bannerify MCP tools.
The Bannerify MCP server has six tools. The assistant picks them from your request, so you rarely call one by name. Every tool works only on the workspace of the connection. Connect an MCP client first if you have not.
Tools
| Tool | What it does | Counts as a generation | Arguments |
|---|---|---|---|
list_templates |
Lists the templates in the workspace. With includeLayers, it also lists the layers you can change |
No | includeLayers (boolean, optional) |
get_template |
Reads one template and its layers | No | templateId (string) |
get_project |
Reads the workspace: its id, name, plan, and creation date | No | None |
create_image |
Renders a template and returns the image | Yes | templateId (string), modifications (object, optional), format (png, jpeg, or webp, default png) |
create_pdf |
Renders a template as a PDF and returns a link to it | Yes | templateId (string), modifications (object, optional) |
create_image_from_shapes |
Composes an image from shapes, with no template | Yes | canvas (object, optional), shapes (array), format (png, jpeg, or webp, default png) |
Use a template id exactly as list_templates returns it.
Find a template
Ask for the templates and their layers:
List my Bannerify templates, with the layers of each one.
The tool returns one entry for each template. Without includeLayers, an entry holds only the id and the name. With it, each layer comes with the name to use in modifications:
[
{
"id": "tpl_xxx",
"name": "Lifecycle email",
"layers": [
{ "name": "headline", "id": "shape:abc123", "type": "text", "suggestInput": "text" },
{ "name": "photo", "id": "shape:def456", "type": "image", "suggestInput": "src" },
{ "name": "qr", "id": "shape:ghi789", "type": "qrcode", "suggestInput": null }
]
}
]
suggestInput names the field to set: text for a text layer, src for an image layer, and null for every other type. A layer without a name shows as Untitled.
Layer names come from the template editor, where you rename a layer by double-clicking it. Modifications explains how a name matches a layer.
Pass layer values
modifications is an object keyed by layer name. A string sets the text of the layer, and an object sets the fields of that layer. The array format of the REST API is not valid here.
| Layer | Example value |
|---|---|
| Text | { "headline": "Summer sale" } |
| Image | { "photo": { "src": "https://example.com/photo.png" } } |
| QR code | { "qr": { "qrcode": "https://example.com/restart" } } |
| Table | { "prices": { "columns": ["Plan", "Price"], "rows": [{ "Plan": "Automate", "Price": "$29" }] } } |
| Any layer | { "tag": { "visible": false } } |
A full example for create_image:
{
"templateId": "tpl_xxx",
"format": "png",
"modifications": {
"headline": "Welcome back, An",
"photo": { "src": "https://example.com/hero.png" },
"qr": { "qrcode": "https://example.com/restart" }
}
}
A layer that you leave out keeps the values from the template, and a name that matches no layer is ignored. Modifications lists the fields of every layer type.
Read the result
create_image returns the image inline, with a line that gives its format and size in bytes. Your client decides how to show or save the image.
create_pdf stores the file and returns a link:
Generated a PDF from template tpl_xxx. Download: https://images.bannerify.co/files/mcp/0b3c1c1e-5d6f-4c52-9e0a-8f6a4c0f2a11.pdf
The PDF has one page with the size of the canvas, and its text can be selected and searched. Generate PDFs has the details.
Compose an image without a template
Use create_image_from_shapes when no template fits. Give the tool a canvas and a list of shapes. It draws the shapes in order and returns the image, so the assistant can design a one-off banner or invoice.
The canvas object is optional. It is 1200 by 630 pixels and white unless you set these fields:
| Field | Description |
|---|---|
width, height |
The size in pixels, from 16 to 4096 on each side |
background |
A solid color. The default is white |
backgroundImage |
An HTTPS URL, a data URL, or a CSS gradient such as linear-gradient(to right, #4f46e5, #9333ea). It wins over background |
objectFit |
How the background image fills the canvas: cover (default), contain, or none |
Every shape has type, x, y, width, and height, in pixels from the top left of the canvas. The first shape is at the back and the last is on top. Three more fields work on every type: opacity (0 to 1), rotation (degrees, clockwise), and style.
| Type | Required | Optional |
|---|---|---|
text |
text |
fontSize (default 24), align (left, center, or right), lineClamp, color, fontFamily, fontWeight |
frame |
None | backgroundColor, borderColor, borderWidth, borderRadius |
image |
src |
objectFit (fill, contain, cover, none, or scale-down; default cover), borderRadius |
qrcode |
qrcode |
backgroundColor |
barcode |
barcode |
None |
icon |
icon |
color |
star |
None | star (1 to 5, default 1), color |
table |
columns, rows |
footer, variant, stripe, compact, fontFamily, align (left, center, or right) |
A few rules:
icontakes an Iconoir name, for examplecheck-circleorarrow-right. A name that Iconoir does not have fails the call.srctakes an HTTPS URL or a data URL. A remote image loads with the same rules as in a template: PNG, JPEG, WebP, or SVG, and a failed download returnsFETCH_IMAGE_ERROR.- A table has one value per column in every row. This differs from
modifications, where a row is an object.variantisline,grid(default),minimal,striped,compact,bordered, orprimary-header. styletakes CSS property names in camelCase, for examplepadding,boxShadow,lineHeight, andletterSpacing. A key that the renderer does not support fails the call with anUnrecognized keymessage. Set the size withwidthandheight, not withstyle.- A field on the shape, such as
colororborderRadius, wins over the same key instyle. - A color is a hex value,
rgb(),hsl(), or a CSS color name.
| Limit | Value |
|---|---|
| Shapes | 1 to 100 |
| Canvas | 16 to 4096 pixels on each side, and at most 12,000,000 pixels in total |
| Text | 4,000 characters |
| Table | 12 columns and 200 rows |
src and backgroundImage |
8,192 characters |
qrcode value |
2,000 characters |
barcode value |
200 characters |
A full example, an invoice:
{
"canvas": { "width": 800, "height": 560, "background": "#f8fafc" },
"shapes": [
{ "type": "frame", "x": 0, "y": 0, "width": 800, "height": 120, "backgroundColor": "#0f172a" },
{ "type": "text", "x": 48, "y": 44, "width": 400, "height": 40, "text": "INVOICE", "fontSize": 30, "color": "#ffffff" },
{ "type": "text", "x": 500, "y": 52, "width": 252, "height": 24, "text": "INV-1042", "fontSize": 18, "align": "right", "color": "#94a3b8" },
{
"type": "table",
"x": 48,
"y": 176,
"width": 704,
"height": 180,
"columns": ["Item", "Qty", "Total"],
"rows": [["Logo pack", 1, "$29.00"], ["Banner credits", 500, "$19.00"]],
"footer": ["", "Due", "$48.00"],
"variant": "striped",
"compact": true
},
{ "type": "text", "x": 48, "y": 392, "width": 300, "height": 28, "text": "Thank you for your business.", "fontSize": 16, "color": "#475569" },
{ "type": "qrcode", "x": 632, "y": 384, "width": 120, "height": 120, "qrcode": "https://bannerify.co/invoices/1042" }
]
}
Bannerify checks the whole request before it renders, so an invalid request does not use a generation. A valid one counts like a generation from a template. See Quota and limits.
Handle errors
A failed call returns isError: true and a text message in one of two forms:
| Form | Meaning |
|---|---|
CODE: message, for example NOT_FOUND: template tpl_xxx not found |
An error from Bannerify. The next table lists the codes |
Invalid arguments. <field>: <message> |
The arguments do not match the tool, and the message names the field. This form has no code |
| Code | Meaning | What to do |
|---|---|---|
NOT_FOUND |
The template does not exist in this workspace. A template of another workspace is not found either | Run list_templates and use an id from the result |
USAGE_EXCEEDED |
The workspace reached its monthly or daily generation limit | Wait for the next period, or see Quota and limits |
BAD_REQUEST |
A color or style value in create_image_from_shapes is not valid, or a value in modifications does not fit its layer field |
Fix the value that the message names. For modifications, the message gives the position of the layer in your object, counted from 0, for example modifications[0].src |
FETCH_IMAGE_ERROR |
An image could not be downloaded, or is too large to decode | Use a public URL that returns an image |
INTERNAL_SERVER_ERROR |
The render failed, or an icon name does not exist in Iconoir |
Try again, and check the icon names |
A missing or expired token gets HTTP 401 with the error invalid_token before any tool runs, so a tool never returns UNAUTHORIZED. Your client then signs in again. RATE_LIMITED and TOO_MANY_REQUESTS do not occur, because the MCP server has no request rate limit. Handle errors lists the codes of the REST API.