Connect AI assistants to OKZest with MCP
OKZest includes an MCP (Model Context Protocol) server so AI assistants and AI-powered tools can work directly with your designs.
Instead of building your own integration, you can connect your OKZest account and ask a tool such as Claude, ChatGPT, or Copilot to:
- List the designs and projects in your account
- Check which fields a design supports
- Generate a live personalised image URL
- Edit a design's layers and render a one-off image
- Create and save a new personalised design from a description
- Find a font to use in a design
What you need
Before you start, make sure you have:
- An OKZest account
- At least one design in your account
- An API key from Settings -> API Keys
- An MCP-compatible AI tool or client
The MCP server uses the same API key as the REST API.
MCP server URL
Your AI tool should connect to:
https://api.okzest.com/mcp
Example configuration
Many MCP clients let you define servers in a JSON config file.
Add an OKZest server like this:
{
"servers": {
"okzest": {
"url": "https://api.okzest.com/mcp",
"headers": {
"x-api-key": "YOUR_OKZEST_API_KEY"
}
}
}
}
Replace YOUR_OKZEST_API_KEY with an API key from Settings -> API Keys in your OKZest dashboard.
Keep your API key private. Do not paste it into public repos, public prompts, or client-side code.
Codex Desktop configuration
Codex Desktop reads MCP server settings from your Codex configuration file.
1. Store your API key in an environment variable
On Windows, open PowerShell and run the following, replacing the placeholder with your API key:
[Environment]::SetEnvironmentVariable("OKZEST_API_KEY", "YOUR_OKZEST_API_KEY", "User")
2. Add the MCP server to Codex
Open C:\Users\<your-username>\.codex\config.toml and add:
[mcp_servers.okzest]
url = "https://api.okzest.com/mcp"
env_http_headers = { "x-api-key" = "OKZEST_API_KEY" }
OKZest requires the x-api-key header. Do not use bearer_token_env_var for this connection.
3. Restart Codex
Restart Codex after saving the file so it can read the environment variable and load the MCP server. Then start a new task and ask, for example:
Using OKZest, list all the projects.
If authentication fails, confirm that the OKZEST_API_KEY environment variable contains a current API key from Settings -> API Keys in OKZest.
How it works
The MCP server gives your AI tool 15 OKZest actions.
The MCP server acts as the user who created the API key, with that user's project permissions, just like the dashboard. The AI tool only sees the projects that user is a member of, and only the designs in projects where they can view designs. Creating, editing and deleting designs need the matching permission in the project. list_projects shows what the user can do in each project.
1. Find your designs
Technical tool name: list_designs(projectName?, nameContains?, pageSize?, pageNumber?)
This lists every design in your account and returns:
- Design ID
- Design name
- Render URL
- Project ID and project name
- Available URL parameters
- Billing cycle open count
- Lifetime open count
All parameters are optional:
projectNamefilters the results to designs that belong to a project with that name (case-insensitive, exact match)nameContainsfilters the results to designs whose name contains the given text (case-insensitive substring match)pageSizeandpageNumberpage through the results together, for examplepageSize: 20, pageNumber: 2returns the second page of 20 designs
Leave all of them out to list every design in the account.
Use this when you want the AI tool to discover what is available in your account, narrow the search to a specific project or name, or work through a large account a page at a time, for example:
List my OKZest designs in the "Q1 Campaign" project.
Find my OKZest designs with "banner" in the name.
2. List your projects
Technical tool name: list_projects()
This lists every project in your account and returns:
- Project ID
- Project name
- Design count
- Billing cycle open count
- Lifetime open count
Use this when you want the AI tool to discover which projects exist before narrowing a list_designs search, or when you just want an overview of how designs are organised, for example:
What projects do I have in OKZest, and how many designs are in each?
3. Check what a design accepts
Technical tool name: get_design(id)
This returns the full details for one design, including the available URL parameters for dynamic text and image layers.
Always do this before generating a URL. It tells the AI tool the exact parameter names to use.
For example, a design might support parameters such as:
[
{ "name": "name" },
{ "name": "title" },
{ "name": "company" }
]
4. Generate a live image URL
Technical tool name: generate_image_url(designId, urlParams?, include_preview?)
This creates a runtime image URL for the design.
urlParams is optional and is passed as a JSON object string, for example:
{"name":"Jane","title":"CEO"}
The returned URL can be dropped straight into an email, web page, workflow, or automation step.
OKZest does not pre-render or save the image when this tool runs. It only returns a URL. The image is rendered fresh every time that URL is requested.
Set include_preview to true to also get a small preview of the image, so the AI tool can check the layout. See Previews.
5. Inspect editable layers
Technical tool name: get_design_fields(designId)
This returns the editable layers for a design, including each layer's layer_id, type, and the exact properties that layer supports.
For example, a text layer may support properties such as text, color, font_size, font_family, font_weight, x, y, width, height, opacity, and stroke, border, or shadow settings. An image layer may support properties such as image_url, x, y, width, height, and opacity.
This mirrors the REST endpoint GET /v1/images/{designId}/fields.
Use this when you want the AI tool to edit real layer properties instead of only filling URL parameters.
6. Modify layers and render an image
Technical tool name: modify_design_layers(designId, layersJson, backgroundJson?, format?, quality?, include_preview?)
This applies one or more layer edits, renders the image server-side, and returns:
imageUrlmimeType
The edits only apply to this render. The saved design does not change, so to keep a change, make it in the OKZest editor. This tool edits a design's existing layers and cannot add new ones; use create_design for that.
format is jpeg, png or webp. Leave it out to get a JPEG, or a PNG if the design has a transparent background (no background colour and no background image). quality (1-100) applies to JPEG and WebP only. Set include_preview to true to also get a small preview of the render; see Previews.
layersJson is passed as a JSON array string, for example:
[
{
"layer_id": "heading",
"text": "Hello",
"color": "#ff0000"
}
]
modify_design_layers returns a temporary URL
generate_image_url and modify_design_layers are not interchangeable.
generate_image_urlreturns a permanent runtime URL. Nothing is stored, so you can reuse that URL indefinitely.modify_design_layersrenders once, stores the result temporarily, and returns a temporary URL. The image is deleted after about a day.
Download, forward, or display the modify_design_layers result straight away. Do not save it as a permanent embed URL.
If you change font_family, use a value returned by list_fonts.
7. Find a font
Technical tool name: list_fonts(search?, projectId?)
This lists the fonts a design can use and returns, for each font:
font_family- the exact value to pass asfont_familyincreate_designormodify_design_layerslabel- the name shown in the editor's font pickersource-customfor fonts you have uploaded,msfor Microsoft fonts, orgooglefor Google Fonts
Uploaded fonts come first, then the Microsoft fonts, then the Google fonts. For an uploaded font, font_family is different from label, so always pass font_family.
Uploaded fonts are switched on per project in Custom fonts: a font is listed if it is on for that project or for every project. Pass projectId (from list_projects) to include that project's uploaded fonts. You can leave it out if your account has only one project; with more than one, leaving it out lists no uploaded fonts. A design can only use the uploaded fonts that are on for its own project.
There are about 1,750 fonts, so the tool returns at most 100. The response also includes total_count. If total_count is higher than the number of fonts returned, ask for a narrower search.
search is optional and matches the font name, ignoring case, for example:
list_fonts(search: "roboto", projectId: "YOUR_PROJECT_ID")
8. Create a new design
Technical tool name: create_design(name, width, height, layersJson, backgroundJson?, projectId?)
This creates and saves a new design in your account, the same as one made in the editor. It returns:
design- the saved design, including its design ID, render URL and URL parameterspreviewImageUrl- a temporary preview of the design with its default valuespreviewError- why the preview is missing, if it could not be rendered. The design is still saved.
The inputs are:
name- the design namewidthandheight- the canvas size in pixels, from 1 to 3508layersJson- a JSON array of layers, drawn in order, so later layers sit on topbackgroundJson- optional background colour, for example{"color":"#ffffff"}. The default is white.projectId- the project to save the design in. This is required if your account has more than one project, so ask the AI tool to calllist_projectsfirst, orcreate_projectto save it in a new project.
Each layer needs a layer_id (1-50 letters, numbers, - or _) and a type of text or image. It can also set any property modify_design_layers accepts, such as x, y, width, height, color, font_size, font_family, font_weight, text_align and opacity.
How personalisation works in a new design:
- Dynamic text: put the layer's own ID in square brackets in its text, for example
"text": "Hi [first_name]!"on a layer with"layer_id": "first_name". The placeholder is replaced by the URL parameter of the same name, anddefault_textis shown when no value is given. Leavetextout to get just the placeholder. - Static text: text without the placeholder never changes.
- Images: an image layer needs an
image_url, which is the default image. The URL parameter named after the layer swaps the image on each render. The image is resized to the layer's width and keeps its aspect ratio. - Background photo: add an image layer at
x0,y0, sized to the canvas, as the first layer.backgroundJsononly takes a colour. - Fonts:
font_familymust be a value returned bylist_fonts. Text layers use Open Sans by default.font_weighttakesbold,normalor a number from 100 to 900; 600 and above draws the font's bold file.font_styletakesitalic. A font without a bold or italic file, such as Anton, draws its regular file. The same applies whenmodify_design_layerschanges a layer's weight or style.
For example:
[
{
"layer_id": "first_name",
"type": "text",
"text": "Hi [first_name]!",
"default_text": "there",
"x": 40,
"y": 40,
"width": 520,
"font_size": 48,
"color": "#111111"
},
{
"layer_id": "photo",
"type": "image",
"image_url": "https://example.com/photo.jpg",
"x": 40,
"y": 160,
"width": 200,
"height": 200
}
]
This design gets two URL parameters, first_name and photo, so it is ready to use with generate_image_url straight away. You can open it in the OKZest editor to fine-tune it.
Unlike modify_design_layers, create_design saves: the design stays in your account until you delete it. Use generate_image_url on the new design for its permanent image URL; the preview URL expires.
create_design needs an API key that is linked to a user. If you see "This API key is not linked to a user", create a new API key in Settings -> API Keys and use that.
9. Create a project
Technical tool name: create_project(name)
This creates a new, empty project, the same as New project in the dashboard, and returns its project ID and name. Pass the project ID to create_design to save designs in it. For example:
Create an OKZest project called "Acme Spring Campaign" and make a 600x300 welcome banner in it.
Project names do not have to be unique, so the AI tool should call list_projects first and reuse a project that already exists.
The project is created as the user who created the API key, and that user is added to the project with full access. The user needs permission to create projects, the same permission that shows New project in the dashboard.
create_project needs an API key that is linked to a user. If you see "This API key is not linked to a user", create a new API key in Settings -> API Keys and use that.
10. Save changes to a design
Technical tool name: update_design_layers(designId, layersJson, backgroundJson?)
This saves layer edits to a design, for example to fix a typo or change a colour. It takes the same layersJson as modify_design_layers, but modify_design_layers only renders a one-off image, while this tool changes the saved design.
OKZest renders an image each time it is opened, so the change also shows in emails and pages you have already sent with this design.
- Text containing the layer's own ID in square brackets, for example
[first_name], stays personalised. Text without it is static. - A new
image_urlkeeps the layer's width, and its height follows the image's aspect ratio. backgroundJsontakes a colour only. Change a background image in the editor.
It returns the saved design and a temporary preview. It needs permission to edit designs in the design's project.
11. Copy a design
Technical tool name: duplicate_design(designId, name, projectId?)
This copies a design as a new design, with its own design ID, render URL and copies of its uploaded images. It is saved in the same project unless you give a projectId. This is handy for starting a new client's version of a template, for example with create_project first. It needs permission to create designs in the project the copy goes to.
12. Move a design
Technical tool name: move_design(designId, projectId)
This moves a design to another project. The design ID and render URL stay the same, so images already sent keep working. It needs permission to edit designs where the design is, and to create designs where it goes.
13. Rename a design or project
Technical tool names: rename_design(designId, name) and rename_project(projectId, name)
Renaming needs permission to edit designs in the project, or to edit the project. Render URLs do not change.
14. Delete a design
Technical tool name: delete_design(designId)
This deletes a design that has never been opened, such as a draft or a mistake the AI tool just made. A design that has been opened may be in emails or pages already sent, and deleting it would break those images, so the MCP server refuses. Delete those in the dashboard if you are sure. Previews in the dashboard and from the MCP server do not count as opens. It needs permission to delete designs in the design's project. Deleting cannot be undone.
15. Delete a project
Technical tool name: delete_project(projectId)
This deletes a project and every design in it, but only when none of those designs has ever been opened, such as an empty project or a draft project the AI tool just made. If even one design has been opened, the MCP server refuses and deletes nothing, because opened designs may be in emails or pages already sent. Delete those projects in the dashboard if you are sure.
It needs permission to delete projects (the same permission that shows Delete project in the dashboard) and permission to delete designs in that project. Other team members lose access to the project too. Deleting cannot be undone.
Previews
generate_image_url and modify_design_layers take an optional include_preview. Set it to true and the result also includes a small JPEG of the image (at most 512 pixels wide and 1024 tall, never enlarged, transparency shown on white), so the AI tool can see the layout without opening the URL.
- A preview counts as one render. For
modify_design_layersit is the same render, so the call still counts once. Forgenerate_image_url, which normally renders nothing, the preview renders the image once. - If the account has reached its plan limit, the preview shows the design's default text.
- PDF output has no preview, and a preview that fails or times out comes back as a short note instead. The URL is still returned.
Limits and tool hints
- Each account can make up to 120 MCP requests a minute. Over that, the server answers with HTTP 429.
- Up to 20 render calls a minute:
create_design,modify_design_layers, andgenerate_image_urlwithinclude_preview. Over that, the tool returns an error asking the AI tool to wait a minute and try again.
If you hit a limit, see Troubleshooting and FAQ.
Each tool also tells your AI tool what it does, so the tool can decide which calls to approve automatically. list_projects, list_designs, get_design, get_design_fields, list_fonts and generate_image_url only read. create_project, create_design and duplicate_design add a project or design, and modify_design_layers stores a temporary image. update_design_layers, move_design, rename_design and rename_project change saved designs or projects, and delete_design and delete_project delete a design or project that has never been opened.
Error messages
When a request is wrong, the MCP server tells your AI tool what to fix, so it can correct the call and try again. For example:
- An unknown design or project ID
- JSON in
layersJson,backgroundJsonorurlParamsthat cannot be read - A
font_familythat does not exist. The message suggests the right name when it is only a case or label mix-up, and says to calllist_fonts. - A canvas size outside 1-3508 pixels
- A user without permission for the action, for example to create projects or to edit designs in a project
- A design that cannot be deleted because it has been opened
- Too many render calls in a minute
Recommended workflow
For best results, ask your AI tool to follow one of these orders:
For discovering what you have
list_projectslist_designs(optionally filtered byprojectNameornameContains)
For URL-parameter personalisation
list_designsget_designgenerate_image_url
For layer editing
list_designsget_design_fieldslist_fonts(only if you are changing the font)modify_design_layers
For creating a new design
list_projects(if your account has more than one project)create_project(only if the design belongs in a new project)list_fontswith thatprojectId(if you want a font other than Open Sans)create_designgenerate_image_urlwith the new design ID
This helps the AI tool choose the right design and use valid parameter names or layer properties.
Worked example
Here is a simple example using an AI assistant to create a personalised image URL.
Step 1 - ask the assistant to find your design
List my OKZest designs and find the one for my welcome email banner.
The assistant should use list_designs and return the matching design. If you know which project it lives in, you can narrow the search with list_designs(projectName: "Marketing").
Step 2 - ask it to inspect the design
Get the details for that design and show me the available parameters.
The assistant should use get_design(id) and identify the parameter names, such as name and title.
Step 3 - ask it to create the URL
Generate a personalised image URL for Jane, title CEO.
The assistant should use:
generate_image_url(
designId: "YOUR_DESIGN_ID",
urlParams: "{\"name\":\"Jane\",\"title\":\"CEO\"}"
)
The result will be a live OKZest image URL that you can paste into an <img> tag, an email platform, or an automation tool.
Worked example: editing design layers
Here is a simple example using an AI assistant to edit a layer's text and colour before rendering the image.
Step 1 - ask the assistant to find your design
List my OKZest designs and find the one for my webinar banner.
The assistant should use list_designs and return the matching design.
Step 2 - ask it to inspect the editable layers
Show me the editable layers for that design and tell me which properties the heading layer supports.
The assistant should use get_design_fields(designId) and identify a layer such as heading with editable properties including text and color.
Step 3 - ask it to render the edited image
Change the heading text to Hello Jane and make it red.
The assistant should use:
modify_design_layers(
designId: "YOUR_DESIGN_ID",
layersJson: "[{\"layer_id\":\"heading\",\"text\":\"Hello Jane\",\"color\":\"#ff0000\"}]"
)
The result will be a temporary image URL. Use it straight away, before it is deleted. Add include_preview: true if you want the assistant to see the image and check it.
Worked example: creating a design
Here is a simple example using an AI assistant to build a new personalised design from scratch.
Step 1 - describe the design
Create an OKZest design called "Welcome banner", 600 by 300 pixels with a white background.
Add the text "Hi [first_name]!" in Montserrat, size 48, with "there" as the default,
and a profile photo layer on the right.
The assistant should call list_fonts(search: "montserrat") to get the exact font_family, then call create_design with the layers.
Step 2 - check the preview
The assistant gets back the saved design and a previewImageUrl. Ask it to show you the preview. If something looks wrong, ask for changes, or open the design in the OKZest editor.
Step 3 - use it
Generate a personalised image URL for Jane using that design.
The assistant should use generate_image_url with the new design ID and {"first_name":"Jane"}.
Good use cases
The MCP server is a good fit when you want an AI tool to help with:
- Email personalisation
- Sales outreach images
- Customer onboarding images
- Zapier or Make workflows
- A/B testing different personalised image variants
- Editing a design's layers programmatically via AI
- Creating new designs from a description, without opening the editor
- Auditing or organising a large design library by project, with search and pagination
If you are already using automation tools, see the Zapier integration page as well.
Authentication
OKZest authenticates MCP requests with the x-api-key HTTP header.
- Missing API key: the request is rejected
- Invalid API key: the request is rejected
- Valid API key: the AI tool acts as the user who created the key, with that user's project permissions
This is the same API key model used by the REST API.
When to use MCP vs REST API
Use MCP when you want an AI assistant or AI-powered tool to discover designs, create new designs, generate runtime image URLs, or render one-off layer-edited images for you. Creating designs and listing fonts are only available through MCP.
Use the REST API when you want to build a traditional coded integration or request binary image output directly.
Skill file for your AI tool
If your AI tool supports installable "skills" (for example, Copilot CLI, Claude, or other agent skill directories), you can download a ready-made skill file that teaches it the full OKZest MCP workflow:
Download okzest-image-generation SKILL.mdSave it into your tool's skills folder (e.g. .github/skills/okzest-image-generation/SKILL.md, .claude/skills/, or .agents/skills/) alongside the MCP server configuration above.