Skip to main content
The library: browse, search, import and upload the media an account owns. 15 tools. Every tool below is exposed by the hosted MCP server at https://mcp.contenthero.ai and by the @contenthero/mcp npm package. A write tool changes your account; a read tool does not.

list_media

read List the library’s files: every file the account keeps, or one part of the library with source, each item naming the part it is in. Filter by contentType, kind, favorited or archived; order with sort and order; page with limit and cursor. Each item shows its media id, its file name and size, its asset id (the id get_project reports as a clip’s sourceId) and its resolved URL inline, so you can reference it directly. Call get_media to SEE an item (image blocks / video keyframes).
boolean
Only archived files.
string[]
Only these media types.
string
The previous page’s cursor.
boolean
Only favorited files.
`creation` \| `board` \| `look`
Creations only. Filter by asset class: ‘creation’ (normal generations), ‘board’ (reference boards), or ‘look’. Omit to list all.
integer
How many to return.
`asc` \| `desc`
The sort direction.
boolean
Link each image’s small copy instead of the file itself, where the library keeps one: for drawing images small, as code that shows many at once does. Never for downloading or delivering a file, or showing it large.
`createdAt` \| `fileName` \| `sizeBytes`
The field to sort by.
`all` \| `creations` \| `uploads` \| `exports`
Which part of the library to read: ‘all’ (the default, every file), ‘creations’ (studio generations), ‘uploads’ (files the user uploaded), or ‘exports’ (renders of their projects).

get_media

read SEE specific media, up to 5 items. This is for YOUR eyes only: it returns image blocks so you can judge a face, check legibility or compare variations, and it renders NOTHING for the person. If they should see it, call show_media, which displays up to 100 items and costs you almost no context. Pass a batch of items to view at once, returned as image blocks for you: each item is either a { url } (e.g. a URL threaded from get_context, a layer/asset URL from get_project / get_card, or an upload URL from list_media source=uploads) or a { mediaId } (the media id list_media, search_media and get_folder print: a1B2c3D4, or a1B2c3D4-2 for one output of a generation with several). Returns light metadata per item plus an IMAGE block for each image so you can actually see it. For a VIDEO, set frames (and optionally fromSec/toSec) on the item to get low-res KEYFRAMES across that source-time window, so you can watch the raw footage (judge B-roll relevance, take quality) without editing it; audio still returns metadata + the url. A bare id for a generation returns ONLY its primary output, named by its full media id, and lists the others’ media ids; pass one of those to see it. To ZOOM, set region { x, y, width, height } on an item, in the file’s own pixels: that part is cut from the original and returned at its own detail, never enlarged, so you can check small text or an edge; on a video it applies to every keyframe. Use this to inspect the actual pixels, not just URLs.
value[]
required
The media to LOOK at, up to 5 per call. Five is where the inline byte budget runs out, not a round number. Use show_media for a larger set you only need to display.

show_media

read SHOW media to the person, up to 100 items in one card. Use this to present a set you do not need to look at yourself: search results, a folder, a shortlist, everything a list_media call returned. It renders a grid the person can browse, expand and act on, and it costs you almost no context because it returns urls rather than pixels. Each item is a { url } or a { mediaId }, the same shapes get_media takes. Pair it with list_media: list to FIND, show to PRESENT. Do not re-show media another tool already displayed: anything that creates or imports media renders its own card, and showing it again only duplicates it. If you need to SEE the pixels yourself (judge a face, check legibility, compare variations) use get_media instead, which attaches image blocks for up to 5 items.
value[]
required
The media to show, up to 100 items per call.

search_media

read Semantically search the account’s editable media library (their generated creations, uploads, licensed stock, and brand assets) by describing the content in natural language. Returns matching assets ranked by relevance, each with its media kind, a description, tags, and, for videos, the timestamps of the specific scenes that matched, so a precise moment can be located. Use this to find existing material to place, reference, or build with, rather than generating new media, whenever the user refers to footage, images, audio, or clips they already have. Optionally restrict results to specific media kinds. This searches only the account’s own usable library, never inspiration, published posts, or knowledge. Call get_media to SEE a match (image blocks / video keyframes).
string
required
A natural-language description of the media to find, describing its visible or audible content.
string
The previous page’s cursor.
string[]
Restrict results to these media kinds. Omit to search all kinds.
integer
How many to return.
boolean
Link each image’s small copy instead of the file itself, where the library keeps one: for drawing images small, as code that shows many at once does. Never for downloading or delivering a file, or showing it large.

import_media

write Import a remote URL as first-class media: the server fetches and re-hosts it, returning its outputId + public URL (referenceable by outputId in generate_* and as an asset on a card via update_card). Use this for a file already on a public URL, or from a hosted client that cannot read local files. Requires the library:write scope.
string
required
A public https URL to fetch and re-host.
string
Optional MIME override (else taken from the response).
string
Optional file name (used for its extension).

share_media

write A public link to media made in Studio: outputs of your finished generations, by the media ids list_media, search_media and get_folder print. One output gives its generation’s link, opened at that output; a generation keeps one link, so sharing it again returns the same page. Several give a new link to them as a set, leaving out any that cannot be shared. Anyone with the link sees the media, with no sign-in. Pass shared:false to stop sharing, naming a generation by one media id or any media link as shareUrl; a stopped link never opens again, and sharing again makes a new one. An export’s share page comes with get_export. Requires the studio:write scope.
string[]
One or more media ids of outputs of your finished generations. To stop sharing, one.
string
With shared:false, the media link to stop.
boolean
Default true. Pass false to stop sharing.
string
A title for a set of two or more.

create_media_upload

write Upload local files as first-class media (phase 1 of 2). Accepts 1-25 files in one call. Returns, for each file, a signed uploadUrl and the exact headers to send; PUT each file’s bytes to its URL with those headers unchanged, then call complete_media_upload once with every returned outputId. The finished media is referenceable by outputId in generate_* and as an asset on a card via update_card. For a file already on a public URL, use import_media instead. Requires the library:write scope.
object[]
required
1-25 files to upload.

complete_media_upload

write Finalize uploads (phase 2 of 2) after each file’s bytes were PUT to its signed uploadUrl from create_media_upload. Accepts 1-25 outputIds in one call: finalize a batch together, so the person sees it as one card. Publishes each file and returns its outputId and URL. Requires the library:write scope.
string[]
required
1-25 outputIds returned by create_media_upload.

list_folders

read List the account’s library folders (their own manual and smart folders, as a flat list with parent links for nesting) together with the built-in derived folders (recents, favorites, edits, canvas, cards). Use this to see how the library is organized before browsing or filing items.
string
The previous page’s cursor.
integer
How many to return.

get_folder

read Return the contents of one folder. The folder id is either one of the account’s own folder ids or a built-in derived-folder key. A manual folder returns exactly the items filed in it; a smart folder computes its members live from its saved query; a derived folder returns its built-in set. Items are media (with kind and a description) and, in manual folders, entities such as projects or posts.
string
required
A folder id, or a derived-folder key (recents, favorites, edits, canvas, cards).
string
The previous page’s cursor.
integer
How many to return.
boolean
Link each image’s small copy instead of the file itself, where the library keeps one: for drawing images small, as code that shows many at once does. Never for downloading or delivering a file, or showing it large.

create_folder

write Create a new library folder. A manual folder is an initially-empty collection you then file items into. A smart folder saves a query and stays live, always showing whatever currently matches. Optionally nest it under a parent folder. Create a folder only when the user wants to organize or save a view, not to hold a single transient result.
string
required
The folder name.
string
Nest the new folder under this parent folder id.
object
For a smart folder: the live query that defines its membership (the same filters as the library search bar).
`manual` \| `smart`
‘manual’ (a collection you file items into) or ‘smart’ (a saved live query). Defaults to manual.

update_folder

write Update the account’s own folders: rename one, MOVE folders under a different parent (or to the top level with a null parent), change a smart folder’s saved query, and FILE or UNFILE items. addItems/removeItems are DELTAS of { mediaId } (media, as list_media, search_media and get_folder print it), { projectId } or { cardId }, not a list to replace, because an item can sit in several folders at once and a replace would silently unfile it from the others. Filing never moves or copies anything: it adds a pointer, and only manual folders accept items (a smart folder computes its own membership). Pass folderIds to patch several folders at once, which crossed with addItems files the same items into all of them; renaming and re-querying still need exactly one folder. NOTE the asymmetry: nesting a FOLDER via parentId is a MOVE (a folder has one parent), while filing an ITEM is a pointer that leaves its other folders alone.
string
required
The folder id to update.
value[]
File these items into the folder(s). A delta: their other folders are untouched.
string[]
Patch several folders at once. Attribute fields (name, query) still need exactly one.
object
Move one item within this manual folder: after or before another of its items, or to an end (position). Each item is named as addItems names one. Name neighbors or a position, not both.
string
A new name.
string,null
A new parent folder id, or null to move to the top level. MOVES the folder.
object
For a smart folder: the live query that defines its membership (the same filters as the library search bar).
value[]
Unfile these items. Only the pointer goes; the asset is never deleted.

delete_folder

write Delete one of the account’s own folders and everything nested under it. This removes the folder structure only; the media and entities inside are pointers, so the underlying assets are never deleted. Confirm intent before deleting a folder that contains items.
string
required
The folder id to delete.

favorite

write Favorite or UNfavorite an asset: pass favorited:false to clear it (default true). For media (one output of a generation, an upload, stock), pass its mediaId as list_media, search_media and get_folder print it (a1B2c3D4-2 for one output of several). For anything else, pass assetType + id (card, voice, brand_kit, project, inspiration_content, gallery, transition, caption-template, template, space). Requires the favorites:write scope. Idempotent in both directions.
`card` \| `voice` \| `brand_kit` \| `project` \| `inspiration_content` \| `gallery` \| `transition` \| `caption-template` \| `template` \| `space`
The kind of asset, for anything that is not media. Pass with id.
boolean
Default true. Pass false to UNfavorite.
string
The asset’s id, with assetType.
string
A media id, for media. A bare id for a generation with several outputs is refused with their media ids listed.

archive

write Archive or UNarchive an asset: pass archived:false to restore it (default true). ContentHero never hard-deletes, so this is always reversible. For one output of a generation, pass its mediaId (a1B2c3D4-2 for one output of several). For anything else, pass assetType + id (card, brand_kit, brand_kit_section, project, space, template). Archiving is a timestamp and nothing else is touched, so a scheduled card restores as scheduled. Requires the favorites:write scope. Idempotent in both directions.
boolean
Default true. Pass false to RESTORE (unarchive).
`card` \| `brand_kit` \| `brand_kit_section` \| `project` \| `space` \| `template`
The kind of asset, for anything that is not media. Pass with id.
string
The asset’s id, with assetType.
string
A generated output’s media id. A bare id for a generation with several outputs is refused with their media ids listed.