hermosodocs

Files & documents

Read and write files in the user’s Google Drive or OneDrive, build reports as Sheets and Docs, save pages to Notion, and send designs to and from Canva.

30 tools. Every name, description and parameter on this page is generated from the running MCP server — see how this reference is built.

Google Drive: full CRUD over the files Hermoso created in th…

save_to_drive#

Save file(s) to Google Drive

Save a Hermoso render — or ANY file — into the user’s connected Google Drive. Pass a Hermoso render URL as url (or urls[] for several); for a local/external file, call upload_file first and pass the url it returns. Optional folder (created if new) + name. Returns the Drive file(s) with a webViewLink. Needs Google Drive connected (Settings > Connectors > Google Drive — one connection covers Drive, Sheets and Docs). NOTE: Hermoso uses the drive.file scope, so it reaches ONLY the files it created plus any the user explicitly handed over with the Google file picker in the app — never their whole Drive.

ParameterTypeDescription
urlstringa single Hermoso render URL to save
urlsstring[]several render URLs (up to 20) to save in one call
folderstringDrive folder name to save into (created if new)
namestringfile name (single save)

Google Sheets: export structured data to a spreadsheet the a…

create_sheet#

Create a Google Sheet

Create a new Google Spreadsheet in the user’s Drive and optionally fill it with rows — e.g. export a swipefile, ad list, or performance report. Pass rows as an array of row arrays (first row = headers). Returns the spreadsheet id + URL. Needs Google Drive connected (Settings > Connectors > Google Drive — one connection covers Drive, Sheets and Docs).

ParameterTypeDescription
titlestringspreadsheet title
rowsstring | number | boolean[][]rows to write — array of row arrays; first row = headers

append_to_sheet#

Append rows to a Google Sheet

Append rows to a Google Sheet Hermoso can reach — one it created (pass the spreadsheetId from create_sheet) or one the user handed over with the Google file picker in the app (find its id with list_drive_files). rows = array of row arrays.

ParameterTypeDescription
spreadsheetIdrequiredstringthe spreadsheet id from create_sheet
rowsrequiredstring | number | boolean[][]rows to append — array of row arrays
rangestringrange to append at (default A1 / first sheet)

read_sheet#

Read a Google Sheet range read-only

Read cells from a Google Sheet Hermoso can reach — one it created, or one the user handed over with the Google file picker in the app (that is how an EXISTING spreadsheet becomes readable; find its id with list_drive_files). Pass the spreadsheetId (from create_sheet) OR paste a Google Sheets URL as sheetUrl. If Google answers that the file was not found, the user has not picked it yet — ask them to pick it in the app rather than retrying. Returns a 2-D array of values.

ParameterTypeDescription
spreadsheetIdstringthe spreadsheet id (from create_sheet)
sheetUrlstringa Google Sheets URL to read — the spreadsheet id is extracted from it
rangestringA1 range, e.g. "A1:D50" (default A1:Z1000)

GOOGLE SLIDES: a swipefile collection as a real presentation…

export_swipefile_deck#

Swipefile to Google Slides

Turn a SWIPEFILE COLLECTION into a real Google Slides deck — one slide per saved ad, carrying the creative, the brand, the ad copy, the run dates with the run length, and the platform. This is the thing a marketer actually presents to a client or a team. Returns the presentation id + URL. Creates a NEW deck every time: under the drive.file scope Hermoso can only touch files it created, so it cannot add slides to a deck the user already has. A creative whose ad-library link has expired cannot be embedded — Meta signs those URLs with a short expiry — so that slide says so in words and keeps its copy and run dates, and the reply reports how many. Needs Google Drive connected (Settings > Connectors > Google Drive — one connection covers Drive, Sheets, Docs and Slides).

ParameterTypeDescription
collectionstringthe swipefile collection to export, by name or id (default: the first collection)
titlestringdeck title (default: the collection name)
limitnumbermax ads to include, 1-60 (default 30)

Notion

list_notion_pages#

List Notion pages read-only

Find the Notion pages and databases the user shared with Hermoso, by title, newest edited first. Gives the page id that save_to_notion, append_to_notion_page and read_notion_page take, or the database id to save rows into. Read-only, free. Needs Notion connected (Settings > Connectors > Notion).

ParameterTypeDescription
querystringwords in the title
type"page" | "database"limit results to pages or to databases; omit for both
limitnumber1-100, default 25
cursorstringfrom the previous page

save_to_notion#

Save to Notion

Save to the user's Notion as a NEW page: a research report, competitor teardown or campaign report as `content` (markdown: headings, lists, links, and an image or video URL on its own line becomes the media), a swipefile collection (swipefileCollection: name or id; each ad with its creative, copy, run dates and link), the content calendar (includeSchedule:true), or a mix. Put it under parentPageId, as a row in databaseId, or omit both for a private page in their workspace. Long text is split across blocks, never cut. The answer is read back from Notion. Free; never overwrites anything.

ParameterTypeDescription
titlestringtitle of the new Notion page
contentstringmarkdown body
swipefileCollectionstringswipefile collection name or id
includeSchedulebooleanadd the scheduled posts
parentPageIdstringpage id or link to save under
databaseIdstringdatabase id or link: saves as a new row
dataSourceIdstringdata source id to save into as a new row; pass only one of parentPageId, databaseId, dataSourceId
iconstringone emoji

append_to_notion_page#

Add to a Notion page

Add to the END of an existing Notion page (pageId or its link, from list_notion_pages): markdown content, a swipefileCollection, or includeSchedule:true. Nothing already on the page changes. Free.

ParameterTypeDescription
pageIdrequiredstringpage id or link
contentstringmarkdown to add
swipefileCollectionstringswipefile collection name or id to append, with each ad's creative, copy, dates and link
includeSchedulebooleantrue appends the scheduled posts too

read_notion_page#

Read a Notion page read-only

Read a Notion page the user shared with Hermoso, as markdown (pageId or a Notion link). A database id answers with its data sources instead. Read-only, free.

ParameterTypeDescription
pageIdrequiredstringpage id or Notion link

export_schedule_to_notion#

Export the schedule to Notion

Export the posting schedule to a Notion database, one row per post: date, channels, caption, media link and status. Creates a new database (under parentPageId, or private in the workspace) or writes into an existing one (databaseId), matching its columns by name. historyDays adds posts already published. Up to 100 rows per run; the answer says if more were left. Free.

ParameterTypeDescription
parentPageIdstringNotion page to create the new database under; omit for a private page in the workspace
databaseIdstringan existing database id or link
dataSourceIdstringdata source id of an existing database to write rows into, matched to columns by name
titlestringname for a new database
historyDaysnumber0-90 days of published posts to include

query_notion_database#

Read a Notion database read-only

Read the ROWS of a Notion database the user shared with Hermoso — e.g. the team's content calendar: each row's title, id, link and every property as a plain value (status, date, channels, caption, links), plus the database's columns with their types and options. Filter with match {"Status": "Scheduled"} (typed from the database's own columns) or a raw Notion filter object; sort with sortBy (a column, or created_time / last_edited_time) and direction. Up to 100 rows per call, cursor for more; the answer says when Notion stopped at its 10,000-result limit. Use it to import a calendar and schedule its posts, or to find the row update_notion_row changes. Read-only, free. Needs Notion connected (Settings > Connectors > Notion).

ParameterTypeDescription
databaseIdstringdatabase id or link (list_notion_pages type:"database")
dataSourceIdstringdata source id from an earlier read, as an alternative to databaseId
matchobject{"Column": value} — equality for status/select/checkbox/number/date, contains for text/multi-select
filterobjecta raw Notion filter object
sortBystringcolumn name to sort by, or created_time or last_edited_time
direction"ascending" | "descending"ascending (default) or descending
limitnumber1-100, default 50
cursorstringnextCursor from the previous page of rows
archivedbooleanread archived rows instead

update_notion_row#

Update a Notion database row destructive

Change properties on ONE row of a Notion database (pageId from query_notion_database) — e.g. mark a calendar row Status "Posted" and put the live post link in its URL column. properties is {"Column": value} by column name: text, number, checkbox, select (an existing option or a new one), status (must be an existing option), multi-select (array; replaces the whole value), date (ISO, or {start, end}), url, email, phone; null clears. Validated against the database's own columns before anything is sent and refused by name otherwise, never coerced; columns you do not name keep their values. Read back from Notion. trash:true moves the row to Notion's trash (restorable; returns a preview first and needs confirm:true), trash:false restores it. Free.

ParameterTypeDescription
pageIdrequiredstringthe row id or link
propertiesobject{"Column": value}
trashbooleantrue moves the row to Notion trash (needs confirm); false restores it
confirmbooleantrue confirms moving the row to trash; not needed for other changes

Google Docs: export copy / brief / report as a doc the app c…

create_doc#

Create a Google Doc

Create a new Google Doc in the user’s Drive with a title + optional body text — e.g. export ad copy, a creative brief, or a report. Returns the document id + URL. Needs Google Drive connected (Settings > Connectors > Google Drive — one connection covers Drive, Sheets and Docs).

ParameterTypeDescription
titlestringdocument title
textstringbody text to insert

append_to_doc#

Append text to a Google Doc

Append text to the end of a Google Doc Hermoso can reach — one it created (pass the documentId from create_doc) or one the user handed over with the Google file picker in the app (find its id with list_drive_files). Optional `dropdown:{title, options:[2-50], selected}` appends a Google Docs dropdown chip after the text — e.g. text "Status: " + dropdown {title:"Status", options:["Draft","In review","Approved"]} gives a brief a status the team can click to change; the chip is confirmed by reading the doc back. Set it later with update_doc dropdowns.

ParameterTypeDescription
documentIdrequiredstringthe document id from create_doc
textstringtext to append at the end of the doc (optional when a dropdown is passed)
dropdownobjecta dropdown chip to append after the text

read_doc#

Read a Google Doc read-only

Read the text of a Google Doc Hermoso can reach — one it created, or one the user handed over with the Google file picker in the app (that is how an EXISTING doc becomes readable; find its id with list_drive_files). Pass documentId (from create_doc) OR paste a Google Docs URL as docUrl. Under the drive.file scope it reaches nothing else in the user’s Drive; if Google answers that the file was not found, the user has not picked it yet — ask them to pick it in the app rather than retrying. Returns the plain text of EVERY tab (each headed by its tab name when there are several), with smart chips (dropdowns, people, dates, rich links) shown as the text Docs displays, plus `dropdowns[]` — each chip with its title, current value and options, which is what update_doc dropdowns sets. Read-only, free.

ParameterTypeDescription
documentIdstringthe document id (from create_doc)
docUrlstringa Google Docs URL to read — the document id is extracted from it

The Sheets / Docs WRITE surface

list_sheet_tabs#

List the tabs in a Google Sheet read-only

The tabs in a Google Spreadsheet, each with its name, numeric sheetId, row/column count and position. Call this BEFORE naming a tab in update_sheet / clear_sheet_range / manage_sheet_tabs / format_sheet, and before proposing to delete one — it is how you learn what the file actually contains instead of guessing at a name. Read-only, free.

ParameterTypeDescription
spreadsheetIdstringthe spreadsheet id (from create_sheet, or list_drive_files for one the user picked)
sheetUrlstringa Google Sheets URL — the id is extracted from it

update_sheet#

Write to a range in a Google Sheet destructive

CORRECT cells in a Google Sheet — write values to an exact range, overwriting whatever is there. This is the fix append_to_sheet cannot make: appending only ever adds rows at the bottom, so without this a wrong number stays wrong forever and the only "correction" is a second row contradicting the first. Pass `range` (e.g. "B2:C5", or "Q3 Report!B2" to name a tab — list_sheet_tabs gives the names) and `values` as an array of row arrays; an anchor cell like "B2" is fine and the block is written down and right from it. Writing into EMPTY cells goes straight through. Writing OVER cells that already hold values is REFUSED first, naming exactly how many filled cells would be overwritten — show the user that, get a yes, then call again with confirm:true. The result is READ BACK from the sheet, so what you report is what the sheet now holds rather than what Google accepted.

ParameterTypeDescription
spreadsheetIdstringGoogle spreadsheet id; use this or sheetUrl
sheetUrlstringGoogle Sheets link, instead of spreadsheetId
rangestringA1 range or anchor cell, e.g. "B2:C5", "B2", or "Q3 Report!B2" (default A1)
valuesstring | number | boolean[][]array of row arrays to write
updatesobject[]write SEVERAL disjoint ranges in one call, instead of range+values
valueInputOption"USER_ENTERED" | "RAW"USER_ENTERED (default) parses formulas, dates and numbers the way typing them would; RAW stores every value as literal text
confirmbooleanrequired only when the target range already holds values

clear_sheet_range#

Clear a range in a Google Sheet destructive

Empty a range of cells in a Google Sheet, leaving the rows themselves in place. DESTRUCTIVE: call it WITHOUT confirm first and nothing is cleared — you get back the real number of filled cells in that exact range. Show the user that number, get an unambiguous yes, then call again with confirm:true AND confirmCells set to it. The echo is not ceremony: it is what catches naming A1:Z1000 when you meant A1:Z10, which is the mistake that actually happens. There is deliberately NO default range. The clear is read back and reported as confirmed only if the range really is empty afterwards. To remove a whole tab instead, use manage_sheet_tabs.

ParameterTypeDescription
spreadsheetIdstringGoogle spreadsheet id; use this or sheetUrl
sheetUrlstringGoogle Sheets link, instead of spreadsheetId
rangerequiredstringthe range to clear, e.g. "A2:D50" or "Sheet1!A2:D50"
confirmbooleantrue clears the range; call without it first to get the filled-cell count
confirmCellsnumberecho back the filled-cell count the unconfirmed call reported

manage_sheet_tabs#

Add, rename or delete a sheet tab destructive

Add, rename or delete a tab in a Google Spreadsheet. action:"add" + title · action:"rename" + tab + newTitle · action:"delete" + tab. Name the tab by its TITLE or its numeric sheetId (list_sheet_tabs gives both); an unknown tab is refused with the real list rather than a Google error nobody can map back. DELETING a tab destroys everything on it: call it without confirm first to get the filled-cell count, then confirm:true + confirmCells. Google does not allow removing the LAST remaining tab in a file, and that is refused by name with the way out (clear it, or delete the whole file with delete_drive_file). Every action is read back from the spreadsheet before it is reported as done.

ParameterTypeDescription
spreadsheetIdstringGoogle spreadsheet id; use this or sheetUrl
sheetUrlstringGoogle Sheets link, instead of spreadsheetId
actionrequired"add" | "rename" | "delete"add, rename or delete a tab
tabstringwhich tab — its title or numeric sheetId (rename / delete)
titlestringthe name for the new tab (action:"add")
newTitlestringwhat to rename the tab to (action:"rename")
confirmbooleantrue deletes a tab that holds data; needs confirmCells
confirmCellsnumberthe filled-cell count an unconfirmed delete reported

format_sheet#

Format a Google Sheet destructive

Make an exported sheet readable: bold the header row, FREEZE it so it stays visible while scrolling, and auto-size the columns so nothing is cut off. Worth calling right after create_sheet — a raw export with unsized columns and a header that scrolls away is the difference between a spreadsheet someone reads and one they close. Changes no cell VALUE, so it is never gated. The defaults do all three on the first tab; pass `tab` to pick another, freezeRows:0 to skip freezing, boldHeader:false or autoResize:false to skip those.

ParameterTypeDescription
spreadsheetIdstringGoogle spreadsheet id; use this or sheetUrl
sheetUrlstringGoogle Sheets link, instead of spreadsheetId
tabstringtab title or numeric sheetId (default: the first tab)
boldHeaderbooleanbold the header row; default true, false skips it
freezeRowsnumberhow many top rows to freeze (default 1, 0 = none)
autoResizebooleanauto-size columns to fit their content; default true, false skips it

update_doc#

Edit a Google Doc in place destructive

EDIT a Google Doc — the correction append_to_doc cannot make. Two shapes: `replacements:[{find, replace}]` rewrites specific text wherever it appears (call read_doc first and match the text EXACTLY; matchCase:false ignores case), or `rewrite:"…"` replaces the ENTIRE body (rewrite:"" empties it), or `dropdowns:[{title, value}]` sets a dropdown chip (e.g. Status -> Approved — read_doc lists every chip with its options; pass dropdownId when two share a title; an unknown title or option is refused with the real list and nothing changes); the same entry with options:[…] (the COMPLETE new list, 2–50) and/or newTitle changes the dropdown itself for every chip built from it, and an option you drop that a chip shows needs replace:{"Old":"New"}. Find/replace runs immediately and REPORTS how many occurrences changed — zero matches is reported as a FAILURE to match, never as a quiet success, because a text edit that silently does nothing is worse than one that visibly fails. A whole-body rewrite is destructive: call it without confirm first to get the character count, then confirm:true + confirmCells. Both are index-free by design — an agent cannot reliably compute Google’s character offsets, and a wrong offset deletes the wrong sentence.

ParameterTypeDescription
documentIdstringthe document id (from create_doc, or list_drive_files for one the user picked)
docUrlstringa Google Docs URL — the id is extracted from it
replacementsobject[]find/replace pairs, applied in order
rewritestringreplace the WHOLE body with this text ("" empties the doc)
confirmbooleantrue runs a whole-body rewrite after the character count is shown
confirmCellsnumberecho back the character count the unconfirmed call reported (rewrite only)
dropdownsobject[]dropdown chips to set, or dropdowns to change

Microsoft OneDrive: full CRUD over the user's OneDrive

save_to_onedrive#

Save file(s) to OneDrive

Save a Hermoso render — or ANY file — into the user’s connected Microsoft OneDrive. Pass a Hermoso render URL as url (or urls[] for several); for a local/external file, call upload_file first and pass the url it returns. Optional folder (created if new) + name. Returns the OneDrive file(s) with a webViewLink. Needs OneDrive connected (Settings > Connectors > OneDrive).

ParameterTypeDescription
urlstringa single Hermoso render URL to save
urlsstring[]several render URLs (up to 20) to save in one call
folderstringOneDrive folder name to save into (created if new)
namestringfile name (single save)

list_onedrive_files#

List OneDrive files read-only

List files & folders in the user’s OneDrive — the root by default, a folder’s contents (folderId), or a name search (query). onlyFolders:true lists folders only. Paginate with pageToken (the cursor from a previous call). Read-only.

ParameterTypeDescription
querystringsearch — only items whose name matches this
folderIdstringlist the contents of this folder id
onlyFoldersbooleanlist folders only
pageSizenumberrows per page (1–200, default 50)
pageTokenstringcursor from a previous call

get_onedrive_file#

Get a OneDrive file’s details read-only

Fetch one OneDrive item’s metadata — name, type, size, modified time, a webViewLink to open it and a webContentLink to download it. Pass fileId (from list_onedrive_files). Read-only.

ParameterTypeDescription
fileIdrequiredstringthe OneDrive item id (from list_onedrive_files)

update_onedrive_file#

Rename / move a OneDrive file destructive

Update a OneDrive item: rename (name) and/or move it into a folder (moveToFolderId). Pass fileId (from list_onedrive_files). To remove an item, use delete_onedrive_file.

ParameterTypeDescription
fileIdrequiredstringthe OneDrive item id
namestringnew name
moveToFolderIdstringfolder id to move the item into (from create_onedrive_folder / list_onedrive_files)

delete_onedrive_file#

Delete a OneDrive file destructive

Delete a OneDrive item — it moves to the OneDrive recycle bin (recoverable there). Pass fileId (from list_onedrive_files) + confirm:true. Confirm the exact file with the user first.

ParameterTypeDescription
fileIdrequiredstringthe OneDrive item id
confirmbooleanREQUIRED true

share_onedrive_file#

Share a OneDrive file as a link destructive

Create a SHARING LINK to a OneDrive file or folder (fileId from list_onedrive_files): type view (read-only, default), edit, or embed (an <iframe> link, personal OneDrive only); scope anonymous (anyone with the link, default), organization (work or school OneDrive only) or users (only people you invite); optional expiresAt (date or ISO) and password (on a personal OneDrive both need a Microsoft 365 subscription; the refusal says so). An ANONYMOUS EDIT link lets anyone holding it change or delete the file, so it needs confirm:true after you show the user that; every other link is created straight away. If Hermoso already made the same kind of link, OneDrive returns that one and the reply says it was reused. Read back from the item's permission list. 0 credits. Needs OneDrive connected.

ParameterTypeDescription
fileIdrequiredstringOneDrive file or folder id from list_onedrive_files
type"view" | "edit" | "embed"view (default), edit, or embed (personal OneDrive only)
scope"anonymous" | "organization" | "users"anonymous (default, anyone with the link), organization (work or school), or users (invited people only)
expiresAtstringe.g. 2026-11-30 or 2026-11-30T17:00:00Z
passwordstringpersonal OneDrive with Microsoft 365
confirmbooleanrequired for an anonymous edit link

onedrive_file_permissions#

Who can open a OneDrive file destructive

action list (default): every sharing link and person with access to a OneDrive file or folder: link URL, view or edit, scope, expiry, password, whether it is inherited from a parent folder. action remove: revoke one (permissionId from the list); anyone relying on it loses access at once and the link cannot be restored, so WITHOUT confirm:true nothing is removed and you get what would go. An inherited permission is removed on the parent folder, and the owner's own access cannot be removed. Removal is verified by reading the list back. 0 credits. Needs OneDrive connected.

ParameterTypeDescription
fileIdrequiredstringOneDrive file or folder id
action"list" | "remove"list (default) or remove
permissionIdstringfor remove
confirmbooleanrequired true for remove

convert_onedrive_file#

Convert a OneDrive file to PDF or JPG

Turn a file already in the user’s OneDrive into a PDF or a JPG — Microsoft does the conversion on its own servers, so nothing is re-encoded here and nothing is lost in a screenshot. It reads about 130 source formats, which is the point: PowerPoint and Word decks, Excel, Photoshop PSD, Illustrator AI, Sketch, 3D (fbx/glb/obj), video (mp4/mov/webm), HEIC from an iPhone, and the raw camera formats (CR2, NEF, ARW, DNG) that nothing else in this product can open. Use it to turn a client’s deck into images you can actually put in an ad, to get a usable JPG out of a designer’s PSD or a photographer’s raw file, or to hand someone a PDF of a spreadsheet. CONVERTING TO JPG REQUIRES BOTH width AND height — Microsoft refuses the call without them. The result is stored at a durable Hermoso URL you can pass straight to a render or a post; Microsoft’s own conversion link expires within minutes, so do not hand that one to anyone. Needs OneDrive connected — no new permission.

ParameterTypeDescription
fileIdrequiredstringthe OneDrive item id, from list_onedrive_files
format"pdf" | "jpg"default pdf
widthnumberREQUIRED for jpg — output width in pixels
heightnumberREQUIRED for jpg — output height in pixels

create_onedrive_folder#

Create a OneDrive folder

Create a folder in the user’s OneDrive (optionally nested under parentId) to organize saved files. Returns the folder id + webViewLink. Use that id as update_onedrive_file’s moveToFolderId or as parentId for a nested folder. NOTE: save_to_onedrive’s `folder` is a NAME (find-or-created), not this id.

ParameterTypeDescription
namerequiredstringfolder name
parentIdstringparent folder id for a nested folder (default: OneDrive root)