# Generate files with MCP tools

> Learn how to list templates, generate images and PDFs, and compose images from shapes with the Bannerify MCP tools.

Canonical: https://bannerify.co/docs/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](https://bannerify.co/docs/mcp/overview) 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:

```text
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`:

```json
[
  {
    "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](https://bannerify.co/docs/essentials/modifications#name-your-layers) 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`:

```json
{
  "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](https://bannerify.co/docs/essentials/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:

```text
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](https://bannerify.co/docs/essentials/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:

- `icon` takes an [Iconoir](https://iconoir.com) name, for example `check-circle` or `arrow-right`. A name that Iconoir does not have fails the call.
- `src` takes 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 returns `FETCH_IMAGE_ERROR`.
- A table has one value per column in every row. This differs from `modifications`, where a row is an object. `variant` is `line`, `grid` (default), `minimal`, `striped`, `compact`, `bordered`, or `primary-header`.
- `style` takes CSS property names in camelCase, for example `padding`, `boxShadow`, `lineHeight`, and `letterSpacing`. A key that the renderer does not support fails the call with an `Unrecognized key` message. Set the size with `width` and `height`, not with `style`.
- A field on the shape, such as `color` or `borderRadius`, wins over the same key in `style`.
- 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:

```json
{
  "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](https://bannerify.co/docs/account/quota).

## 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](https://bannerify.co/docs/account/quota) |
| `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](https://bannerify.co/docs/api-reference/errors/introduction) lists the codes of the REST API.

## Learn more

- [Connect an MCP client](https://bannerify.co/docs/mcp/overview)
- [Modifications](https://bannerify.co/docs/essentials/modifications)
- [Layer types](https://bannerify.co/docs/essentials/elements)

## Related

- [Previous: Connect an MCP client](https://bannerify.co/docs/mcp/overview)
- [Next: Generate from the terminal](https://bannerify.co/docs/cli/overview)
- [Documentation index](https://bannerify.co/docs/llms.txt)
