Bring your own creative
Upload images and video you own, then register them into an advertiser's provider-side library — from your AI agent, over MCP.
Until now the MCP tools let an agent read your accounts and performance. The asset_* tools add the first creative-side capability: bring the source media you own — images and video — into AdCrunch, and place it in a specific ad account’s library so ads there can use it. All of it from the same AI client you already connected.
Two ideas
Everything here is built on two words. They mean different things, and keeping them apart is what makes the workflow legible.
- An Asset is a source media file your organization owns — an image or a video. It lives in AdCrunch, belongs to your organization (not to any one ad account), and exists before and independently of any ad. An Asset always has bytes we hold: a video hosted somewhere else is not an Asset.
- A Registration is the act — and the record — of placing one Asset’s bytes into a single advertiser’s provider-side library, in exchange for a provider identifier. One Asset can be registered to many advertisers, one per account. Registering does not make an Asset live; it makes it available for an ad in that account to reference.
The workflow
Start an upload
The agent calls asset_create_upload with
the filename. It gets back an assetId (ast_…) and a short-lived
uploadUrl — a presigned URL that accepts the bytes directly.
Upload the bytes — the agent does this itself
The agent sends an HTTP PUT to uploadUrl with the file as the body. The
bytes go straight to storage from the agent’s runtime; they never pass
through the conversation. A Worker can’t receive a large upload at all —
Cloudflare rejects an over-limit body before any code runs — which is why
the upload is client-to-storage, not through us.
Finalize
The agent calls asset_finalize with the
assetId. Nothing is known about the file until it lands, so this is where
the type and size are checked and a wrong file is rejected. On success the
Asset joins your library. You can pass an advertiser_id here to register
in the same call.
Register
asset_register places the Asset in an
advertiser’s library. It returns immediately with a running Registration —
the provider processes the file in the background.
Poll until ready
The agent calls asset_get to watch the
Registration go from running to ready. Video can stay running for
several minutes while the provider transcodes it — that’s normal, not a
failure.
What you can upload
Finalizing rejects anything ads can’t use. Accepted types today:
- Images — JPEG, PNG, WebP, GIF.
- Video — MP4 (Meta accepts files up to 4 GB).
Size can’t be enforced before the file arrives, so an oversized file is caught at finalize and discarded — upload a smaller version and try again.
Statuses you’ll see
| On | Value | Meaning |
|---|---|---|
| Asset | pending |
Reserved; the bytes haven’t landed or been finalized yet. |
| Asset | ready |
Finalized and usable. |
| Registration | running |
Sent to the provider; still processing. Poll asset_get. |
| Registration | ready |
Live in the advertiser’s library; carries the providerIdentifier. |
| Registration | failed |
The placement failed; failureReason says why. Retry asset_register. |
Scopes
The read tools need asset:read; the write tools — upload and register — need asset:write. Registration isn’t folded into mutation:write: an Asset landing in a library changes no delivery and spends no money, so it stays a separate, lower-stakes grant. See Auth & scopes.
Provider support
Meta and TikTok are supported today, and support is per-provider by design: Meta streams the bytes, while TikTok registers media by URL — it fetches the file itself, so a video that Meta accepts up to 4 GB may be refused by TikTok’s own lower limits, reported plainly on the Registration. What each provider supports carries the rest, including why Google Ads is recorded as unsupported rather than failed. As more providers come online they slot in behind the same five tools.