Tools Reference
Neleto exposes 43 MCP tools across 8 categories. Each tool call requires an Authorization: Bearer <token> header.
id fields for files and file-related tools are UUIDs (strings), while ids for pages, layouts, components, posts, and events are integers.{ "items": [...], "total": n } — never a bare top-level array.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.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).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.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.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.
page_get
Load a single page with its layout, elements, and translated content.
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.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.
/ (e.g. /about).[] for new pages).page_update
Update an existing page including its nested elements. Same fields as page_create plus:
page_delete
Soft-delete a page.
page_duplicate
Duplicate a page to a new route and title.
/ (e.g. /about-copy).Layouts
Layouts are reusable templates that can be assigned to multiple pages.
layout_list
List page layouts.
layout_get
Load a single layout with its element tree.
layout_create
Create a reusable layout with template, style, script, and fixed elements.
[] for new layouts).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.layout_update
Update an existing layout including its element tree. Same fields as layout_create plus:
layout_delete
Soft-delete a layout.
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.
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.
component_search
Search components by form label. Returns the same lightweight summary shape as component_list.
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.
component_create
Create a new component.
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.)"" for a component with no script.{{ properties.<key> }} and child elements with {{ render_elements(children) }}.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 itspropsarray.- The row-template object still needs top-level
id,name,data,defaultValue,items([]), and apropertyobject ({ type, defaultValue }). Strictly required by the deserializer arelabel,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
dataanddefaultValueto""(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'sdataas 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
defaultValueand each element'sdata[<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>(notitem.<fieldId>):
{{#each properties.items as item}}
{{item.data.question}}
{{item.data.answer}}
{{/each}}
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:
component_delete
Delete a component and all element instances linked to it.
Blog Posts
post_list
List blog posts.
post_get
Load a blog post by ID.
post_search
Search posts by title, description, or content.
post_create
Create a blog post.
"en" or "de").{}).heroImageId).post_update
Update a blog post. Same fields as post_create plus:
post_delete
Delete a blog post.
Events
event_list
List events.
event_get
Load an event by ID.
event_search
Search events by title, description, or content.
event_today
List all events happening today.
No parameters required.
event_upcoming
List upcoming events.
No parameters required.
event_create
Create an event.
{}).heroImageId).event_update
Update an event. Same fields as event_create plus:
event_delete
Delete an event.
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.
"/" for root), or load a specific file by path.["image/jpeg", "image/png"]).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.
file_search
Search files by title, description, path, status, or MIME type.
true, exclude folders from results.file_create
Create a file, folder, or remote file entry. Local files are created empty on disk.
"/images/logo.png").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.
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.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.base64Data for anything larger than a few KB; takes precedence when both are set.data:image/…;base64,… data-URI). Required only when sourceUrl is not given."image/png"). Falls back to the sourceUrl response's Content-Type, then to guessing from the path.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.
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:
file_upload_beginwith the destinationpath(+ optionalmimeType,status,title,description,metadata,tags,handleConflicts) → returns{ uploadId, maxBytes }.file_upload_chunkrepeatedly with{ uploadId, data }—datais 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 passsha256(lowercase hex of that chunk's raw bytes); a mismatch rejects just that chunk. Returns{ receivedBytes }.file_upload_commitwith{ uploadId, sha256 }(lowercase hex of the whole file, plus optionaltotalSize) → the server reassembles, verifies, stores the file, and returns the same{ size, serveUrl, … }payload asfile_upload.file_upload_abortwith{ uploadId }(optional) → discards a partial upload and its temp file when it can't be finished. An unknown or already-finisheduploadIdis 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.
file_delete
Delete one or more files or folders.
file_move
Move or copy files into another folder path.
"/images/archive").true, copy the files instead of moving them.file_rename
Rename a file or folder by changing the last segment of its 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.
"sitemap.xml").web_file_create
Create a new web file served at /<path>.
"sitemap.xml", "blog/llms.txt"). Slashes are allowed to nest files. Must be unique.web_file_update
Update the content of an existing web file by path.
web_file_delete
Delete a web file by path.
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.
settings_update
Update CMS settings. All fields are optional - only provided fields are changed.
robots.txt content.value (e.g. "en") and label (e.g. "English").