Manage a Cloudinary media library — upload from a URL, search and tag assets, organise folders, apply named transformations, and build delivery URLs.
Cloudinary ships in the w6w first-party pack. It declares 21 actions, 2 health checks, and the host runs its code in a sandbox that never sees the credential.
io.w6w.cloudinaryCloudinary puts a media library into a workflow — upload an asset from a remote URL or data URI, search and tag it, organise folders, define reusable named transformations, and build the delivery URLs that are the point of all of it. Assets can be read back with their derived renditions and EXIF data, updated with tags, context and structured metadata, renamed (which moves them between folders), deleted by id or prefix, and restored where backups are enabled.
Named transformations turn a size or crop setting into something a workflow references by name rather than a string baked into every URL — edit the definition once and every derived asset built from it regenerates on the next request. Delivery URLs are assembled locally from the cloud name, transformation and public id rather than fetched from an endpoint, and can include a version segment to make a URL immutable against a later overwrite.
The app tracks a few real gotchas: overwriting or deleting an asset does not flush the CDN edge cache unless explicitly invalidated, an upload without an explicit public id creates a fresh copy on every run rather than replacing the last one, and tag operations vary widely in scope — from touching one asset’s tags to clearing every tag across the entire account. It does not perform signed uploads or signed delivery URLs for private assets, since those require signing a request body rather than a plain HTTP call.
Three routes to the same 21 actions. The Workflow tab is generated from Cloudinary's own manifest and carries its real ids, so it is copy-pasteable; the Code and CLI examples are the same call for any action on any app, so every app-specific value in them is a blank you fill in.
asset-delete Delete by public id (up to 100), by prefix, or everything of a type. The last two need an explicit confirmation — neither can say in advance how much it removes.
asset-explicit Re-run the upload pipeline over an asset already in the library — pre-generate transformations, or run auto-tagging, moderation and OCR after the fact.
asset-get One asset in full — including its derived renditions and extracted metadata, and unlike search, immediately after upload.
asset-list Assets by public-id prefix, newest first. Filtering by anything richer — tags, size, dates — is Search's job.
asset-rename Change an asset's public id — which, in a fixed-folder account, is also how it moves folders. Every delivery URL using the old id breaks.
asset-restore Bring back deleted (or overwritten) assets — only if the account had backups enabled BEFORE the delete. Without them the response is empty rather than an error.
asset-search Cloudinary's search expression language over every indexed field — tags, folder, format, dimensions, dates, context and structured metadata. The index is eventually consistent.
asset-tag Add or remove one tag across many assets without touching their other tags. `replace` and `remove_all` are destructive and need confirming.
asset-update Change an asset's tags, context, structured metadata or moderation status. Tags REPLACE the whole set — Manage Tags is the additive version.
asset-upload Upload from a remote URL or a data URI. Without a public id Cloudinary invents one, so repeated runs create duplicates rather than replacing.
asset-url Assemble a transformation URL from a public id — locally, with no API call. Refuses private and authenticated assets, which need a signature this app cannot produce.
folder-create Create a folder and any missing parents. Dynamic-folder accounts only — in a fixed-folder account, folders come from the assets' public ids.
folder-delete Delete an empty folder. Cloudinary refuses while it still holds assets, which is why this needs no confirmation — emptying it is a separate, gated step.
folder-list The folders directly under a path — one level per call, since Cloudinary returns no tree.
metadata-field-list The account's structured metadata schema — the external ids and allowed enum values that writing metadata has to match.
tag-list Every tag in use for a resource type. Tags are per resource type, so the same word on an image and a video is two entries.
transformation-create Define `t_name` once and reference it from every URL — so changing the size of a thumbnail is a setting rather than a redeploy.
transformation-delete Remove a named transformation and every rendition generated from it. Originals are never touched; URLs using `t_name` break.
transformation-list Named transformations and the unnamed ones Cloudinary has generated from delivery URLs — the latter being a record of storage spent, not a design.
upload-preset-list Stored upload settings by name, for Upload Asset's preset field. The `unsigned` flag marks presets anyone with the cloud name can use.
usage-get Plan usage — credits or transformations, storage and bandwidth — plus the hourly API request allowance from the rate-limit headers.
A workflow step names the app and the action, and the editor fills in the
connection when you pick one. This is the Step shape from the
workflow spec, carrying Cloudinary's real ids.
{
"manifestVersion": "2",
"name": "cloudinary-example",
"steps": [
{
"id": "asset-explicit",
"uses": {
"app": "io.w6w.cloudinary",
"action": "asset-explicit",
"connection": "conn_YOUR_CONNECTION_ID"
},
"with": {
"publicId": "<publicId>"
}
}
]
}asset-explicit asset-get asset-list asset-rename asset-restore +16 more actions available
Every app-specific value here is a blank you have to fill in. An
app action is reached through the connection that authenticates it, so the
address is a connection id, not the app id — and connections belong to your account,
so a public page cannot know yours. Create one for Cloudinary, then fill in
the three blanks: conn_YOUR_CONNECTION_ID, the action key, and the
parameters that action declares. The call itself is real — the shape is transcribed
from the studio's own snippet builder, which prints the same kind of blanks — but
nothing in it is specific to Cloudinary. The Workflow tab is where this app's
real ids are.
npm install @w6w/sdkyarn add @w6w/sdkpnpm add @w6w/sdkdeno add npm:@w6w/sdkimport { W6wClient, isActionRun } from "@w6w/sdk";
// Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.
const client = new W6wClient();
const envelope = await client.run({
urn: "conn_YOUR_CONNECTION_ID",
action: "asset-explicit",
payload: {
publicId: "<value>",
// resourceType: "<value>",
// type: "<value>",
// eager: "<value>",
// eagerAsync: "<value>",
// categorization: "<value>",
// autoTagging: "<value>",
// ocr: "<value>",
// tags: "<value>",
// context: "<value>",
},
});
if (isActionRun(envelope)) console.log(envelope.value); npm install -g @w6w/cli w6w run conn_YOUR_CONNECTION_ID --action asset-explicit --payload '{"publicId":"<value>"}' Give an AI agent Cloudinary — without giving it Cloudinary's credentials. One MCP endpoint exposes every app, function and workflow the caller is entitled to, as tools it can discover and run. Access is granted per team while we onboard.
One tool call{
"name": "w6w_invoke",
"arguments": {
"ref": "app:io.w6w.cloudinary#asset-explicit",
"input": {
"publicId": "<publicId>"
}
}
}
Every tool names its target with a single ref. The
app: form above doesn't name a connection at all — the
host resolves which of the caller's Cloudinary connections to sign
with, and refuses rather than guesses when the answer is ambiguous.
The token is attached host-side, at the moment of the call. It is never a tool argument, never in the model's context, and never in a transcript — so a prompt injection has nothing to exfiltrate.
Tools are derived per end user from what that person has actually connected and is entitled to — not one shared bot identity carrying the union of everyone's access.
Multi-step work runs on the workflow engine and returns a run handle the agent can poll — retries, branching and state survive the conversation that started them.
Cloudinary's declared health checks are on the surface too, so an agent can tell "the vendor is down" from "your credential expired" before it burns a retry on either.
The MCP surface is part of the hosted platform. Cloudinary itself is MIT, and the runtime that executes it is source-available (FSL).
Cloudinary declares its own checks, so its health is a property of the app rather than something the host guesses at.
The Admin, Upload and Media Transformation components for THIS connection's datacenter — an outage in another region is not this connection's problem.
Cloudinary's hourly API request allowance, read from the rate-limit headers, and the plan's credit budget from GET /usage. Being throttled and being over budget are different problems.