Tools Reference

All available MCP tools in Neleto

Neleto exposes 43 MCP tools across 8 categories. Each tool call requires an Authorization: Bearer <token> header.

All id fields for files and file-related tools are UUIDs (strings), while ids for pages, layouts, components, posts, and events are integers.
List & search responses are objects of the shape { "items": [...], "total": n } — never a bare top-level array.
Update tools replace the whole record.page_update, layout_update, and component_update overwrite every field; any field you omit is reset to its empty/default value, not left unchanged. Load the record first with the matching *_get, apply your edits, then send the complete object back.
Element data vs form defaultValue. In a component template {{ properties.x }} reads the element's data[x] and renders empty when the key is absent — defaultValue is only an editor seed and is not a render-time fallback. New elements are auto-seeded from each property's defaultValue, but populate data explicitly for anything you rely on. Render child elements with {{ render_elements(children) }} — the same helper as {{ render_elements(page.elements) }} and {{ render_elements(page.layout.elements) }}. Translatable fields (textarea / richtext / markdown) are only persisted when page_create / page_update is called with a language code, and element order is positional (a returned order of null is not meaningful).
Every element needs a tempId — including existing ones. In page_update / layout_update, each entry of the elements array must include a tempId string, even elements that already have a real numeric id. Omitting it rejects the whole request with missing field tempId. page_get / layout_get return every element with a tempId already set (existing elements come back as "old-<id>") — keep and resend that value unchanged. The elements array is replace-semantics: any existing element you leave out is silently deleted (no warning). To keep an element, resend it; to delete one, drop it from elementsand add its numeric id to deletedElements.
Shrink write responses with verbose: false.page_create / page_update, layout_create / layout_update, and component_create / component_update echo the full saved record by default (verbose: true) — for pages and layouts that nests every element's complete component definition, which is large. Pass verbose: false to get only the essentials instead: { id } for components, and { id, elements: [{ id, componentId, tempId, children }] } for pages and layouts — enough to learn the real ids assigned to newly-created elements without the record echo. Prefer it once a build works.
Attach images inline with sourceUrl — no separate upload step. In a page_* / layout_*elements payload, a relation property with relationName: "file" normally takes a stored file id. Instead you may put an ingest instruction in that data slot: { "sourceUrl": "https://…" } (optional keys: path, title, description, mimeType, status). During the same save the server fetches and stores the file and substitutes the resulting id — collapsing upload + wiring into one call. A multiple file relation takes an array mixing existing ids and such objects. Only declared file-relation slots are treated this way; every other data value is stored verbatim.

Pages

Tools for managing CMS pages.

page_list

List pages available in the CMS.

ids
integer[]
Filter by specific page IDs.
limit
integer
Maximum number of results to return.
offset
integer
Number of results to skip (for pagination).
language
"en" | "de"
Filter pages by language.

page_get

Load a single page with its layout, elements, and translated content.

Component definitions are deduplicated. By default each element's full component definition is not embedded per element (that duplicates the same large definition once per instance and blows the response token budget on element-heavy pages). Instead, unique components are collected once into a top-level components array, and each element keeps its componentId. The per-element component object and the top-level components array are read-only context — page_update ignores them, so you don't need to send them back.
id
integer required
The page ID.
lang
"en" | "de"
Language to load translated content in.
componentDetail
"lean" | "minimal" | "full"
How much component detail to return. lean (default) deduplicates components into the top-level components array, keeping each one's editing form schema but dropping the render-only style/script/template. minimal also drops form (smallest — fetch prop schemas via component_get). full restores the legacy behaviour of embedding the complete component inside every element (largest — avoid on big pages).

page_create

Create a new page including tags, meta tags, and elements.

title
string required
Page title.
route
string required
URL route for the page. Must start with / (e.g. /about).
useTailwind
boolean required
Whether to include Tailwind CSS for this page.
metaTags
object[] required
Array of meta tag objects.
tags
object[] required
Array of tag objects.
elements
object[] required
Array of page element objects.
deletedElements
integer[] required
IDs of elements to delete (use empty array [] for new pages).
template
string
Custom Handlebars template for the page.
renderMode
"prerendered" | "dynamic"
How the page is rendered. Defaults to prerendered.
layoutId
integer | null
Assign a layout to the page.
status
"draft" | "public" | null
Publication status.
description
string | null
Page description used in meta tags.
language
"en" | "de" | null
Language of the page.

page_update

Update an existing page including its nested elements. Same fields as page_create plus:

id
integer required
The ID of the page to update.

page_delete

Soft-delete a page.

id
integer required
The ID of the page to delete.

page_duplicate

Duplicate a page to a new route and title.

id
integer required
The ID of the page to duplicate.
title
string required
Title for the new duplicated page.
route
string required
URL route for the new page. Must start with / (e.g. /about-copy).

Layouts

Layouts are reusable templates that can be assigned to multiple pages.

layout_list

List page layouts.

limit
integer
Maximum number of results to return.
offset
integer
Number of results to skip.
language
"en" | "de"
Filter by language.

layout_get

Load a single layout with its element tree.

id
integer required
The layout ID.
lang
"en" | "de"
Language for translated element content.

layout_create

Create a reusable layout with template, style, script, and fixed elements.

name
string required
Display name for the layout.
elements
object[] required
Array of element objects included in the layout.
deletedElements
integer[] required
IDs of elements to delete (use [] for new layouts).
icon
string | null
Icon shown for the layout in the editor. Format is tabler:<icon-name> — an icon from the Tabler set (Iconify collection prefix tabler), exactly what the admin's icon picker stores. The filled variant adds a -filled suffix. Examples: tabler:layout-grid, tabler:layout-navbar, tabler:columns. A bare word without the tabler: prefix does not resolve.
template
string
Handlebars template string.
script
string
JavaScript to include.
style
string
CSS styles for the layout.
language
"en" | "de" | null
Language context.

layout_update

Update an existing layout including its element tree. Same fields as layout_create plus:

id
integer required
The ID of the layout to update.

layout_delete

Soft-delete a layout.

id
integer required
The ID of the layout to delete.

Components

Components are reusable building blocks that editors can insert on pages.

component_list

List all reusable CMS components. Returns a lightweight summary per component (id, label, category, icon, canHaveChildren) — enough to find a component and resolve its id cheaply. Load a component's full definition (template/style/script/form) with component_get.

limit
integer
Max number of components to return.
offset
integer
Number of components to skip.
language
"en" | "de"
Language for localized fields.
verbose
boolean
Response size control (default false). false returns lightweight summaries; true embeds each component's full definition (template/style/script/form) — much larger, avoid unless you really need them all.

component_get

Load a single component by ID.

id
integer required
The component ID.

Search components by form label. Returns the same lightweight summary shape as component_list.

q
string required
Search query.
verbose
boolean
Response size control (default false). false returns lightweight summaries; true embeds each match's full definition.

component_used_by_elements

List all element instances that use a given component.

id
integer required
The component ID to search usage for.

component_create

Create a new component.

icon
string required
Icon shown for the component in the editor. Format is tabler:<icon-name> — an icon from the Tabler set (Iconify collection prefix tabler), exactly what the admin's icon picker stores. The filled variant of an icon adds a -filled suffix. Examples: tabler:award-filled, tabler:message-circle-2, tabler:layout-grid. A bare word without the tabler: prefix does not resolve and renders no icon. (The i-tabler-<icon-name> class form also renders, but tabler:<icon-name> is canonical.)
form
object required
Form definition describing the component's properties.
style
string required
CSS styles for the component.
script
string
JavaScript for the component. Optional — omit or pass "" for a component with no script.
template
string required
Handlebars template string for the component. Render form values with {{ properties.<key> }} and child elements with {{ render_elements(children) }}.
category
"text" | "design" | "layout" | "interactive" | "media" | "misc" required
Component category for grouping in the editor.
canHaveChildren
boolean required
Whether child elements can be nested inside this component.

Images (file relations). A relation value is not a file until you bind it. Bind the file out of the relation, then pass the bound file to image_path together with a required options string. Calling image_path(file) with no options, or passing relations.<id> unbound, is a hard render error — not an empty src:

{{#if relations.image as file}}
  <img src="{{ image_path(file, "w_1600,f_webp") }}" alt="{{ file.title }}">
{{/if}}

This serves /image/user-upload/<file-id>?options=w_1600,f_webp. Options are comma-separated and applied in order — s_<N> (square), w_<N>, h_<N>, f_webp|jpeg|png|avif|gif, q_<N> (jpeg quality), e_<t>_<l>_<w>_<h> (crop), fit_contain|fit_cover|fit_fill|fit_inside|fit_outside — see image scaling. Other relation helpers follow the same bind-first rule: post_path(post), event_path(event), and file_path(file) for downloads. For a multiple relation, iterate with {{#each relations.<id> as file}} … {{/each}}.

f_ is format only — fit uses fit_.f_ sets the output format (f_webp, f_jpeg, …). Fit/crop is a separatefit_ prefix (fit_cover, fit_contain, …). There is no f_cover/f_contain — writing one is parsed as a format, fails validation, and returns a hard HTTP 400 (no graceful fallback to the original). fit_ also only works alongside a size and must appear after the w_/h_/s_ in the string. For simple cropping/aspect control, prefer CSS object-fit on the <img> — it is more predictable than the fit_ option.

Builder (repeater) form property. A builder property is a repeater: the editor manages an array of rows that all share the same fields. Its JSON shape is easy to get wrong. The property definition's items array holds exactly one entry — a single row template — and the per-row fields live inside that entry's props array (not as separate items entries):

{
    "id": "items",
    "type": "builder",
    "label": { "en": "Questions", "de": "Fragen" },
    "description": null,
    "hint": null,
    "required": null,
    "defaultValue": [
        { "id": "row1", "data": { "question": "...", "answer": "..." } },
        { "id": "row2", "data": { "question": "...", "answer": "..." } }
    ],
    "items": [
        {
            "id": "question",
            "type": "text",
            "name": "question",
            "label": { "en": "Item", "de": "Item" },
            "icon": null,
            "items": [],
            "data": "",
            "defaultValue": "",
            "property": { "type": "text", "defaultValue": "" },
            "props": [
                {
                    "id": "question",
                    "type": "textarea",
                    "label": { "en": "Question", "de": "Frage" },
                    "defaultValue": null,
                    "description": null,
                    "hint": null,
                    "required": null
                },
                {
                    "id": "answer",
                    "type": "textarea",
                    "label": { "en": "Answer", "de": "Antwort" },
                    "defaultValue": null,
                    "description": null,
                    "hint": null,
                    "required": null
                }
            ]
        }
    ]
}
  • items = exactly one row-template object. The real per-row fields (question, answer, …) are plain flat property definitions inside its props array.
  • The row-template object still needs top-level id, name, data, defaultValue, items ([]), and a property object ({ type, defaultValue }). Strictly required by the deserializer are label, name, data, props; the rest mirror what the admin Builder Configuration editor emits — include them so the definition round-trips through the UI.
  • Set the row-template's data and defaultValue to "" (empty string). Do not use a real placeholder string: on save the admin builder editor spreads a non-empty string's characters into every row's data as stray numeric keys ({"0":"H","1":"o",…}). It doesn't break rendering but corrupts the stored data (known admin-UI bug); "" avoids it.
  • Row values — both the property's top-level defaultValue and each element's data[<propId>] — are an array of { id, data } objects, not a flat { fieldId: value } per row: [ { "id": "row1", "data": { "question": "…", "answer": "…" } } ].
  • In the template, read row values via item.data.<fieldId> (not item.<fieldId>):
{{#each properties.items as item}}
    {{item.data.question}}
    {{item.data.answer}}
{{/each}}
Component CSS injection order is not guaranteed. Each component's style block is hoisted into <head>, but the order in which different components' styles are injected does not necessarily follow page/element order. When two components set the same property on a shared utility class used together on one element (e.g. a shared .wrap plus a component-specific class), the cascade can resolve unpredictably. Scope component-specific overrides with a more specific selector (e.g. .myComponentClass .wrap { … } rather than bare .wrap { … }) so they win regardless of injection order.

component_update

Update an existing component. Same fields as component_create plus:

id
integer required
The ID of the component to update.

component_delete

Delete a component and all element instances linked to it.

id
integer required
The ID of the component to delete.

Blog Posts

post_list

List blog posts.

ids
integer[]
Filter by specific post IDs.
limit
integer
Maximum number of results.
offset
integer
Number of results to skip.

post_get

Load a blog post by ID.

id
integer required
The post ID.

post_search

Search posts by title, description, or content.

q
string required
Search query.

post_create

Create a blog post.

slug
string required
URL-friendly identifier for the post.
title
string required
Post title.
description
string required
Short description shown in listings.
content
string required
Richtext content. HTML is allowed.
language
string required
Language of the post (e.g. "en" or "de").
metadata
object required
Post metadata object (can be an empty object {}).
tags
object[] required
Array of tag objects.
files
object[] required
Array of associated file objects.
status
"draft" | "public" | null
Publication status.
publishDate
string | null
ISO 8601 publish date.
heroImageId
string | null
UUID of the hero image file.
heroImage
object | null
Hero image file object (alternative to heroImageId).

post_update

Update a blog post. Same fields as post_create plus:

id
integer required
The ID of the post to update.

post_delete

Delete a blog post.

id
integer required
The ID of the post to delete.

Events

event_list

List events.

ids
integer[]
Filter by specific event IDs.
limit
integer
Maximum number of results.
offset
integer
Number of results to skip.

event_get

Load an event by ID.

id
integer required
The event ID.

Search events by title, description, or content.

q
string required
Search query.

event_today

List all events happening today.

No parameters required.

event_upcoming

List upcoming events.

No parameters required.

event_create

Create an event.

slug
string required
URL-friendly identifier for the event.
title
string required
Event title.
description
string required
Short event description.
content
string required
Richtext content. HTML is allowed.
status
"draft" | "public" required
Publication status.
metadata
object required
Event metadata (can be an empty object {}).
tags
object[] required
Array of tag objects.
files
object[] required
Array of associated file objects.
publishDate
string | null
ISO 8601 publish date.
start
string | null
ISO 8601 start date/time.
end
string | null
ISO 8601 end date/time.
heroImageId
string | null
UUID of the hero image file.
heroImage
object | null
Hero image file object (alternative to heroImageId).

event_update

Update an event. Same fields as event_create plus:

id
integer required
The ID of the event to update.

event_delete

Delete an event.

id
integer required
The ID of the event to delete.

Files

File IDs are UUIDs (strings), not integers.

file_list

List files, folders, or load a single file with optional content. File records include a serveUrl — an absolute …/image/user-upload/<id> URL that serves the stored bytes.

path
string | null
List contents of a folder path (e.g. "/" for root), or load a specific file by path.
mimeType
string[] | null
Filter by MIME type (e.g. ["image/jpeg", "image/png"]).
ids
string[] | null
Load specific files by UUID.

file_get

Load a file with its tags by ID. The record includes a serveUrl — an absolute …/image/user-upload/<id> URL that serves the stored bytes.

id
string required
The file UUID.

Search files by title, description, path, status, or MIME type.

q
string | null
Search query (title, description, or path).
onlyFiles
boolean | null
If true, exclude folders from results.
status
"draft" | "public" | null
Filter by status.
allowedMimeTypes
string[]
Filter by allowed MIME types.

file_create

Create a file, folder, or remote file entry. Local files are created empty on disk.

type
"folder" | "file" | "remoteFile" required
The type of entry to create.
path
string required
Full path including file name (e.g. "/images/logo.png").
tags
object[] required
Array of tag objects.
status
"draft" | "public" | null
Publication status.
title
string | null
Display title for the file.
mimeType
string | null
MIME type of the file.
description
string | null
File description.
metadata
object
File metadata.

file_upload

Upload a binary file or image. Provide the bytes one of two ways: sourceUrl (an http(s) URL the server fetches itself) or base64Data (inline base64). Exactly one is required. On success the response includes the stored byte size and a ready-to-use serveUrl (absolute …/image/user-upload/<id> URL); that URL also accepts ?options=w_200,f_webp-style resizing.

Prefer sourceUrl for anything non-trivial. When you pass a sourceUrl the server downloads the file directly, so nothing large travels through the tool call and there is no corruption risk. Point it at an existing serveUrl, a generated-image URL, or any hosted file. Use inline base64Data only for small payloads.
Inline base64 reliability.base64Data travels inline as a tool-call argument, and large payloads can be corrupted in transit before they reach the server. Line-wrapped/whitespaced base64 is accepted (whitespace is stripped before decoding), and on a decode failure the error states whether the payload looks truncated (length not a multiple of 4) or corrupted. If you hit either, switch to sourceUrl rather than resending the same bytes.
path
string required
Full destination path including file name.
sourceUrl
string | null
An http(s) URL the server fetches the bytes from itself. Preferred over base64Data for anything larger than a few KB; takes precedence when both are set.
base64Data
string | null
The file content as a base64-encoded string (raw base64 or a data:image/…;base64,… data-URI). Required only when sourceUrl is not given.
mimeType
string | null
MIME type (e.g. "image/png"). Falls back to the sourceUrl response's Content-Type, then to guessing from the path.
status
"draft" | "public" | null
Publication status.
title
string | null
Display title.
description
string | null
File description.
metadata
object
File metadata.
tags
object[] | null
Array of tag objects.
handleConflicts
boolean | null
Whether to auto-resolve path conflicts.

file_upload_begin / file_upload_chunk / file_upload_commit

Chunked upload for when you must send bytes inline (no sourceUrl) and they're too large to survive a single file_upload call. The file is streamed in small base64 slices and verified with a SHA-256 checksum, so a corrupt transfer fails loudly instead of storing garbage.

Prefer sourceUrl on plain file_upload whenever the file is reachable by URL — it's a single call with no corruption risk. Use chunking only as the inline-safe fallback.

Flow:

  1. file_upload_begin with the destination path (+ optional mimeType, status, title, description, metadata, tags, handleConflicts) → returns { uploadId, maxBytes }.
  2. file_upload_chunk repeatedly with { uploadId, data }data is base64 (raw or whitespace-wrapped) for the next slice, in order. Keep chunks small (roughly a few KB of raw bytes) so the base64 is short enough to emit without drift. Optionally pass sha256 (lowercase hex of that chunk's raw bytes); a mismatch rejects just that chunk. Returns { receivedBytes }.
  3. file_upload_commit with { uploadId, sha256 } (lowercase hex of the whole file, plus optional totalSize) → the server reassembles, verifies, stores the file, and returns the same { size, serveUrl, … } payload as file_upload.
  4. file_upload_abort with { uploadId } (optional) → discards a partial upload and its temp file when it can't be finished. An unknown or already-finished uploadId is a no-op.

Uploads that stay idle for an hour (no committed and no new chunk) are swept automatically, and any leftover temp files are cleaned up on server restart. Chunks must be sent by the same user that began the upload.

file_update

Update file metadata or content for local files.

id
string required
The file UUID.
fileType
"local" | "remote" required
Whether the file is stored locally or remotely.
tags
object[] required
Updated array of tag objects.
type
"folder" | "file" | "remoteFile" | null
Change the entry type.
path
string | null
New path for the file.
status
"draft" | "public" | null
Publication status.
title
string | null
Display title.
mimeType
string | null
MIME type.
description
string | null
File description.
metadata
object
File metadata.
content
string | null
New text content for local files.

file_delete

Delete one or more files or folders.

ids
string[] required
Array of file UUIDs to delete.

file_move

Move or copy files into another folder path.

ids
string[] required
Array of file UUIDs to move (or copy).
path
string required
Destination folder path (e.g. "/images/archive").
copy
boolean | null
If true, copy the files instead of moving them.

file_rename

Rename a file or folder by changing the last segment of its path.

id
string required
The file UUID to rename.
name
string required
The new file/folder name (just the last segment, not the full path).

Web Files

Web files are static text files served at the root of your site (e.g. /sitemap.xml, /llms.txt, /llms-full.txt). Each file has a unique path, raw text content, and a MIME content type derived from the path's extension.

web_file_list

List all web files.

No parameters required.

web_file_get

Get a single web file by path.

path
string required
The file path (e.g. "sitemap.xml").

web_file_create

Create a new web file served at /<path>.

path
string required
The path at which this file is served (e.g. "sitemap.xml", "blog/llms.txt"). Slashes are allowed to nest files. Must be unique.
content
string required
The raw text content of the file.

web_file_update

Update the content of an existing web file by path.

path
string required
The path of the file to update.
content
string required
New content for the file.

web_file_delete

Delete a web file by path.

path
string required
The path of the file to delete.

Settings

settings_get

Load CMS settings with resolved page references and meta tags. The response also exposes the live instance's public URLs, so an agent can screenshot or verify the site it builds:

  • publicBaseUrl — the host the site is served from (e.g. https://yannik.free.neleto.io).
  • imageBaseUrl — the prefix served uploads live under (e.g. …/image/user-upload).
  • adminUrl — the editor URL.
language
string
Language context for resolved page references.

settings_update

Update CMS settings. All fields are optional - only provided fields are changed.

title
string
Site title.
robots
string
robots.txt content.
fallbackPageId
integer | null
Page to serve for unknown routes (404 fallback).
blogPostPageId
integer | null
Page used to render individual blog posts.
eventPostPageId
integer | null
Page used to render individual event detail pages.
faviconId
string | null
UUID of the favicon file.
fileDefaultStatus
"draft" | "public"
Default status for newly uploaded files.
postDefaultStatus
"draft" | "public"
Default status for newly created blog posts.
pageDefaultStatus
"draft" | "public"
Default status for newly created pages.
eventDefaultStatus
"draft" | "public"
Default status for newly created events.
metaTags
object[]
Global meta tags applied to all pages.
emailHost
string
SMTP host.
emailPort
integer
SMTP port.
emailUser
string
SMTP username.
emailPassword
string
SMTP password.
emailFrom
string
Sender address for outgoing emails.
emailTls
"tls" | "start-tls" | "none"
TLS mode for SMTP connection.
defaultLanguage
string
Default language for the site.
languages
object[]
Available site languages. Each entry needs value (e.g. "en") and label (e.g. "English").
autoDetectBestLanguage
boolean
Automatically redirect visitors to their preferred language.
maxUploadFileSizeMb
integer
Maximum file upload size in megabytes.
tailwindConfig
string
Global Tailwind CSS configuration.