Asset tools#
API reference for the ZenCreator MCP tools that upload media and fetch URLs for generated or uploaded assets. Every asset is identified by an asset_id (a UUID). You feed asset_ids into generation tools, and you read them back out of completed tasks.
Where asset ids come from. Generation output ids are discovered with
zencreator_get_call_resultafter a task finishes — see generation tools. To turn user-supplied media into anasset_id, usezencreator_upload_assetbelow. For end-to-end recipes, see workflows.
Download vs. preview — read this first#
Two different URLs come back from this tool group, and they are not interchangeable:
download_url |
preview_url |
|
|---|---|---|
| What it is | The full-resolution original binary | A downscaled, re-encoded web preview (thumbnail) |
| Format | The original's media_type (e.g. image/png, video/mp4) |
The preview's own preview_media_type (commonly image/webp) — usually differs from the original |
| Use it for | Downloading / saving the real file | Viewing / rendering in chat |
| Tool | zencreator_get_asset_download_url / _urls |
zencreator_get_asset_preview_url / _urls |
Never present a preview_url as "the original" or "full resolution". When the user wants to save the file, call the download tool and label it with media_type. When you just want to show the image, call the preview tool and label it with preview_media_type.
All URLs returned here are signed and expire within a few minutes. Do not cache them long-term; re-call the tool to get a fresh one.
Every tool also accepts response_format ("markdown" default, or "json") and always returns a full structuredContent object regardless of format. See concepts for the shared response contract.
zencreator_upload_asset#
Create a new ZenCreator asset from a URL or base64 bytes, returning an asset_id you can pass to generation tools that operate on user-supplied media (image-to-video, lipsync, face-swap, image editing, upscaler, photoshoot with reference, and so on). Without an upload, those generators cannot run on the user's own images.
Provide exactly one of source_url or data_base64.
- The user pasted a public
http(s)://URL → usesource_url. Preferred: the server fetches the full-resolution bytes itself, with no tool-argument size limit. - The user gave a local file path (Claude Code, CLI clients) → read the real bytes yourself and use
data_base64. - The user pasted a small RFC 2397
data:URL → usesource_url. The base64 rides in the request body, so this works only for small images. - The user attached media to the chat (Claude.ai web / mobile app, ChatGPT, Cursor, Claude Desktop) → this usually cannot be uploaded via
data_base64. The attachment is a vision block, not copyable bytes;data_base64only fits tiny images, and the request body is capped (~25 MB over the HTTP transport). Never resize, downscale, crop, or re-encode the user's image to squeeze it into a tool argument — that silently destroys their photo. Instead ask the user for a publichttp(s)://URL, or to upload the file in the ZenCreator web app and supply theasset_id. Chat-attachment URLs are session-bound and unreachable from the server — do not try to refetch them.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
source_url |
string | one of source_url/data_base64 |
— | http(s):// URL or RFC 2397 data: URL. The server fetches the bytes and forwards them as a multipart upload (max 50 MB, 30 s fetch timeout). file://, blob:, javascript: and other schemes are rejected. |
data_base64 |
string | one of source_url/data_base64 |
— | Raw file bytes as a base64 string. Use for local file paths (Claude Code / CLI). Inline base64 rides in the request body (capped at ~25 MB over the HTTP transport — roughly an ≤18 MB image after base64 inflation), so it is not viable for large files or for chat attachments. Prefer source_url whenever a URL exists. |
filename |
string | No | — | Up to 255 chars. Used to detect the media type via extension and as the multipart filename. Auto-derived from a source_url path when absent. |
media_type |
enum | No | — | Explicit override; required only when auto-detection fails. One of the allowed media types below. |
response_format |
string | No | "markdown" |
"markdown" or "json". |
Media-type detection precedence (first match wins): explicit media_type arg → HTTP Content-Type from source_url → media type from the data: URL header → filename / URL pathname extension. If none yields an allowed value, the tool errors and asks you to pass media_type explicitly.
Returns — structuredContent:
{
"asset_id": "string", // pass to generation tools as image_asset_id / video_asset_id / etc.
"media_type": "string", // one of the allowed list
"size_bytes": 0 // local byte count before upload
}
Limits
- 50 MB per upload (applied locally to all media types). This full cap is reachable via
source_url(fetched server-side); for inlinedata_base64over the HTTP transport the effective ceiling is the ~25 MB request-body cap (roughly an ≤18 MB image after base64 inflation). - For
image/*the backend additionally validates that the bytes are a real, decodable image and may reject with a 400 even if the mime passes.
Not idempotent — every call creates a new asset row. Calling twice with the same bytes produces two distinct asset_ids.
Errors
pass exactly one of 'source_url' or 'data_base64'— provide one input mode, not zero or both.unsupported scheme/ scheme blocked — usehttp(s)://ordata:only.malformed data: URL— thedata:URL could not be parsed.data_base64 is not valid base64/decoded to zero bytes— fix the encoding.- payload
> 50 MB cap— resize or compress before uploading. could not determine an allowed media_type— pass an explicitmedia_type.- 400 from backend — corrupt image, oversized image, or a mime that doesn't match the bytes.
- 401 — the caller must re-authorize.
Example
"Here's a photo at this URL — upload it and use it as the reference for the next generation." (The client calls
zencreator_upload_assetwithsource_url; the server fetches the full-resolution bytes.) For a raw chat attachment with no URL, ask the user for a public link or to upload it in the ZenCreator web app — never downscale it to fit a tool argument.
Allowed media types#
zencreator_upload_asset's media_type enum and the upload validator accept exactly:
image/png image/jpeg image/jpg image/webp image/heic image/heif
video/mp4 video/mov video/quicktime
audio/mpeg audio/mp3 audio/wav audio/x-wav audio/x-m4a
Anything else is rejected.
zencreator_get_asset#
Return an asset's media type so you know how to handle it before fetching the binary.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
asset_id |
string (UUID) | Yes | — | The asset UUID. |
response_format |
string | No | "markdown" |
"markdown" or "json". |
Returns — structuredContent:
{
"id": "string",
"media_type": "string" // RFC 6838 media type, e.g. 'image/png'
}
Errors
- 404 —
asset_idnot recognised or not owned by the user.
zencreator_get_asset_download_url#
Return a short-lived presigned URL for the full-resolution original binary, plus the asset's media type so you can state the file format to the user.
Always tell the user the format — never hand over a bare URL. For 2+ assets, prefer the batch variant zencreator_get_asset_download_urls.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
asset_id |
string (UUID) | Yes | — | The asset UUID. |
response_format |
string | No | "markdown" |
"markdown" or "json". |
Returns — structuredContent:
{
"asset_id": "string",
"download_url": "string", // signed; expires within minutes
"media_type": "string" // RFC 6838 type of the original, e.g. 'image/png', 'video/mp4'
}
Errors
- 404 —
asset_idnot recognised or not owned by the user. - The URL expires shortly — if it's stale, re-call to get a fresh one.
Example
"Give me the download link for that image." → returns
download_url+media_typeto surface as "Here's your image (PNG): <url>".
zencreator_get_asset_download_urls#
Batch version of zencreator_get_asset_download_url: fetch full-resolution download URLs and media types for 1..50 assets in one round-trip. Use whenever a task produced 2+ assets. Per-asset failures do not abort the batch.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
asset_ids |
array<string UUID> | Yes | — | 1 to 50 asset UUIDs. |
response_format |
string | No | "markdown" |
"markdown" or "json". |
Returns — structuredContent:
{
"count": 0,
"succeeded": 0,
"failed": 0,
"items": [
{
"asset_id": "string",
"download_url": "string", // present iff succeeded; signed and expires shortly
"media_type": "string", // RFC 6838; present iff succeeded
"error": "string" // present iff failed (e.g. backend 404)
}
]
}
Errors
- Per-asset: each failed item carries an
errorstring; the rest still succeed. - URLs are signed and expire within a few minutes — surface them promptly or re-call.
zencreator_get_asset_preview_url#
Return a short-lived URL to a reduced-size, re-encoded web preview (a downscaled thumbnail — commonly WebP, not the original), the original asset's media type, and — by default — the preview bytes inline as an MCP image content block so sandboxed clients (e.g. Claude.ai web) can render the image without reaching storage directly.
preview_url is for viewing, not downloading. Label it with preview_media_type and state the original's media_type separately. For the full-resolution original, use zencreator_get_asset_download_url. For 2+ assets, prefer zencreator_get_asset_preview_urls.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
asset_id |
string (UUID) | Yes | — | The asset UUID. |
inline |
boolean | No | true |
When true, fetch the preview bytes and attach them as an image content block. Per-image inline cap is 2 MB; over that it falls back to URL-only with an inline_skipped note. Set false for a smaller response or when the client renders URLs natively. |
response_format |
string | No | "markdown" |
"markdown" or "json". |
Returns — structuredContent:
{
"asset_id": "string",
"preview_url": "string", // reduced-size web preview — NOT the original
"preview_media_type": "string", // RFC 6838 type of preview_url itself, e.g. 'image/webp' (omitted if undeterminable)
"media_type": "string", // RFC 6838 type of the ORIGINAL asset, e.g. 'image/png'
"inline_skipped": "string" // present only when inline was requested but skipped
}
When inlining succeeds, the response also carries an extra { type: "image", mimeType, data } content block, which most clients render as an inline thumbnail.
Errors
- 404 —
asset_idnot recognised or not owned by the user. inline_skippedis informational (e.g. image > 2 MB, or a network error fetching the preview) — the URL is still returned.
Example
"Show me that result in the chat." → returns
preview_url+ inlined thumbnail; tell the user "Preview (WebP), shown inline; original is PNG — say the word for the full-res link."
zencreator_get_asset_preview_urls#
Batch version of zencreator_get_asset_preview_url: fetch reduced-size web preview URLs plus each original's media type for 1..50 assets in one round-trip, and — by default — inline the preview bytes as image content blocks. Use whenever a task produced 2+ assets. Per-asset failures do not abort the batch.
These URLs are for viewing, not downloading. For full-resolution originals use zencreator_get_asset_download_urls.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
asset_ids |
array<string UUID> | Yes | — | 1 to 50 asset UUIDs. |
inline |
boolean | No | true |
Attach preview bytes as image content blocks. Per-image cap 2 MB; per-call total cap 8 MB. Assets exceeding either cap fall back to URL-only with an inline_skipped note. Set false to keep the response small. |
response_format |
string | No | "markdown" |
"markdown" or "json". |
Returns — structuredContent:
{
"count": 0, // input count
"succeeded": 0, // URL fetched
"failed": 0, // URL fetch failed (no preview_url, has error)
"inlined": 0, // bytes also attached as image content blocks
"items": [
{
"asset_id": "string",
"preview_url": "string", // web preview — NOT the original; present iff URL fetch succeeded
"preview_media_type": "string", // RFC 6838 type of preview_url itself (omitted if undeterminable)
"media_type": "string", // RFC 6838 type of the ORIGINAL asset; present iff succeeded
"inline_skipped": "string", // present iff URL ok but inlining was skipped
"error": "string" // present iff URL fetch failed
}
]
}
The response carries one { type: "image", mimeType, data } content block per successfully inlined asset, in the same order as items.
Errors
- Per-asset: failed items carry an
error; inlining failures carryinline_skipped. The rest still succeed. - The per-call 8 MB inline budget: once reached, remaining assets fall back to URL-only with
inline_skipped: "batch ... cap reached".
See also#
- Generation tools — submit generations and discover output
asset_ids withzencreator_get_call_result. - Workflows — end-to-end upload → generate → fetch recipes.
- Concepts — the shared response, pagination, and credits contracts.