Hermitage Fine Art β MCP
Content and auction-platform tools for office agents. Nothing to install: point an MCP client at the endpoint below.
π΄ Production β writes are live
Endpoint: https://mcp.admin.hermitagefineart.net/mcp
Tools (40)
statusreadEnvironment, database hosts, S3 buckets, row counts of the key collections, and how many documents still carry page content in the pre-segments `blocks` array rather than in `segments`. Call this first to see whether writes would hit production.
content_describereadLive field map of a collection: field names, types, which are localized and which are relations. Use it before writing so field names and shapes are right. It cannot describe page content, which is a json field: `pages`, `pages-auctions` and `sales-categories` show `segments` (what the site renders) and `blocks` (the pre-segments array, kept but never rendered) β read those with content_segments_read instead.
content_listreadList rows of a collection with optional filters. Each filter is 'field=value' (equals) or 'field~=value' (contains); filter by the field's real name β a lot's number is `number`, not `lotNumber`. Rows carry long descriptions, so ask for `fields` unless you need whole documents.
content_getreadFetch a single document. locale 'all' returns every locale side by side: a locale that is simply missing from the answer has no translation at all (the page then falls back to English), which is different from an empty string β that one blanks the public page. On a page it returns the raw content json too; `blocks` there is the pre-segments array and is not what the site renders, so read a page's content with content_segments_read.
content_global_readreadGlobals are singletons with no id (e.g. the site global holding the notice bar). 'list' shows the known slugs, 'describe' its fields, 'get' its values β with locale 'all' to see which translations exist.
content_inspectreadFull profile of one lot across both databases: lot, object, attachments, private-sales item and the auction's site pages-auctions record β the one that carries the auction page's content and meta, flagged MISSING when absent. The fastest way to ground a change before making it; to read or edit that page's content, follow up with content_segments_read.
content_segments_componentsreadThe vocabulary of page content: which components exist and, for one of them, its props β types, which are required, which are translated, which take their values from other documents. Read this before adding or filling a segment; component and prop names are not guessable.
content_segments_readreadPage content lives in `segments`. This shows the document's segments in order β component, a one-line summary and anything that fails validation β and says whether the page renders from segments or from the pre-segments `blocks` array. A document that has segments NEVER renders its blocks, so a leftover blocks list is dead weight, not content. Ask for one segment to see its stored props and which languages each translated field has.
content_object_idsreadResolve a batch of lot references to their catalogs object ids (objects have no slug, so bulk edits need the uuids). Give either several 'auction/lot' refs, or one auction slug plus lot numbers.
content_audit_sales_itemsreadFind private-sales rows whose lot is missing or whose lot has no object β those render broken on the site.
content_audit_mastersreadCheck that the canonical S3 master exists for each media row of an owner type. Legacy masters stored under their old '<id>.WxH.jpg' name read as missing here.
content_verify_attachmentsreadRe-check an owner's attachments and their S3 masters. Run it in a fresh call after an upload: a large image can land in S3 while its rows roll back.
content_mark_soldwriteSet objects.sold on the lots' objects. This is the ONE sold flag: auction, lot and private-sales pages all read it, so a piece marked sold shows as sold everywhere. Changes reach the public site only after a rebuild; say so when you finish.
content_mark_resalewriteSet or clear objects.resale on the lots' objects β the resale right levied on the piece. Changes reach the public site only after a rebuild; say so when you finish.
content_mark_temporarywriteSet or clear objects.temporary on the lots' objects β the β temporary-import status. Changes reach the public site only after a rebuild; say so when you finish.
content_mark_vatwriteSet or clear objects.vat on the lots' objects β VAT applies to the piece. Changes reach the public site only after a rebuild; say so when you finish.
content_import_soldwriteFetch an ended auction's results from Bidspirit and set objects.sold on every lot that sold. Matches the Bidspirit auction by day and name unless bidspirit_id is given; scraping takes about a minute. Changes reach the public site only after a rebuild; say so when you finish.
content_edit_textwriteWrite one localized scalar field, or a batch of them. An empty string is REFUSED: empty is not the same as absent β it blanks the public page, while a missing locale falls back to English. Use clear to empty a field deliberately. Only text fields: page content is json, and writing a string into it would leave the page unable to read its own content β use content_segments_set. Changes reach the public site only after a rebuild; say so when you finish.
content_global_setwriteWrite a field of a global (singleton). The site-wide notice bar is one of these: it is the `notice` field of the `site` global, not a document you can look up β that is where to put an announcement and where to remove one. A localized field REQUIRES a locale; without one Payload writes English under every language. Taking a notice down means clearing it in ALL FOUR locales. Changes reach the public site only after a rebuild; say so when you finish.
content_createwriteCreate a row from a JSON object. Creating a catalogs auction also creates the site pages-auctions record it needs β without that record the auction's lots do not render. Changes reach the public site only after a rebuild; say so when you finish.
content_updatewriteUpdate a row from a JSON object of changed fields. Localized fields need a locale. Page content (`segments`) is not edited this way β use content_segments_set and content_segments_edit, which keep segment ids and check the result; a whole-array rewrite here is refused when it would break a segment. Changes reach the public site only after a rebuild; say so when you finish.
content_deletewriteDelete one or many rows. Nothing cascades: the plan lists rows that point at the deleted one (an auction's lots, its site page) and they are left behind β delete them too if that is what you mean. Deleting an owner collection (objects, auctions, pagesβ¦) on production is gated behind confirm. Deleting an attachment removes the join row only β the S3 bytes are content-addressed and may be shared. Changes reach the public site only after a rebuild; say so when you finish.
content_clone_productwriteCopy a lot's object, its attachments (same content-addressed media, no re-upload), the lot itself, and optionally a private-sales item. Changes reach the public site only after a rebuild; say so when you finish.
content_segments_editwriteStructural edits to a page's content: add a segment (from the components in content_segments_components), remove one, move it, or switch it off without deleting it. A new segment starts empty, so fill it with content_segments_set before it can render β an incomplete segment is skipped at build time and its block simply does not appear on the page. Changes reach the public site only after a rebuild; say so when you finish.
content_segments_setwriteWrite one value inside a segment, addressed by the dotted path of the prop ("title", "paragraphs.0.text", "slides.1.image_wide"); row-add and row-rm grow and shrink a list first. A translated prop is stored per language, so locale picks which one you are writing β and clearing a value removes that language rather than blanking it, which is what makes the fallback to English work. A write that would leave the segment unrenderable is refused, with the reason. Changes reach the public site only after a rebuild; say so when you finish.
content_customize_category_blockwriteThe pre-segments way to give one private-sales category its own opening text: clone the shared private-sales/root block to private-sales/<category> and repoint that category, leaving the root text untouched. It only applies to a category that still renders from blocks β a converted one opens with the private-sales-intro segment, whose text lives in the component, and the tool refuses with the segment commands to use instead. Changes reach the public site only after a rebuild; say so when you finish.
content_ensure_auction_pagewriteEvery auction needs a site pages-auctions record keyed by its id, or its lots do not render on the built site. The record is created with the auction-legal segment, which is what carries the temporary-import, resale and VAT notes. Idempotent: it does nothing when the record exists. Changes reach the public site only after a rebuild; say so when you finish.
content_sales_itemwriteAdd a lot to a private-sales category, or move an item to the top. Private-sales items have no sort field β they are ordered newest first, so "pin" recreates the row. Changes reach the public site only after a rebuild; say so when you finish.
content_set_platformswriteFetch upcoming auction links from the external platforms (about a minute of scraping), keep those whose date matches the auction, and merge them into auctions.platforms by host β links on other hosts are kept. The buyer's premium per platform comes from PLATFORMS_FEE_*; a real run refuses when a matched platform has no fee configured. Changes reach the public site only after a rebuild; say so when you finish.
content_highlightwriteThe "auction highlight" cards (image, title, realized price) shown on /auctions-highlights/. Add fills title, lot number and the first gallery image itself β you supply the price. Order is create order, newest first: the position field is never read. Changes reach the public site only after a rebuild; say so when you finish.
content_uploadwriteAttach images (or PDFs and office files) to a record. When the file sits on the person's own computer or phone, get an upload_token from content_upload_link first β a file attached to this conversation cannot be passed to a tool. Images go through the convert service and end up as a jpeg master. Re-running is idempotent, which is how a flaky large upload is healed β always verify afterwards with content_verify_attachments in a separate call. gallery is the ordered role: without sort the files are numbered 0,1,2β¦ in the order given, and the piece's main image is simply gallery sort 0 β there is no separate cover role. Changes reach the public site only after a rebuild.
content_catalog_pdfwriteCompress a catalog PDF, upload it under files/auctions/<slug>/<name>.pdf, point the auction's field at it and attach the same file to the auction. When the PDF is on the person's own machine, get an upload_token from content_upload_link first β a file attached to this conversation cannot be passed to a tool. The target bucket is whatever S3_CDN_BUCKET names for this environment β the public one in production, the local store in development β and it is a DIFFERENT bucket from image masters. Changes reach the public site only after a rebuild.
content_s3writeList, copy, move or delete objects in the buckets. Keys are sharded by the media id: objects/aa/bb/cc/<id>.jpg β pass a bare id to ls and it is expanded for you. Deleting bytes is not undoable and a master may be shared by several records (keys are content hashes) β list first.
content_onedrive_lsreadList a OneDrive/SharePoint folder (read-only, via Microsoft Graph). Use it to find the path to feed content_upload or content_catalog_pdf. Lot photos live under 'PHOTO BY LOT NUMBER/<AUCTION>' and are named <lotNumber>_<index>.
content_upload_linkUse this when the file is on the person's own computer or phone β which is the usual case, and the only way to get it here. A file attached to this conversation CANNOT be passed to a tool: ask for nothing, just hand over the link this returns. The link opens a page where they drop the file; it carries the destination, so they cannot send it to the wrong place. Print the address in your own reply (not only in the tool result, which some clients hide), then call content_upload or content_catalog_pdf with the token β that call waits for the file and shows you the plan.
platforms_fetch_upcomingreadLinks to our upcoming (non-live) auctions on Bidspirit, Invaluable, Drouot, the-saleroom and Interencheres, with their dates normalised. Feed these to content_set_platforms. Drives a headless browser, so expect it to take about a minute.
platforms_list_resultsreadList the ended auctions in the Bidspirit admin β the ids feed platforms_fetch_results and content_import_sold. Drives a headless browser, so expect it to take about a minute.
platforms_fetch_resultsreadSold lots with their hammer prices for one Bidspirit auction. Unsold lots are omitted, and lot numbers keep their suffix. Drives a headless browser, so expect it to take about a minute.
platforms_compare_pricesreadCompare per-lot estimates between our site and the other platforms, flagging the lots that differ. The hermitagefineart URL is the canonical source and must be included. Drives a headless browser, so expect it to take about a minute.
platforms_compare_inforeadCompare titles, prices and images per lot between our site and the other platforms, reporting the mismatches. The hermitagefineart URL is the canonical source and must be included. Drives a headless browser, so expect it to take about a minute.