> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.bannerify.co/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP tools

> Read templates and generate images and PDFs from an MCP client.

The Bannerify MCP server exposes six tools. The assistant picks them automatically from your request, so you rarely call them by name.

Every tool works only on the workspace that approved the connection.

## Tools

| Tool | What it does | Arguments |
| - | - | - |
| `list_templates` | Lists the templates in the workspace, with the layers you can override | `includeLayers` (boolean, optional) |
| `get_template` | Reads one template and its layers | `templateId` (string) |
| `get_project` | Reads the linked project, its plan, and its creation date | none |
| `create_image` | Renders a template and returns the image | `templateId` (string), `modifications` (object, optional), `format` (`png`, `jpeg`, `webp`) |
| `create_pdf` | Renders a template as a PDF and returns a download link | `templateId` (string), `modifications` (object, optional) |
| `create_image_from_shapes` | Composes an image from shapes, with no template | `shapes` (array), `canvas` (object, optional), `format` (`png`, `jpeg`, `webp`) |

A template id looks like `tpl_xxxxx`.

## Find a template

Ask for the templates and their layers:

```text theme={null}
List my Bannerify templates, with the layers of each one.
```

The answer names every template and, for each layer, the name to use in `modifications`, for example:

```json theme={null}
[
  {
    "id": "tpl_lifecycle",
    "name": "Lifecycle email",
    "layers": [
      { "name": "headline", "type": "text", "suggestInput": "text" },
      { "name": "photo", "type": "image", "suggestInput": "src" },
      { "name": "qr", "type": "qrcode", "suggestInput": null }
    ]
  }
]
```

Layer names come from the template editor, so keep them descriptive: `headline`, `price`, `qr`, `photo`.

## Pass layer values

`modifications` is an object keyed by layer name. A string sets the text of a layer. An object sets that layer's own fields.

| Layer type | Example value |
| - | - |
| Text | `{ "headline": "Summer sale" }` |
| Image | `{ "photo": { "src": "https://example.com/photo.png" } }` |
| QR code | `{ "qr": { "qrcode": "https://example.com/restart" } }` |
| Table | `{ "table": { "rows": [["Plan", "Price"], ["Pro", "$29"]] } }` |
| Any layer | `{ "tag": { "visible": false } }` |

A full example for `create_image`:

```json theme={null}
{
  "templateId": "tpl_lifecycle",
  "format": "png",
  "modifications": {
    "headline": "Welcome back, An",
    "price": "$29",
    "photo": { "src": "https://example.com/hero.png" },
    "qr": { "qrcode": "https://example.com/restart" }
  }
}
```

Layers you leave out keep the values from the template.

## Read the result

`create_image` returns the image itself, so the assistant can show it or save it to a file. `create_pdf` stores the file and returns a link:

```text theme={null}
Generated a PDF from template tpl_lifecycle. Download: https://images.bannerify.co/files/mcp/9f1c....pdf
```

The link points to the Bannerify CDN and stays available like any other stored asset.

## 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, label, or invoice.

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.

| Type | Required | Optional |
| - | - | - |
| `text` | `text` | `fontSize` (24), `align` (`left`, `center`, `right`), `lineClamp`, `color`, `fontFamily`, `fontWeight` |
| `frame` | — | `backgroundColor`, `borderColor`, `borderWidth`, `borderRadius` |
| `image` | `src` | `objectFit` (`cover`), `borderRadius` |
| `qrcode` | `qrcode` | `backgroundColor` |
| `barcode` | `barcode` | — |
| `icon` | `icon` | `color` |
| `star` | — | `star` (1 to 5), `color` |
| `table` | `columns`, `rows` | `footer`, `variant`, `stripe`, `compact`, `align`, `fontFamily` |

A few rules:

* `icon` takes an [Iconoir](https://iconoir.com) name, for example `check-circle` or `arrow-right`.
* `src` and `canvas.backgroundImage` take an HTTPS URL or a data URL. `canvas.backgroundImage` also takes a CSS gradient, for example `linear-gradient(to right, #4f46e5, #9333ea)`.
* `style` takes CSS property names for the rest: `padding`, `boxShadow`, `borderStyle`, `lineHeight`, and similar. Set the size with `width` and `height`, not with `style`.
* Table `columns` are the headers and `rows` hold one value per column in the same order.
* Limits: 1 to 100 shapes, 16 to 4096 pixels on each side of the canvas, 4000 characters of text, 200 table rows, 12 table columns.

The canvas is white unless `canvas.background` is set. `canvas.backgroundImage` wins over `canvas.background`.

A full example: an invoice.

```json theme={null}
{
  "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" }
  ]
}
```

A generation from shapes counts against the same monthly and daily quota as a generation from a template. See [Quota and limits](/account/quota).

## Handle errors

A failed tool call returns a message with the error code, using the same codes as the REST API:

| Code | Meaning | What to do |
| - | - | - |
| `NOT_FOUND` | The template does not exist in this workspace | Run `list_templates` and use a returned id |
| `UNAUTHORIZED` | The connection is no longer valid | Remove the server from your MCP client and add it again |
| `USAGE_EXCEEDED` | The workspace reached its monthly or daily generation limit | Wait for the next period, or check [Quota and limits](/account/quota) |
| `TOO_MANY_REQUESTS` | Too many requests arrived in a short time | Retry after a short wait |
| `BAD_REQUEST` | A layer value does not match its layer, or a shape spec is not valid | Check the layer with `get_template`, or the shape fields above |
| `FETCH_IMAGE_ERROR` | A remote image could not be downloaded | Use a public URL that returns an image |

See [Errors](/api-reference/errors/introduction) for the full list.

## Learn more

* [Connect an MCP client](/mcp/overview)
* [Create an image](/api-reference/endpoint/create-image)
* [Template elements](/essentials/elements)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.