Skip to main content

MCP Tool Catalog

The NativeAds MCP server lists 18 tools, and reaches 42 actions more through them. One of the tools, panel_bridge, declares _meta.ui.visibility: ["app"], so a host that honours that key offers it to the panel and not to the model: on claude.ai the assistant sees 17. It is listed here because the server serves it and a client that does not implement visibility will see it too. This page lists each one with its purpose, key inputs, and behavior hints. See the MCP Guide to set up a client, and the REST API Guide for the underlying HTTP shapes.

Tools and actions. An action is not in tools/list. Find it with find_actions, then call it through the run_*_action tool its entry names; see Finding and running actions. This page names tools and actions alike, and the Actions table says which names are actions. Calling an action directly by its name still works, which is how a connector whose tool list was cached before the action moved keeps working.

Views. Three tools each stand in for several that did one job between them: show_media reads a brand's media, show_brand_dna its Brand DNA, and edit_brand_dna changes a Brand DNA version. A view argument picks what show_media and show_brand_dna read; edit_brand_dna picks by what you send. Each runs the tool it replaced and returns that tool's result, unchanged except for its display note: show_media and show_brand_dna put a note in front telling the assistant the user is looking at it and to answer in one sentence, and keep only the part of the reader's note that applies when no panel rendered (a client whose capabilities declare no MCP Apps UI gets that part alone, without the note in front), and it enforces that tool's own schema, so an argument the chosen view does not take is refused (invalid_argument, with the view's inputSchema in details) rather than ignored. Of the eleven tools they replaced, the nine readers (list_scene_forges, list_generated_video_groups, list_assets, get_environment_generation, get_brand, get_brand_dna, get_active_brand_dna, get_brand_dna_version and list_brand_dna_versions) are read actions, for looking something up without showing it: through run_read_action nothing renders, and the result's display says so (see Actions). The two editors, update_brand_dna_version and patch_brand_dna_version, are not listed and are not actions. A client that still has any of the eleven can call it by name.

Asking the user. ask_user opens one of three panels that ask the user something and returns their answer as the call's result: brand_picker, brand_dna_options or url_extraction, chosen with its panel argument (see Asking the user). It replaced open_brand_picker, open_brand_dna_options and get_url_extraction, which are no longer listed and are not actions, but a client that still has them can call them by name.

New to the platform? Call get_started first for orientation, then follow the Recommended workflow below. It is the order that produces on-brand results.

Reading the annotations​

Each tool carries hints that clients use to decide how to present it:

  • Read-only — does not change any state.
  • Idempotent — calling it again with the same input has the same effect.
  • Destructive — overwrites or permanently removes data. One listed tool is destructive, edit_brand_dna (a merge patch can delete a key, an overwrite replaces the payload, and neither keeps a revision you can read back), plus run_destructive_action, which routes the four destructive actions: update_brand, rerun_brand_dna_version, cancel_brand_dna_version and delete_brand_dna_version. Only the last two delete a row; the others replace content with no history, which the hint covers as well.
  • Open-world — reaches something outside the platform, so its result is not fully predictable: it fetches a URL you supplied, or calls a generative model. Six listed tools are open-world, two of them the run_write_action and run_destructive_action gateways, which route the thirteen open-world actions.
  • Async — returns a task id; poll get_task (an action, through run_read_action) until terminal is true. No listed tool is async; thirteen actions are.

Unless noted, string ids are required. Optional inputs are marked.

Brand DNA is the platform's model of a brand's visual and verbal identity, and it is what makes generated creative on-brand. Create it before generating.

Guide, do not one-shot. When a human is present, do not silently create a brand and extract DNA end to end. Explain what you are about to do, ask what the user can provide (above all their logo and brand assets), and recommend the choices that raise quality. Confirm with the user before every meaningful action, creating the brand, starting Brand DNA, uploading assets, and generating; propose and wait for a yes rather than acting silently.

  1. Orient — call get_started first for any ad or social post request (image or video), before asking the user anything, for the plan, whether Brand DNA is available, whether a brand exists, and a suggested next action. Read its choices block before generating: it lists every option the generation tools accept, the default that applies when you send nothing, what each call costs, and an ask level per decision (ask, propose, default) saying how hard to put that decision to the user. The options live there rather than in the tool schemas because the schemas ship on every session and this is fetched once. The seedance-2.5-pro lengths and reference caps in it are narrowed to your plan, and choices.planLimits states the same ceilings (referenceImageCap, referenceVideoCap, maxDurationSec). On a plan without seedance-2.5-pro, choices.planLimits.available is false, modelPlan names the first plan that has it, and the menu leaves the model out and defaults to seedance-2.0-pro.
  2. Create the brand — ask the user for the brand name and their logo, propose an industry and a short description, and confirm these before calling create_brand (only name is required; or find an existing brand with list_brands). Both are actions: call them through run_write_action and run_read_action. Do not upload the logo or other files yet: asset upload needs the brand to exist, so it happens in step 2.
  3. Add Brand DNA and activate it — Brand DNA is the platform's model of the brand's visual and verbal identity and the single biggest driver of output quality, the core of what makes NativeAds on-brand. Explain this to the user, then guide them to get the most out of it: recommend the full set together, their logo and brand assets (images and videos), any brand-guideline PDFs, and their website URL(s). Do not assume a URL alone is enough or quietly fall back to URL-only. Check with get_brand_dna (an action, through run_read_action, so nothing is shown to the user); hasActiveBrandDna: false means the brand has none yet. show_brand_dna with view: "active" is for showing it. Confirm what the user will provide, add each asset and PDF by URL (import_asset_from_url, with isLogo: true for the logo; the server fetches it, there is no client-side upload), then call create_brand_dna_version (an action, through run_write_action) with those assetIds and the website urls together. On an interactive (OAuth) client, offer it with ask_user and panel: "brand_dna_options" instead: the panel submits the build, and the server refuses a build no panel offered, or one the user answered with Skip. API keys are exempt. Proceed with a smaller set, or skip Brand DNA, only when the user explicitly declines; tell them the output will be off-brand, then it is their call. Poll show_brand_dna with view: "version" and the versionId until its status is ready (get_task reports the workflow as completed, not ready). Then review it with the user: state the confidence score and any missing fields, and if the DNA is weak or missing the logo or brand colors, recommend adding it and offer to re-run with rerun_brand_dna_version. Correct wrong content with edit_brand_dna (a patch of only the fields to change, or the full dna with its updatedAt), then activate_brand_dna_version. Generation without active Brand DNA still runs, but output will be off-brand.
  4. Enhance the prompt (recommended) — enhance_scene_forge_prompt / enhance_img2video_prompt (actions, through run_write_action), poll get_task (through run_read_action) until terminal, then read the result with get_scene_forge_prompt_enhancement / get_img2video_prompt_enhancement and review the enhanced prompt before generating.
  5. Generate — on a client that shows panels, open open_generation_options (pre-filled with what was agreed: the user's words as prompt or, if they gave none, your draft as suggestedPrompt) and the user submits; the server refuses scene_forge / image_to_video from such a client. Elsewhere call scene_forge (images) or image_to_video (video), both actions, through run_write_action, with the user's words or a prompt you proposed in chat and they approved; the prompt renders exactly as sent: promptIsEnhanced defaults to true on this surface, whether the words came from an enhancer (for video, as userPrompts: [enhancedPrompt]) or from the user. Pass promptIsEnhanced: false only to let the render pipeline rewrite them; on video that rewrite is also what carries Brand DNA into a prompt the enhancer never saw. Feature the real product via productAssetIds (+ environmentAssetId); a Scene Forge image makes a strong startImageAssetId for every video model except seedance-2.5-pro. For seedance-2.5-pro (reference-to-video), upload reference images and/or videos, pass them as referenceImageAssetIds / referenceVideoAssetIds, and omit start/end/intermediate frames — those fields are rejected. seedance-2.0-pro (up to 9) and kling-v3-omni-pro (up to 7) take either startImageAssetId or referenceImageAssetIds, never both, and no reference videos. Brand DNA is applied by default for scene_forge, but must be requested with useBrandDna: true for image_to_video and enhance_img2video_prompt. Newly uploaded assets must reach status complete (poll show_media with view: "assets") before you reference them.
  6. Retrieve output — poll get_task (through run_read_action) until terminal; the submit result's resultTool names the reader, resultView the view it takes when that reader is show_media or show_brand_dna, resultPanel the panel when it is ask_user, and its readBack spells out the whole call, view or panel first, with this task's id filled in (resultIdField is the name of that argument; its value is this ack's task_id). A run the generation panel submitted is the exception: the panel shows the finished render itself, so do not read it back to display it. A completed scene_forge returns several variations sorted best-first: present them all, relay each variation's warnings verbatim as non-fatal advisories, and skip any variation carrying an errorCode. Hand the user each variation's asset.assetUrl as a markdown link; those urls are signed and expire a few hours after they are minted, so call the reader again for fresh ones rather than reusing older link text. download_asset is for inspecting an asset yourself or fetching a file to save, not for showing one: on Claude web and Desktop a tool-result image never reaches the reply, and for a video asset download_asset returns no image block at all. Nothing on this surface puts a headline, CTA or other text onto a creative, so do not offer it.
  7. Upscale for large placements (optional) — when a placement such as print or a digital billboard needs more pixels than a finished image has, upscale it. Upscale needs the Pro or Ultra plan; on Starter it is refused with upgrade_required. On a client that shows panels, open open_upscale_options with the image's imageId (an asset id, such as one from get_task's assetIds, or a Scene Forge image id), and pass targets only for sizes the user named. The user picks the sizes, sees the cost and submits, so do not run upscale_image after it; read the result once with show_media and view: "upscale". Elsewhere, state the cost and get a yes, then call upscale_image (an action, through run_write_action) with imageId and 1 to 4 targets, poll get_task until terminal, and read the group with show_media and view: "upscale".

Clients that render MCP Apps show the output directly. Ten listed tools declare a panel. Two follow one rule: if a result hands you a loadable media url, it renders (show_media, import_asset_from_url). Three show Brand DNA as a palette and typography (show_brand_dna, edit_brand_dna, activate_brand_dna_version), the uploader takes a file, and the other four, open_generation_options, open_resize_options, open_upscale_options and ask_user, ask the user rather than displaying a result: the user picks the model, length, audio and framing in the first, the sizes or the framing of a resize in the second, the larger sizes of an upscale in the third, and in the fourth which brand to work on, which assets and site URLs Brand DNA should read, or which extraction candidates to save and which is the logo. Each reports that choice itself, so those values never pass through the assistant. list_brands has no panel: it answers the count, and its result says to open the brand picker only when two or more brands could be meant. Generated variations, resize results, upscale results, brand assets, logos and generated backdrops all render as ui://nativeads/generation-gallery; the resize panel renders as ui://nativeads/resize-options and the upscale panel as ui://nativeads/upscale-options; extraction candidates keep their own ui://nativeads/extraction-gallery; Brand DNA renders as ui://nativeads/brand-identity, a palette and typography view rather than a grid. ask_user renders as ui://nativeads/ask, which mounts the brand picker, the Brand DNA options or the extraction gallery, whichever its panel names. The eleven tools the views replaced, and the three ask_user replaced, keep their panels for a client that still calls them by name; a read action run through run_read_action renders nothing. On Claude web, Claude Desktop and ChatGPT these appear inline, with video playing in place. The host tells you when it happened by appending a note that an interactive widget was rendered — read it rather than assuming either way. Claude Code and plain API-key callers get no panel at all, which is why the links still matter.

A newly declared panel reaches a claude.ai connector only once that connector's cached tool list refreshes, so on an existing connection some of these render and some do not. Nothing about the result itself changes either way.

get_task reports status, never the result payload; the additions are assetIds on a succeeded scene_forge or image_to_video task, the ids of what it rendered in the order its reader lists them, and imageLabels on a succeeded scene_forge, each image's panel name (Image N, numbered by creation, so not in assetIds order) mapped to its asset id. Read the actual output with the call the submit result's readBack spells out.

Iterating. For a cohesive set, hold productAssetIds, environmentAssetId, and theme constant and vary only the prompt, reusing one confirmed enhanced prompt across siblings. For more of the same look, prefer extend_scene_forge / extend_generated_videos_group over a fresh call. There is no seed or negative-prompt field; write "avoid X" into the prompt.

Choosing options. aspectRatio maps to placement: 9:16 stories/reels, 1:1 square feed, 3:4 portrait, 16:9 display/YouTube, 21:9 wide banner (2:3/3:2/4:3 also available). Choose deliberately; a mismatch can raise a hard-spec warning. image_to_video dimension takes pixels, but only their SHAPE reaches the renderer: taller than wide renders 9:16, an exact square renders 1:1 (16:9 on veo-3.1, which has no square), anything else renders 16:9. The presets are 1280x720, 720x1280 and 1080x1080 (the panel does not offer the square on veo-3.1); a bespoke size is accepted, echoed back unchanged in the response, and still rendered as one of those three ratios. A start or end frame of another shape is extended to fit with AI outpainting rather than cropped; a centre crop is only the fallback if that extension fails or takes too long. Video has only those three of the image ratios. For seedance-2.5-pro, prompts bind references as @Image N / @Video N in the order of referenceImageAssetIds / referenceVideoAssetIds; dimension still applies.

Handling failures. A failed task carries an error class: UserRequestError (including content-policy) means fix inputs and do not resubmit unchanged (its message is safe to show); ModelProviderError is transient, retry later; NativeAdsSystemError, surface generically. get_task's retryable reflects this. On a tool error, data.type guides you: upgrade_required (plan lacks the feature, e.g. Brand DNA, or a limit is reached), payment_required (billing inactive or past due), conflict (re-read and retry), invalid_argument, not_found.

Connection errors happen before a tool runs (HTTP, not tool errors): 401 = missing/expired/revoked key or OAuth token; 403 = the credential is not a machine principal (mint a per-user API key); 429 = org rate limit, back off and slow polling.

Do not let a default stand silently. Several inputs apply a server default that changes the artifact or the bill, and get_started's choices names each one. The four that catch people out: model also sets the duration (the MCP default, seedance-2.5-pro, or seedance-2.0-pro on a plan without it, renders 8 seconds, where kling-v3-omni-pro renders 15), and it also decides which assets the call takes: seedance-2.5-pro is reference-to-video, so it needs referenceImageAssetIds and rejects startImageAssetId, seedance-2.0-pro and kling-v3-omni-pro take a first frame or reference images, and every other model requires a first frame; enableAudio defaults to false, so a video is silent unless you ask for sound; scene_forge and extend_scene_forge each render and bill four images per call, with no way to ask for fewer; and partner defaults to default, which spec-checks nothing. Pass the same model, duration and enableAudio to enhance_img2video_prompt and image_to_video — the enhancer writes the prompt for the values it was given, so a mismatch means the approved prompt paces a different film than the one that renders.

isLogo deserves its own warning: it sets the asset's type at upload time and nothing can change it afterwards. An image uploaded without it can never be attached as a brand logo (update_brand rejects it as "not a logo"), and the only remedy is uploading the same file again. Ask before uploading, every time.

Language. This MCP surface currently returns English-canonical Brand DNA and enhanced prompts; there is no per-request output language yet. For video, the prompt is also translated to English immediately before rendering, so a prompt approved in another language is not the prompt that renders.

Asking the user​

ask_user shows a panel where the user answers, and holds the call until they do (see when a call is held, under Turn a page URL into assets); the answer comes back as this call's result, with askPanel naming the panel. Send the panel's own fields beside panel, flat. They are checked against that panel's own schema, so a field it does not take is refused (invalid_argument, with the schema in details) rather than ignored, and an unknown panel is refused with every panel, when to use it and its inputSchema in details.panels. Only brand_dna_options needs a plan that includes Brand DNA. The call itself writes nothing, which is why it is read-only: a Build or a Save is the user's click, and the panel performs it.

ToolPurposeKey inputsHints
ask_userShow a panel that asks the user and returns their answer. Pick it with panel (table below).panel; the rest depends on the panel (table below)read-only, open-world, panel
panelAsksInputsReplaced
brand_pickerWhich brand to work on. Only when two or more brands could be meant: with zero or one it returns at once and shows nothing.optional name, industryopen_brand_picker
brand_dna_optionsWhich assets and which site URLs Brand DNA should read, then Build or Skip. Open it to offer Brand DNA rather than starting one: the panel submits create_brand_dna_version itself, so do not call that after it. The version a Build creates is activated automatically when it becomes ready. Brand DNA is recommended and optional: Skip is a complete answer, it blocks nothing, and generation still works without it. The URL field is editable because the page a user pastes and the page worth crawling are not always the same, and the panel states that the crawl reads that page plus up to 29 pages linked from it.brandId; optional assetIds (pre-ticked), urls (pre-filled)open_brand_dna_options
url_extractionWhich candidates of a finished extract_assets_from_url run to save, and which is the logo. Returns the run's status and ranked candidates, best first; see Turn a page URL into assets.extractionId; optional includeRejectedget_url_extraction

Late panel answers​

A panel the user answers after its call has returned (the hold lapsed, the turn ended, or an unheld call showed the panel) is recorded, and so is each further answer in a panel that already answered (another save, another upload, a second pick). The next tool call the assistant makes carries it once, as latePanelAnswers beside that call's own result: a list of {panel, scopeId, answeredAt, result}, where result is what the panel's own call would have returned (a generation's or a resize's task_id, a Brand DNA build, an uploaded asset, a brand pick, saved candidates), with latePanelAnswersNote saying what they are. A resize the user starts from a Resize button, in the gallery or under a generation panel's results, arrives the same way, with panel: "media_gallery" and a result of startedInGallery (the tool it ran), ack (that tool's submit result, with its task_id) and note. The gallery shows that job's progress and result itself. At most 3 per result, newest first, from the last 30 minutes, the calling user's own, and only once an answer is 5 seconds old. A reply written without a tool call does not get them. They are per user, not per conversation, so one can come from the user's other chat. The server cannot tell a panel's own tool calls from the assistant's, so calls with the shapes panels make never carry them: panel_bridge; get_task, get_asset, initiate_asset_upload, the two enhancers and their result reads; show_media with view: "assets"; and the read-back of a render or Brand DNA build a panel submitted. Nor do show_media and show_brand_dna results at all, since they tell the assistant to stop after one sentence; the next call of another kind carries them. A panel opener (ask_user, open_generation_options, open_asset_uploader) that finds a late answer waiting does not hold first: it returns at once with that panel's keep-waiting result (waitAgain: true) and latePanelAnswers, so the assistant hears the earlier answer before the user acts in the new panel, then calls wait_for_panel to wait on it as usual. On a host whose panels also send the answer as the user's message (ChatGPT, VS Code), the assistant can hear it twice. An API-key caller, or a call whose capability block declares no MCP Apps UI, renders no panel and never gets them. On claude.ai, a click after the user pressed Stop but before the hold ended is handed to the stopped turn and not repeated; the saved state still shows it (alreadySaved on an extraction, currentBrand from get_started, and wait_for_panel returns the recorded answer).

Brands​

Brands are created, listed and changed through actions, create_brand, list_brands and update_brand (see Actions). To have the user pick one, use ask_user with panel: "brand_picker". A brand's own fields and logo are show_media with view: "brand", below.

Showing media​

show_media reads everything a brand has that can be looked at, and renders it in the generation gallery panel. Each view runs the tool it replaced, which a client that still has it can call by name.

ToolPurposeKey inputsHints
show_mediaShow a brand's generated images or videos, its uploaded assets, a generated background, the brand and its logo, a resize group's results, or an upscale group's results. Pick one with view.view; the rest depends on the view (table below)read-only
viewShowsInputsRuns
imagesScene Forge generations for a brand. Pass sceneForgeId (the resultIdField a finished scene_forge names) to read back that one render, and add imageId to narrow it to one image; imageId without sceneForgeId is refused, and with sceneForgeId the list filters (status, partner, page, limit, sortBy, sortOrder) are ignored. On a client that shows panels, each finished Scene Forge image in the gallery has a Resize button: the user can resize it there, to several sizes or to one size they frame, and the gallery follows the job and shows its result itself. On the Pro and Ultra plans an Upscale button sits beside it, and the user picks the larger sizes there; an image no size can be made from shows the button dashed, with the reason on tap. Both buttons work, and the gallery shows their jobs, for 24 hours after this call (see Late panel answers). Unlike REST, variations carry no critique / critiqueStatus here, and originalPrompt / authoredPrompt are omitted when they repeat blendingPrompt / the submitted prompt; authoredPrompt is also absent on renders created before it was recorded.brandId; optional sceneForgeId, imageId, status, partner, page, limit, sortBy, sortOrderlist_scene_forges
videosImage-to-video generation groups for a brand. Pass generatedVideosGroupId (the resultIdField a finished image_to_video names) to read back that one group. Each video's renderedPrompt is the text the model actually received; prompt is what was submitted.brandId; optional generatedVideosGroupId, partner, page, limit, sortBy, sortOrderlist_generated_video_groups
assetsThe brand's assets, with optional filters. type includes logo: a brand logo is stored as logo, not image. status takes processing, complete or failed only.optional brandId, type, status, tags[], campaignId, page, limitlist_assets
backgroundA generate_environment run. Once completed it carries the generated asset, whose id goes to scene_forge as environmentAssetId. Takes no brandId.environmentGenerationIdget_environment_generation
brandOne brand, with its logo.brandIdget_brand
resizeA generative_resize group: the source image (source, named like the panel, Image 2 for a Scene Forge image) and each size (framed when the user placed it) with its versions, each with its rating, dislike reason, picked, a preview url and the original file's fileUrl and fileName, plus the cost of one more version. Sizes come in the order they were requested and each size's versions in the order they were made. A failed group, size or version carries error, one plain sentence. A client that shows panels draws it as the resize results card, where a tap on a version picks it, several per size, and the Download button sends exactly the picks. After a resize the panel submitted, call it once: the card shows the versions as they finish. Takes no brandId.groupId (the task_id generative_resize returns)get_generative_resize_group
upscaleAn upscale group, as get_upscale_group returns it: the source image and each size in the order picked, with its label (×2, 4,096 px), output pixels, credits and status; once completed its url, previewUrl and fileName; once failed its error and creditReturned, plus the image allowance. On an unlimited plan the outputs carry no credits or creditReturned. A client that shows panels draws it as the upscale results card, which follows the sizes as they finish and downloads each one. After an upscale the panel submitted, call it once and do not poll get_task. Takes no brandId.groupId (the task_id upscale_image returns)get_upscale_group

Brand DNA​

Brand DNA is extracted asynchronously from uploaded assets and/or URLs. Exactly one version is active at a time; creating a version does not activate it, call activate_brand_dna_version once it is ready. Creating one is the create_brand_dna_version action (see Actions), or the Build button in the Brand DNA panel (ask_user with panel: "brand_dna_options"), which is how an interactive client starts one. A build started from that panel is the exception: it is activated automatically when it becomes ready, replacing any active version, which stays in the version history.

Every tool in this section requires a plan that includes Brand DNA, the read-only ones as well as the writes. Below that plan they all return upgrade_required, and get_started reports brandDnaAvailable: false. Check that field before offering the feature rather than discovering it on the first call.

ToolPurposeKey inputsHints
activate_brand_dna_versionMake a version the active one (must be ready).brandId, versionIdidempotent
show_brand_dnaShow a brand's Brand DNA as a palette and typography. Pick one with view (table below).view, brandId; optional versionId (version only)read-only
edit_brand_dnaChange a version, one of two ways and not both: a patch, a partial JSON Merge Patch of only the fields to change (nested objects merge, null deletes a key); or an overwrite, name and/or the full dna with the version's updatedAt as an optimistic lock. Sending patch with any of name, dna or updatedAt is refused.brandId, versionId; patch, or updatedAt with name and/or dnadestructive
viewShowsRuns
activeThe brand's live Brand DNA payload, or hasActiveBrandDna: false when it has none.get_brand_dna
versionOne version's detail, including the updatedAt an overwrite needs. With no versionId, the active version's.get_brand_dna_version, or get_active_brand_dna with no id
versionsEvery version for the brand, with its status.list_brand_dna_versions

An edit_brand_dna with a patch runs patch_brand_dna_version; one without runs update_brand_dna_version.

The urls input on create_brand_dna_version and rerun_brand_dna_version accepts only public http/https addresses.

Assets​

The MCP transport never carries file bytes, so there are four ways to add a file — pick the one your client can do. None of them require anything client-specific from you.

  1. The user has a public link → import_asset_from_url. The server fetches it.
  2. Your client can make HTTP requests → initiate_asset_upload (an action, through run_write_action), PUT the bytes to the returned uploadUrl, then confirm_asset_upload (an action too, through run_write_action). This is the standard presigned-upload pattern, and the cheapest for large files: bytes go straight to storage and never pass through the model's context.
  3. Your client renders MCP Apps UI → open_asset_uploader. An upload panel appears in the conversation and the user drops the file into it; the panel reserves, uploads and reports the asset itself, so do not call initiate_asset_upload or confirm_asset_upload after it. Use this when a PUT is not possible — notably Claude web and Claude Desktop, where the code sandbox's egress allowlist blocks the upload host outright.
  4. Neither is possible → initiate_asset_upload also returns uploadPageUrl. Show it to the user; they upload in a browser and it confirms itself. No confirm_asset_upload needed.

A file the user attached to the conversation is a special case. On ChatGPT it is handed to import_asset_from_file directly. No Anthropic client exposes an attachment's bytes or a fetchable URL to a server, and none can today: the mechanism that would allow it (the MCP File Uploads working group's file inputs) is not yet in the specification. On those clients, use open_asset_uploader and let the user drop the file into the panel.

ToolPurposeKey inputsHints
import_asset_from_urlFetch a file from a URL and commit it as an asset.brandId, url; optional fileName, isLogo, categoryIdwrite, open-world
import_asset_from_fileCommit a file the user attached in the conversation.brandId, file (download_url, file_id; optional file_name, mime_type); optional isLogo, categoryIdwrite, open-world
open_asset_uploaderShow an upload panel in the conversation; it uploads and reports the asset itself.brandId; optional isLogo, categoryIdwrite

To see what landed, call show_media with view: "assets".

import_asset_from_url derives the file type and image dimensions from the fetched bytes, so you do not declare them. Supported types: JPEG, PNG, GIF, TIFF, MP4, QuickTime, PDF, DOC, DOCX, and the TTF/OTF/WOFF/WOFF2 fonts. Maximum 500 MB.

The URL must be a public http(s) address. Requests to loopback, private, link-local, and other reserved ranges are refused, at submit time and again on every redirect. The same guards apply to the download_url inside import_asset_from_file.

Turn a page URL into assets​

When the user has a page rather than a file (a product page, a property listing, a service page), this finds the images on it, ranks them by how central they are to the page's subject, and stages them for review. Nothing becomes an asset until the user picks.

ToolPurposeKey inputsHints
ask_user with panel: "url_extraction"Read status and ranked candidates, best first; the user picks what to save.extractionId; optional includeRejectedread-only

API keys are never held. (A client authenticating interactively over OAuth is, because that is the client which can render a panel.) Three tools, ask_user, open_generation_options and open_asset_uploader, hold their call open for an interactive client whose host renders panels, returning what the user chose instead of a payload the assistant has to act on alone. An API-key caller renders no panel, so it is exempt: those calls return immediately, with the same payload they always returned, and a display that leads by saying no panel rendered and to ask the user in chat (left out when that call's capability block declares the MCP Apps UI extension, where a panel may still render). The same goes for an OAuth client whose tools/call capability block does not declare the MCP Apps UI extension (Claude Code on the connector, for example): it gets the immediate payload rather than a held call, with the same no-panel display. A request that carries no capability block at all (the legacy protocol era) is still held.

For an interactive client, ask_user with panel: "url_extraction" holds only when the run has finished, has candidates to pick, and nothing has been saved from it yet — the one state where the answer is the user's. A run still in flight returns at once, so polling works as documented. Once anything is saved, the read returns at once with alreadySaved (saved, keptNotSaved) and a display saying the saved candidates are in the brand's assets, not staged. Each further save the user makes in that gallery comes back as a late panel answer. A new call while an earlier gallery for the same run is still held (a turn the user stopped, for example) gets a hold of its own.

The flow is submit, poll, show, commit. extract_assets_from_url returns a task id: poll it with get_task (through run_read_action), then call ask_user with panel: "url_extraction" and the extractionId. Both the submit and commit_url_extraction_candidates are actions, through run_write_action. On a client that shows panels the commit is the user's: the extraction gallery saves what they pick itself, and the server refuses the commit from the assistant there. A client with no panel (Claude Code, an API key) commits through run_write_action. The scrape covers the page you name plus up to 15 related pages on the same site — its tabs, sub-pages and galleries, sibling products, and the other sections of the same catalogue — so a run takes one to five minutes. A run scores at most 40 unique images across those pages, fetching more than that if the site serves the same photo at several sizes. truncated reports how many heuristic survivors it never got to — the page had more candidate images than one run scores. Near-identical shots the ranker held back are NOT counted there; they come back with kept: false under includeRejected=true and are still committable. Once one of them is saved, every read lists it, with kept: false and its committedAssetId, so a read never hides what the user already saved.

Candidates come back as inline images so you can see and describe them, plus a signed url each. Two shared budgets bound how many render as images; when they bind, the result carries a line reading Showing N of M candidates as images and the rest are text-only. Read that line rather than assuming you saw everything. Present them all and let the user choose rather than picking on their behalf. Note that some clients show tool-result images only inside the collapsed tool-use view, so describe what you see rather than assuming the user is looking at the same thing.

Each candidate's url expires 4 to 8 hours after it was minted. Call ask_user with panel: "url_extraction" again to mint a fresh one rather than storing the value.

Omit items on the commit to save every kept candidate. Commit-all never includes rejected candidates — a rejected one can only be saved by naming its candidateId explicitly. There is no commit-nothing shape, so never call the tool when the user has selected nothing. Pass items to save a subset and to mark one as the brand logo; isLogo also stores the asset as a logo and skips the image-processing pass, so it is complete as soon as the commit returns rather than needing a poll. Flag it on the first commit — setting it later on an already-saved candidate does nothing.

Committing is idempotent per candidate, so a retry returns the assets it already created instead of duplicating them. It is not atomic across candidates: the first failure returns immediately and leaves the earlier ones saved, which is exactly why retrying is the right recovery. It also does not copy what the brand already has: a candidate whose image this brand had already saved, from any extraction, as the same kind of asset returns that existing asset, and alreadyInLibraryCount says how many of the returned assets were already there. The same image means the same bytes, wherever they came from, including a logo captured from an inline SVG; an image saved before this matching existed is matched by its image URL instead. isLogo never reuses a plain image (or the reverse), and a deleted asset is never reused.

purpose tunes ranking and how many candidates come back. scene_forge favours clean, isolated, croppable product shots and returns at most 10; video allows scenic and establishing shots; any has no lean, and is what an omitted or blank value means. Matching ignores case, hyphens and spaces, so Scene Forge reaches the scene_forge profile.

Anything else is free text and is used, not discarded: it keeps any's thresholds and limit while the text itself goes to the ranker as a statement of intent, so it re-tunes the ordering. "Facebook ad creative for first-time buyers" is a valid purpose and ranks differently from sending none. Capped at 300 characters. Nothing is ever rejected here.

media defaults to both; video extraction is not available yet, so an explicit videos is refused rather than silently returning images. Until it ships images and both are identical — only <img> elements are read, and every candidate comes back with mediaType: image.

Uncommitted candidates are not charged, not quality-assessed, and not visible in the asset library. Their staged copies expire 30 days after the run.

Withdrawing a scrape is REST-only

To remove an extraction and its uncommitted staged copies immediately, call DELETE /v1/assets/extract-from-url/{extractionId}. There is no MCP tool for it — assets already committed are unaffected, so nothing an agent produced is at risk from its absence.

Use import_asset_from_url instead when the user already has a direct link to the file itself.

import_asset_from_file takes the file object your client supplies for a user-attached file and fetches its download_url server-side. If the client hands over only a file id with no download_url, the file cannot be retrieved and the tool says so — ask the user for a link and use import_asset_from_url instead.

Uploading bytes directly

The same flow is on REST for API-key callers: POST /v1/assets/initiate-upload → PUT → POST /v1/assets/confirm-upload, plus POST /v1/assets/cancel-upload/{uploadId} to abandon a reservation. cancel_asset_upload is REST-only.

uploadPageUrl is short-lived and single-use, and is omitted entirely in environments where URL signing is not configured.

Generation​

scene_forge and image_to_video start a render. They are actions, through run_write_action (see Actions); on a client that shows panels the server refuses them and the user renders from open_generation_options instead. generative_resize is refused there the same way, and the user resizes from open_resize_options or from the Resize button under an image in the gallery or in a generation panel's results.

ToolPurposeKey inputsHints
open_generation_optionsShow a panel where the user writes the prompt and picks the model, length, audio and framing, with the cost stated, and submits the run themselves. Prefer it over calling a generation tool with values the assistant chose, and open it as soon as the user wants to generate: you do not need asset ids first. The panel submits, so do not call scene_forge / image_to_video after it: poll get_task through run_read_action, and do not read the result back to show it, because the panel paints the finished render itself. It lists the brand's 50 most recent complete images itself, so the user picks the first frame, end frame, intermediate frames, reference images (Seedance 2.5, and Seedance 2.0 or Kling 3.0 Omni Pro, where a First frame / Reference images switch decides which one is sent) and (for images) product images there; ids you pass are preselected. Reference videos are not in the picker, so pass referenceVideoAssetIds if the user wants them. If the panel cannot list the brand's images it says so and asks for them in the chat. The review screen shows the prompt in an editable box, so the user can correct the wording before spending. Pass the user's own words verbatim as prompt. If they gave none, pass your draft as suggestedPrompt: the panel prefills it labelled as the assistant's suggestion, it is ignored when prompt is set, it is never treated as already enhanced (promptIsEnhanced is ignored for it), and nothing renders until the user presses Generate. The result's settings then carries promptOrigin (user, suggested for an unchanged suggestion, suggested_edited), promptEnhanced (whether the panel's own enhance step ran; not the same as promptIsEnhanced, which is true for every panel submit, and promptEnhancedMeans says so in the result) and promptOriginVerified (false when the server had no record of what the panel was opened with, so the origin is the panel's own report). Enhancement is EXPLICIT here: the panel offers it as its own step, after the model is chosen, and whatever the user decides it submits the words they read verbatim — it never lets the render pipeline rewrite them behind the approval. If prompt is an enhancer's output (sent with promptIsEnhanced: true), also pass the words you gave the enhancer as authoredPrompt: the panel submits them so they are stored as what the user wrote, even if the user edits the text first (emptying the box drops them, so what the user then types is stored as their own); it is ignored for a suggestedPrompt and without promptIsEnhanced. Pass any value the conversation already settled (aspectRatio for an image, dimension and duration for a video) and the panel preselects it rather than asking again. A video submitted without the panel's enhance step (and not opened with an already enhanced prompt and promptIsEnhanced: true) reports useBrandDna: false in settings.used, with a warning, because Brand DNA reaches a video only through the enhancer. It offers only the models, lengths and reference counts the caller's plan allows (no seedance-2.5-pro on a plan without it, where it starts on that plan's default model), and drops forwarded reference videos the plan does not include, saying so.brandId, kind (video | image); optional prompt, suggestedPrompt, startImageAssetId, referenceImageAssetIds (max 30), referenceVideoAssetIds (max 10), productAssetIds (max 5, image only), promptIsEnhanced, authoredPrompt, aspectRatio (image only: 1:1 | 2:3 | 3:2 | 3:4 | 4:3 | 9:16 | 16:9 | 21:9), dimension (1280x720 | 720x1280 | 1080x1080; the panel does not offer 1080x1080 on veo-3.1 and asks again if the user switches to it), duration (seconds), resolution (720p | 1080p, 1080p on Pro and Ultra)panel
open_resize_optionsShow a panel where the user picks the sizes to resize one image to, or frames one size, sees the cost beside Generate, and submits it themselves. imageId is the image: an asset id or a Scene Forge image id, from get_task's assetIds, list_assets or show_media. Any finished image in the caller's organization works, an upload too. There is no brandId: the brand is the image's own. The panel has two sides. One resizes to several sizes and renders 3 versions of each from the whole image. The other frames one size: the user places the image on that size's canvas, and it renders 1 version. Exactly one size in sizes opens the framing side; none or more open the other. Suggest framing only when the user names a placement, such as stories or a banner, not after every result. sizes pre-ticks preset keys or WxH sizes. prompt is only what to paint in the new space, if the user said it; usually leave it out. frame pre-sets the framing, needs exactly one size and follows the generative_resize frame rules. All of them are checked before the panel opens: at most 15 sizes, each side 64 to 4096, at most 4,194,304 pixels unless there is exactly one size, and a prompt up to 1000 characters. On the side with several sizes, a size the same shape as the image is refused, since nothing would be filled; the framing side takes it, as long as the frame is not the whole image unchanged. The framing side opens with three framings to tap, the agent's frame first when it sends one, else the whole image centered, and the user can fine tune the frame full screen. An image that cannot be resized still opens the panel, which says so and offers to choose another image. When the plan lacks the credits, the panel says how many are needed and links to add more. 1 image credit = 1 image from the plan's image allowance. The call holds until the user acts. After a submit from either side the panel folds to a short Started note and the call returns the resize's task id, which is the group id: call show_media with view: "resize" and that id once, since that card shows the versions as they finish, and do not poll get_task. If the user chooses another image instead (Change image, or the button on an image that cannot be used), nothing runs or is charged and the result's decision is change_image: ask which image to use, or open the uploader, then open this panel for it. A client that cannot show the panel gets the same presets, limits and cost lines as data, and runs generative_resize itself.imageId; optional sizes[] (max 15), prompt, frame (exactly 1 size)panel
open_upscale_optionsNeeds the Pro or Ultra plan; on Starter the call is refused with upgrade_required. Show a panel where the user picks the larger sizes for one image, sees each size's output and, unless upscales are unlimited, its cost beside the image allowance, and submits it themselves. imageId is an asset id or a Scene Forge image id; to find a named image, use list_assets through run_read_action, not show_media. targets pre-picks up to 4 sizes, only ones the user named, each {mode: "factor", value: 2, 3 or 4} or {mode: "long_edge", value} in pixels. The call holds until the user acts. After a submit the result carries decision: "submitted", the task_id (the group id), status, the sizes picked and, unless the plan is unlimited, the credits charged: call show_media with view: "upscale" and that id once, and do not poll get_task. If the user chooses another image, nothing runs or is charged and decision is change_image. The long-edge presets include the print sizes 12,288 and 16,384 px. Where the organization has print size (the Pro and Ultra plans, or enabled for it) sizes up to 16,384 px (and at most 4× the source) can be picked, and a print size shows its estimated file size; elsewhere a size above 8,192 px shows locked with a link to the plans and is never submitted. A client that cannot show the panel gets the same sizes, costs (none on an unlimited plan) and allowance as data and text, with a locked size marked as needing print size, and runs upscale_image itself once the user agrees.imageId; optional targets[] (max 4)panel
wait_for_panelKeep waiting for a panel the user has not answered yet. A panel opener holds its call open while the panel is on screen, and that hold cannot outlive one request; when it expires the opener returns waitAgain: true with a waitId, the id of that panel's request, and a resumeWith that spells this call. Call it with that panel and waitId. The wait then stays on that one request, so a user with the same panel open in two chats gets each answer in its own chat, and the user's answer still comes back as a tool result instead of as a message they have to send themselves. Call it again for as long as it keeps saying waitAgain, and do not end your turn instead: once it ends, the user's answer reaches you only with a later tool result, as latePanelAnswers (see Late panel answers). It performs nothing: the work is whatever the user clicks.panel, waitIdread-only
panel_bridgeInternal to NativeAds panels. Do not call it. A panel loads what it renders and reports what the user did through this tool, because the panel openers hold their calls open until the user acts and therefore return nothing while the panel is on screen. It performs the side effect the panel's own tool would have performed, so a resolve is refused unless a panel was actually opened for that subject. Listed here only because every tool on the surface is listed.panel, scopeId, action; optional viewId, diag, decision, assetIds, urls, tool, args, assetId, items—

A finished render, and a generated background, are read with show_media (views images, videos and background, see Showing media).

Video model options, each with the exact lengths duration may take, in seconds: optimized (renders on the plan's default model, today seedance-2.0-pro on Starter and seedance-2.5-pro on Pro and Ultra, with that model's inputs, lengths and video credits; at most 15 reference images and no reference videos on Pro; no intermediate frames; get_started states its lengths and inputs for the caller's plan; a refusal names optimized, never its render model), seedance-2.5-pro (6, 8, 10, 15, 20, 30 within the plan's limits below; refs-only / reference-to-video), seedance-2.0-pro (6, 8, 10, 12, 15), kling-v3-omni-pro (6, 8, 10, 12, 15, 20, 30; intermediateImageAssetIds with a start frame, bounded per length, and 20 and 30 need at least one), veo-3.1 (6, 8), grok-imagine-video (6, 8, 10, 12, 15). Any other length is refused with invalid_argument, and so is a legacy model (veo-3.1-fast, kling-v3-pro, seedance-1.5-pro, pixverse-v6); videos already made on one still read back. extend_generated_videos_group checks a group the same way against today's plan, so a group a new video could no longer copy is refused (invalid_argument, or upgrade_required over the plan's Seedance 2.5 limits or for a 1080p group on Starter). The MCP default is seedance-2.5-pro on a plan that has it and seedance-2.0-pro on one that does not; get_started's choices names the caller's. The REST default stays seedance-2.0-pro, because 2.5 rejects the first frame the REST flow normally sends. resolution takes 720p (the default) on every plan and 1080p on Pro and Ultra; 1080p on Starter returns upgrade_required. Each video costs video credits, by model, length and resolution: 1 for most, up to 10 for a 30s seedance-2.5-pro video at 1080p. Each video model option in get_started's choices carries units, keyed by resolution, then seconds, for the resolutions the plan may use, and planLimits.resolutions lists those. A call makes one video per prompt and bills the units per prompt.

seedance-2.5-pro is reference-to-video. Pass referenceImageAssetIds (bound as @Image N in list order) and/or referenceVideoAssetIds (bound as @Video N in list order), at least one reference total. Omit startImageAssetId, endImageAssetId, and intermediateImageAssetIds on image_to_video, and omit startFrameAssetId, endFrameAssetId, and intermediateFrameAssetIds on enhance_img2video_prompt; those fields are rejected for 2.5. seedance-2.0-pro (up to 9 images) and kling-v3-omni-pro (up to 7) take either a start frame (optional end frame) or referenceImageAssetIds, never both, with the same cap on every plan. Neither takes referenceVideoAssetIds. Every other model rejects both reference arrays, and grok-imagine-video renders from the start frame only, so it also rejects endImageAssetId / endFrameAssetId (invalid_argument).

2.5 depends on the plan. Starter has no seedance-2.5-pro at all. Pro allows up to 30 reference images, no reference videos, and up to 15 seconds. Ultra allows up to 30 reference images, up to 10 reference videos and up to 30 seconds. Exceeding the caller's plan returns upgrade_required instead of a video. Call get_started to read the organization's plan before promising a reference-video job.

Reference asset requirements, all enforced at submit before any generation is booked. Reference images: JPEG or PNG, 30MB or smaller, uploaded as an image, logo, or environment asset (an asset NativeAds generated for you reports fileType as the bare category image and is accepted as-is). On kling-v3-omni-pro the cap is 50MB, and an image whose dimensions we recorded must also have an aspect ratio (width / height) of 0.4 to 2.5; one with no recorded dimensions skips that check. Reference videos: MP4 or QuickTime, 200MB or smaller, 2 to 30 seconds each, 30 seconds combined, 23.8 to 60 FPS, and, whenever the dimensions are known, both model frame rules: a pixel count (width × height) of 407,696 to 8,295,044 AND an aspect ratio (width / height) of 0.4 to 2.5. The two are independent — 1400x300 is 420,000 pixels, inside the band, and is refused on its 4.67 ratio. A video whose size was never captured skips both checks rather than being rejected. A reference video whose duration has not been measured yet is rejected rather than queued: conflict while it is still processing, which is worth retrying, and invalid_argument once it reports complete without a duration, which needs a re-upload.

useBrandDna defaults differ by media: it is on by default for scene_forge and enhance_scene_forge_prompt, but off by default for image_to_video and enhance_img2video_prompt — pass useBrandDna: true to apply Brand DNA to video.

Brand DNA requires a plan that includes it. On a plan that does not, every Brand DNA tool returns upgrade_required, reads included, and the two paths through useBrandDna differ on purpose: sending useBrandDna: true fails with upgrade_required, while omitting the flag resolves it to false and the generation runs without Brand DNA. Nothing fails for a caller who never asked for the feature, but the output is generic — so read brandDnaAvailable from get_started before you promise a user on-brand results. When Brand DNA is not on the plan, the choices block omits the useBrandDna row entirely.

Orientation​

ToolPurposeKey inputsHints
get_startedOrientation for a cold start: plan, subscription/lockout, whether Brand DNA is available, whether a brand exists, role, a plain-language nextAction, the industries vocabulary, and a choices block giving every generation option, its default, its cost and how hard to ask the user about it, and currentBrand, the brand the user most recently picked in the brand picker (ask_user with panel: "brand_picker") within the last 6 hours, or null (nextAction then says to name it to the user). Call it first for any ad, image or video request, before asking the user anything.noneread-only

Finding and running actions​

Four tools reach the actions. Each run_*_action tool routes only the actions of its own risk level, so the consent a host asks for, and remembers, is per risk level: one "Always allow" on run_write_action or run_destructive_action covers every action that tool routes. For run_write_action that includes the paid ones, scene_forge, image_to_video and create_brand_dna_version; the usage caps still bill them, and the server-side gates above (renders refused on a client that shows panels, a Brand DNA build refused unless its panel offered it) still apply.

ToolPurposeKey inputsHints
find_actionsSearch the actions. An exact action name returns that one entry. Otherwise it scores each action by how many words of your query (three letters or more) appear in its name or description and names the best five: the top one (and a second only if it ties) in matches, each with action, via (the run_*_action tool to call), description, inputSchema, an example args object, and available; the rest in more, each with action, via and a one-line summary (query its exact name for the full entry). With no match it returns matches: [] plus every action and its via.queryread-only, idempotent
run_read_actionRun a read-only action.action; optional args (the action's own arguments)read-only
run_write_actionRun an action that creates or changes data.action; optional argswrite, open-world
run_destructive_actionRun an action that overwrites, cancels or deletes.action; optional argsdestructive, open-world

A run_*_action call returns the action's own result, unchanged, and every check the action faces by name still applies: plan, billing lockout and usage caps. Under read-only lockout find_actions and run_read_action still work and the other two are refused. These refusals come back as a tool result with isError: true, so you can correct the call:

  • an unknown action, which says to call find_actions, or a listed tool's name, which says to call that tool directly;
  • an action sent to the wrong run_*_action, which names the right one;
  • args that do not match the action's inputSchema. Unlike a direct call, the gateway enforces the schema, and the error's details carries violations, the inputSchema and the example.

describe_action, which took one exact action name, is no longer listed: find_actions answers that query the same way. It stays callable by name for a client that listed it.

args may be omitted or null for an action with no required arguments, and a JSON string holding an object is accepted in its place.

available: false comes with a reason: not on this organization's plan (the call would return upgrade_required), or disabled for this organization, when an organization has had that action switched off. A call to a disabled action, by either path, is refused with insufficient_scope.

Actions​

42 actions, none of them in tools/list. Call each through its gateway with the key args inside args, for example run_read_action with {"action": "list_recent_tasks", "args": {"limit": 5}}.

The eleven readers behind show_media and show_brand_dna are actions as well, for looking something up without showing it, such as finding a brand's product shots to pass on as ids. Through run_read_action no panel renders, and the result's display starts with "This is a lookup for you; nothing is shown to the user. To show it, call show_media or show_brand_dna." For list_scene_forges and list_generated_video_groups it adds that NativeAds cannot put a headline, CTA or other text onto a finished creative. To show the user, call the view instead.

ActionGatewayPurposeKey argsAsync
list_brandsrun_read_actionList brands, with optional filters. No panel; with two or more matches the result points to ask_user with panel: "brand_picker".optional industry, name, sortBy, page, limitno
get_assetrun_read_actionRead one asset by id.assetIdno
download_assetrun_read_actionReturn a short-lived presigned download URL, plus previewUrl: a tile-sized rendition to render instead of the full file (the original itself for a video or document). For a resize group, use download_generative_resize_group instead: one zip.assetIdno
get_scene_forge_prompt_enhancementrun_read_actionFetch an enhancement's result (optimizedPrompt, theme) to review before generating. promptEnhancementId is the task id enhance_scene_forge_prompt returned.brandId, promptEnhancementIdno
get_img2video_prompt_enhancementrun_read_actionFetch an enhancement's result (enhancedPrompt) to review before generating. promptEnhancementId is the task id enhance_img2video_prompt returned.brandId, promptEnhancementIdno
list_recent_tasksrun_read_actionList recent async tasks to recover task ids lost after a disconnect (including enhancement ids, which have no other list tool). Each task_id is the id the matching show_*/get_* tool consumes.optional kind (scene_forge, image_to_video, enhance_scene_forge_prompt, enhance_img2video_prompt, brand_dna_version, extract_assets_from_url, generate_environment, generative_resize, extend_generative_resize_size, upscale_image, and reframe_scene_forge_image for a reframe made before that tool was removed), status (pending, processing, completed, failed, cancelled), limit. There is no brandId filterno
get_taskrun_read_actionFetch an async task's status by the id an async tool returned, sent as taskId or task_id. Poll until terminal is true; succeeded marks a clean finish, and retryable (on failure) says whether resubmitting may help. A succeeded scene_forge / image_to_video task also carries assetIds. The panels poll it through run_read_action too. On a failed resize or extend task, error_message is one plain sentence to tell the user. A reframe made before the reframe tool was removed still reads, as type reframe_scene_forge_image. The group id upscale_image returns reads as type upscale_image: the group's own status, completed once at least one size finished and failed once every size failed. Read the sizes with get_upscale_group. Elsewhere that id answers as an unknown task id.taskId or task_id; optional wait (seconds, max 90)no
get_feature_usagerun_read_actionRead your organization's image credits and video credits used versus plan caps for the current billing period. One video uses 1 or more video credits, by model, length and resolution.noneno
list_assetsrun_read_actionLook up assets without showing them, with optional filters: the read show_media runs for view: "assets". type includes logo.optional brandId, type, status, tags[], campaignId, page, limitno
list_scene_forgesrun_read_actionLook up a brand's Scene Forge generations without showing them: the read behind show_media view: "images".brandId; optional sceneForgeId, imageId, status, partner, page, limit, sortBy, sortOrderno
list_generated_video_groupsrun_read_actionLook up a brand's video generation groups without showing them: the read behind show_media view: "videos".brandId; optional generatedVideosGroupId, partner, page, limit, sortBy, sortOrderno
get_environment_generationrun_read_actionLook up a generate_environment run without showing it: the read behind show_media view: "background".environmentGenerationIdno
get_generative_resize_grouprun_read_actionRead a resize group: its status, its source image (source, named like the panel), and each size with its pixels, preset name and label, status, framed (the user placed the image on it) and versions (variantId, assetId, status, rating, the dislike reason, picked, and once finished a preview url, the original file's fileUrl and its fileName, the name the zip uses). Download all takes every finished version that is picked or not disliked. The results card adds versions, picks and ratings without telling the model, so read the group before answering about them. A failed group, size or version carries error, one plain sentence. Sizes come in the order they were requested and each size's versions in the order they were made. Once a version can be downloaded, download says to get the files with download_generative_resize_group, one zip. Once a version is finished, rate says that a user who likes or dislikes a version wants it rated with rate_generative_resize_variant, since liking a version is not downloading it. Pass groupId, or the sizeId an extend_generative_resize_size task returned. With neither, it returns recent: the caller's resizes from the last 24 hours, newest first, at most 5, each with groupId, status, source.name, createdAt and its sizes (sizeId, name, width, height, versions), for a resize started in a panel whose id the model never got.groupId or sizeId, or neitherno
download_generative_resize_grouprun_read_actionOnly for when the user asks for the files; a like or a dislike is rate_generative_resize_variant. Get one link to a zip of a resize group. With variantIds it zips exactly those versions, each a finished version of the group (a version that is not is refused by id, and an empty list is refused). Without them it takes Download all: every finished version that is picked (pick_generative_resize_version) or not disliked. A size with no finished version, or whose finished versions are all disliked and none picked, is listed in skipped with the reason, and a group with nothing to take is refused. Files are named by size and version, 1080x1920-v2.png, the version being its rank among the size's undeleted versions, the number the card shows. Returns url, expiresAt, files (sizeId, variantId, assetId, width, height, version, fileName) and skipped. The link needs no login and works until expiresAt, 4 to 8 hours after the call. The zip is built each time the link is opened, so nothing is stored and nothing is billed. Refused on a deployment with no signed media links configured.groupId; optional variantIds[]no
get_upscale_grouprun_read_actionRead an upscale group: kind (always upscale), groupId, status, its source, and each output in the order picked (outputId, label such as ×2 or 4,096 px, width, height, credits (left out on an unlimited plan), status; once completed assetId, url, previewUrl and fileName; once failed error and creditReturned (never on an unlimited plan)), with allowance: the image allowance (kind limited, unlimited or unknown; remaining and cap only when limited; and periodEnd, when it resets).groupId (the task_id upscale_image returns)no
get_brandrun_read_actionLook up one brand and its logo without showing it: the read behind show_media view: "brand".brandIdno
get_brand_dnarun_read_actionLook up the brand's live Brand DNA payload without showing it: the read behind show_brand_dna view: "active". Needs a plan that includes Brand DNA.brandIdno
get_active_brand_dnarun_read_actionLook up the active version's detail without showing it: show_brand_dna view: "version" with no versionId. Needs a plan that includes Brand DNA.brandIdno
get_brand_dna_versionrun_read_actionLook up one version's detail without showing it: the read behind show_brand_dna view: "version". Needs a plan that includes Brand DNA.brandId, versionIdno
list_brand_dna_versionsrun_read_actionLook up every version for the brand without showing them: the read behind show_brand_dna view: "versions". Needs a plan that includes Brand DNA.brandIdno
create_brandrun_write_actionCreate a brand in your organization. Only name is required.name; optional industry, description, mission, values[], tone[], voice[], logoAssetIdno
initiate_asset_uploadrun_write_actionReserve an upload; returns uploadUrl and uploadPageUrl.brandId, files[] — each needs fileName and fileType only; optional fileSize, dimension (width, height), duration (seconds; send it for a video used as a Seedance 2.5 reference), isLogo. Optional categoryIdno
confirm_asset_uploadrun_write_actionConfirm an upload after you PUT the bytes to uploadUrl. Not needed when the user uploaded through uploadPageUrl or open_asset_uploader, which confirm themselves.uploadId; optional categoryIdno
extract_assets_from_urlrun_write_actionScrape and rank the images on a page and its related pages. Runs in the background.brandId, url; optional purpose, mediaasync
generate_environmentrun_write_actionGenerate a background/setting image from a description, for use as scene_forge's environmentAssetId. The prompt is the user's words, or one you proposed and they approved. The web app offers both an Upload and a Generate-from-prompt tab for the backdrop; this is the generate half. Costs image quota.brandId, promptasync
enhance_scene_forge_promptrun_write_actionEnhance a Scene Forge prompt.brandId, originalPrompt; optional productAssetIds[], environmentAssetId, useBrandDna, partnerasync
enhance_img2video_promptrun_write_actionEnhance an image-to-video prompt. seedance-2.5-pro is refs-only; seedance-2.0-pro and kling-v3-omni-pro take a start frame or reference images.brandId, originalPrompt, aspectRatio (16:9, 9:16 or 1:1; on veo-3.1 a 1:1 request is accepted and the prompt is written for 16:9); startFrameAssetId (required except on seedance-2.5-pro, or on seedance-2.0-pro / kling-v3-omni-pro with referenceImageAssetIds); optional endFrameAssetId, intermediateFrameAssetIds[] (kling-v3-omni-pro only), referenceImageAssetIds[], referenceVideoAssetIds[], model, duration, enableAudio, useBrandDnaasync
extend_scene_forgerun_write_actionAdd more image variations to a completed Scene Forge, reusing its recipe (prefer over a fresh scene_forge for more of the same look).sceneForgeIdasync
extend_generated_videos_grouprun_write_actionAdd one more video variation to a completed group, reusing its recipe: model, duration, resolution, audio and size are inherited and cannot be overridden. Call it again for another. The group is checked as a new video against today's plan, and refused when one could not be made. Bills the group's per-video cost in video credits; a group made before resolutions were recorded renders and bills at the plan's default resolution, which this extend records on the group.groupIdasync
generative_resizerun_write_actionResize one image to new sizes (Resize & fill on the website). The new space is filled with generated picture; the image is never cropped or stretched. On a client that shows panels the server refuses it and points to open_resize_options, where the user picks the sizes. imageId is the image: an asset id or a Scene Forge image id, from get_task's assetIds, list_assets or show_media. Any finished image in the caller's organization works, and the brand is the image's own. Each size is a preset key from get_started's "Resize an image" choice (1:1, 16:9, 1.91:1, 9:16, 2:3, 3:2, 3:4, 4:3, 4:5, 21:9) or WxH in pixels. Without frame it takes 1 to 15 sizes, each side 64 to 4096 and at most 4,194,304 pixels, and each size renders 3 versions from the whole image for 1 image credit. With exactly 1 size, the optional frame {x, y, w, h} is the part of the image to show, in source pixels at the size's shape: its height may be off that shape by at most 1 px. It may run past the image's edges, and that space is filled. It must overlap the image by at least 64 px each way, be at most 64 times the image on each axis, not scale the image past 4096 px a side, and not be the whole image unchanged. The image must be at least 64 px a side and have a recorded size. A framed size takes each side 64 to 4096 with no pixel cap and renders 1 version at that placement for 1 image credit; frame with more than one size is refused. A size outside its limits is refused with the bad value named, and so is a size the same shape as the image (aspect ratios within 1%) unless it has a frame. 1 image credit = 1 image from the plan's image allowance. The optional prompt is what to paint in the new space, up to 1000 characters; leave it out unless the user described it. The task id is the group id; read the result with get_generative_resize_group.imageId, sizes[]; optional prompt, frame (exactly 1 size)async
extend_generative_resize_sizerun_write_actionAdd one more version to one size of a resize group, for 1 image credit. There is no limit on versions per size: each extra one is billed and counted by the plan's usage cap. When the user names a size ("one more of the banner"), match it to sizes in the resize's result (every resize result and panel answer carries sizeId, name, width, height per size) or in get_generative_resize_group. A framed size's extra version keeps its placement. Refused while the size is still pending, so it also retries a size that failed. The task id is the sizeId; read the result with get_generative_resize_group sizeId.sizeIdasync
rate_generative_resize_variantrun_write_actionWhen the user likes or dislikes a version ("I like the second one", "this one looks wrong"), rate it here, never pick it. Set a resize version's rating to like, dislike or none. Every call writes the whole rating. Liking clears a dislike with its reason and note, disliking clears a like, and a dislike sent again replaces the saved reason and note, clearing any it leaves out. reason and note go with dislike only, and are refused with any other rating. An unknown reason or a note over 500 characters is refused. Sending the same call twice leaves the same state, so a retry is safe. Download all leaves out a disliked version unless the user picked it (pick_generative_resize_version); a like changes nothing about downloads. Returns variantId and rating, and on a dislike a display line: if the user has not said what is wrong, ask in one short question and save the answer as reason and note; offer one more version only after they agree. A dislike that leaves a size with every finished version disliked and none picked also returns a note: Download all leaves that size out unless the user picks one, so tell the user, and offer more versions with extend_generative_resize_size.variantId, rating; optional reason (off_brand | poor_quality | wrong_subject | bad_composition | other), note (up to 500 characters)no
pick_generative_resize_versionrun_write_actionPick only when the user chooses which versions to download; a like or a dislike is rate_generative_resize_variant, never a pick. Pick or unpick one finished resize version. A size can hold several picks. Picks always download: Download all takes every picked version even when disliked, and the card's Download button sends exactly the picks. picked defaults to true; false unpicks. Each call sets the state it names, so a retry or a duplicate leaves the same state. The pick is saved on the version, so it holds after a reload and in a later chat. Picking an unfinished version is refused; unpicking one is not. The results card calls it when the user taps a version. Returns the group as get_generative_resize_group does, with picked per version.variantId; optional picked (default true)no
upscale_imagerun_write_actionUpscale one image to 1 to 4 larger sizes. Needs the Pro or Ultra plan: on Starter it is refused with upgrade_required, and find_actions lists it with available: false. On a client that shows panels the server refuses it, and the user picks the sizes in a panel. imageId is an asset id or a Scene Forge image id. Each target is {mode: "factor", value: 2, 3 or 4} or {mode: "long_edge", value} with the long edge in pixels up to 8192, or 16384 with print size (the Pro and Ultra plans, or enabled for the organization); the other edge keeps the image's shape, and no two targets may make the same output size. A size above 8192 px from an organization without print size is refused with upgrade_required. Each size costs 1 image credit up to 24 MP, 2 up to 48 MP, 4 up to 96 MP and 11 up to 268.4 MP, and a size that fails is given back; an unlimited plan is not charged and the result names no credits. The task id is the group id, and the result carries the group as get_upscale_group returns it.imageId, targets[] (1 to 4)async
create_brand_dna_versionrun_write_actionStart a new Brand DNA extraction from assets/URLs. Send the files and the website together; either alone is half-empty. For an interactive (OAuth) caller, refused unless the Brand DNA panel (ask_user with panel: "brand_dna_options") offered it and the user did not choose Skip; API keys are exempt. Needs a plan that includes Brand DNA.brandId; optional name, assetIds[], urls[]async
commit_url_extraction_candidatesrun_write_actionSave chosen extraction candidates as assets on the brand. Refused on a client that shows panels, where the extraction gallery saves the user's picks itself.extractionId; optional items[] (candidateId, isLogo)no
scene_forgerun_write_actionStart a Scene Forge image generation. Refused on a client that shows panels: use open_generation_options. blendingPrompt is the user's words, or yours once they approved it. If it is an enhancer's output, pass the words you gave the enhancer as authoredPrompt so they are stored as what the user wrote.brandId, blendingPrompt; optional authoredPrompt, promptIsEnhanced, useBrandDna, theme, aspectRatio, productAssetIds[], environmentAssetId, partnerasync
image_to_videorun_write_actionStart image-to-video generation. Refused on a client that shows panels: use open_generation_options. userPrompts are the user's words, or yours once they approved them. If they are an enhancer's output, pass the words you gave the enhancer as authoredPrompts, at the same index. seedance-2.5-pro is reference-to-video (refs-only); seedance-2.0-pro and kling-v3-omni-pro take a start frame or reference images.brandId, userPrompts[], dimension; startImageAssetId (required except on seedance-2.5-pro, or on seedance-2.0-pro / kling-v3-omni-pro with referenceImageAssetIds); optional endImageAssetId, intermediateImageAssetIds[] (kling-v3-omni-pro only), referenceImageAssetIds[], referenceVideoAssetIds[], model, duration, resolution, enableAudio, useBrandDna, promptIsEnhanced, authoredPrompts[], partnerasync
update_brandrun_destructive_actionUpdate brand fields; only fields you pass change.brandId; optional name, industry, description, mission, logoAssetId, values[], tone[], voice[]no
rerun_brand_dna_versionrun_destructive_actionReplace a version's source set and re-run extraction. Permanently discards that version's current DNA payload, including manual edits, and deletes its stored files. No undo, no prior revision to read back. Accepts a version that is currently active, which blanks the brand's live DNA until the new run finishes and is activated — prefer create_brand_dna_version to keep the existing one. Needs a plan that includes Brand DNA.brandId, versionId; optional assetIds[], urls[]async
cancel_brand_dna_versionrun_destructive_actionCancel an in-progress extraction. Needs a plan that includes Brand DNA.brandId, versionIdno
delete_brand_dna_versionrun_destructive_actionPermanently delete a version. Not reversible. Needs a plan that includes Brand DNA.brandId, versionIdno

Working with async tools​

The thirteen async tools (all of them actions: rerun_brand_dna_version through run_destructive_action, and create_brand_dna_version, scene_forge, image_to_video, extract_assets_from_url, extend_scene_forge, enhance_scene_forge_prompt, extend_generated_videos_group, enhance_img2video_prompt, generate_environment, generative_resize, extend_generative_resize_size, and upscale_image, through run_write_action) return a task id immediately, whichever way they are called. Poll get_task (an action, through run_read_action) with that id until terminal is true (workflow status becomes completed, failed, or cancelled — note get_task reports completed, not the brand-DNA-version word ready), then read the finished resource with the call the submit result's readBack spells out: resultTool names the reader, resultView the view it takes when that reader is show_media or show_brand_dna, resultPanel the panel when it is ask_user, and resultIdField the argument the task id goes in. When that reader is an action, the result also carries resultVia, the run_*_action tool that reaches it. Pass wait to block instead of spinning: get_task with wait=90 holds the request open until the task is terminal or 90 seconds pass, so one call replaces about twenty status reads and you never need to sleep between them. If it comes back with terminal: false, call it again. wait is capped at 90 because the MCP route's own timeout is 120s. Through run_read_action a larger value is refused with invalid_argument, carrying the schema and an example with wait: 90, as every gateway action's arguments are checked against its schema; by its bare name, get_task clamps it instead. Omitting it keeps the old immediate-return behaviour.

A write tool's submit result also carries a settings block: used is what the run will actually render with (the resolved model, the resolved duration, the aspect ratio that will really be produced), defaulted names the inputs the caller never chose, and billed states the cost in image credits or video credits (for a video, the video credits per prompt and the model, length and resolution that set them; an upscale on an unlimited plan has no billed). Tell the user what is under defaulted and offer to change it before generating again — a re-run costs the same as the first run. A fully specified call carries no defaulted list at all.

The result's nextStep tells you when to stop rather than leaving you to judge it: while the task is still within a budget set from how long its kind can legitimately take, nextStep says to keep waiting; past that it switches to a hand-back. Those budgets differ by an order of magnitude — a prompt enhancement is capped in seconds, a seedance-2.5 video in tens of minutes — so do not substitute a cadence of your own. keep_waiting is the same signal in machine-readable form: true while the task is inside its budget, absent once it is spent or the task is terminal. Branch on keep_waiting, not on the wording of nextStep, which is prose and is edited.

The finished resource per async tool: Brand DNA → show_brand_dna with view: "version"; URL extraction → ask_user with panel: "url_extraction"; prompt enhancements → get_scene_forge_prompt_enhancement / get_img2video_prompt_enhancement (this is where the enhanced prompt text lives — get_task does not carry it); a generated background → show_media with view: "background"; a resize → show_media with view: "resize" and the group id; an upscale → get_upscale_group with the group id, or show_media with view: "upscale" to show it; generations → show_media with view: "images" / "videos", which renders the generation gallery panel and carries each variation's asset.assetUrl. Each generated video also carries renderedPrompt, the words the model received after any enhancement, translation or per-clip planning. It is absent until the video completes, and for videos made before the field existed.