Tools reference
40 tools the shop MCP server exposes. Generated from the live server registration.
Meta & GraphQL4
get_contextReport the resolved operating context: GraphQL endpoint, organization_id, store_id, store slug/name, the theme_id you are editing, WHETHER THAT THEME IS THE ONE THE STOREFRONT SERVES, and commerce_enabled. High-level tools auto-fill these; use this to learn the values for raw GraphQL.
graphql_mutationRun a raw GraphQL MUTATION against the store. LAST-RESORT escape hatch ONLY for writes with NO dedicated tool. For pages use create_page/update_page/update_page_sections/publish_page; theme files use upsert_theme_file; content use create_content_type/create_content_record; products use create_product; menus use create_menu; publish uses publish_draft_theme. Those apply required contracts + defaults that a raw mutation skips. Remember store/org-scoped mutations need organization_id/store_id — call get_context to fetch them.
| Argument | Type | Description |
|---|---|---|
| query* | string | A GraphQL document. Use graphql_query for queries and graphql_mutation for mutations. |
| variables | object | Variables object for the document. |
graphql_queryRun a raw GraphQL QUERY against the store. Escape hatch for anything not covered by a high-level tool. The API key's org scopes apply. Returns the `data` object.
| Argument | Type | Description |
|---|---|---|
| query* | string | A GraphQL document. Use graphql_query for queries and graphql_mutation for mutations. |
| variables | object | Variables object for the document. |
introspect_schemaDiscover the GraphQL schema. With type_name, returns that type's fields and their argument/field types (use 'Query' or 'Mutation' to list all operations, or an input type to learn its shape). Without it, lists all type names.
| Argument | Type | Description |
|---|---|---|
| type_name | string | Inspect a single type's fields/inputs (e.g. CreateProductInput, Mutation, Query). Omit to list all type names. |
Content4
create_content_recordCreate (omit id) or update (set id) a record of a content type. Field values go in `values` keyed by field code.
| Argument | Type | Description |
|---|---|---|
| id | string | Record id — set to UPDATE an existing record; omit to CREATE. |
| slug | string | URL slug; auto-derived + de-duplicated if omitted. |
| status | string | draft (default) or published. |
| title* | string | REQUIRED — the record's display NAME: one short line of plain text (the product/service/article name, under 60 characters, no HTML, not a sentence). It is what every list, card and detail page shows as the heading, and it cannot be derived from your other values — a call without it is rejected. |
| type_code* | string | Content type code (required). |
| values | object | Field values keyed by field code, e.g. {"price":"150000","bedrooms":3}. Gallery/image fields take URLs. |
create_content_typeDefine a custom content type (e.g. houses, menu_items, projects) with typed fields. EAV-backed, no new tables. Records render on the storefront via the `content` Liquid Drop and the url_pattern router.
| Argument | Type | Description |
|---|---|---|
| code | string | Machine code (lowercase_underscore); derived from label if omitted. |
| embedded | boolean | TRUE for SUPPORTING content that renders ONLY inside sections (FAQ items, testimonials/reviews, logo strips, stats, process steps you insist on storing as data): NO public list/detail routes, no templates, no nav entry — records reach the storefront through the content Drop in your sections. Leave false for DESTINATION entities that deserve their own pages (products, projects, rooms, courses…). Decide from the brief: 'would a visitor ever open /x or /x/<slug> directly?' |
| fields* | nullarray | Field definitions (required, at least one). |
| icon | string | |
| is_form | boolean | TRUE for a form/lead-capture type (contact, booking, newsletter): submissions become the merchant's PRIVATE inbox — public reads are blocked, and NO public list/detail routes or templates are scaffolded. Any section form that fetch-POSTs to /api/storefront/forms/submit needs its type created with is_form:true or the submit returns disabled. |
| label* | string | Type display name, e.g. 'Houses' (required). |
| role | string | WHAT THIS TYPE IS FOR — declare it, do not leave it to be guessed: 'display' = public content the site lists (products, articles, projects); 'order' = THE checkout inbox, whose submissions carry the cart (create exactly ONE per store); 'contact' = contact/booking/consultation submissions; 'newsletter' = an email-only subscription list. Declaring order/contact/newsletter implies is_form. The checkout page, the duplicate-inbox cleanup and the admin all read this, so an undeclared type leaves them inferring from field names. |
| singular | string | Singular form for Liquid access, e.g. 'house'. |
| template | string | Detail template name; defaults to code. |
| url_pattern | string | Storefront route with :slug, e.g. '/properties/:slug'. Defaults to /<code>/:slug. |
list_content_recordsList records of a content type with optional search, facet filters, sort, and pagination. Filtering/search/sort run server-side over the full set, then the page is returned. Mirrors the storefront content-list (which a theme drives via ?q=/?<field>=/?sort=/?per_page= URL params). Returns { data, total (after filter), total_all, page, per_page }.
| Argument | Type | Description |
|---|---|---|
| filters | object | Facet filter: field code -> allowed values, e.g. {"category":["Fashion"],"style":["Modern","Minimal"]}. Exact (case-insensitive); array fields (multiselect/gallery) match if ANY value is present. AND across fields, OR within a field. |
| page | integer | 1-based page (default 1). |
| per_page | integer | Page size (default 20). |
| published_only | boolean | |
| search | string | Case-insensitive substring match on the title + text/richtext/url field values. |
| sort | string | Sort key: a field code, 'title', 'newest', or 'oldest'; prefix '-' for descending (e.g. '-price'). Numeric fields sort numerically. |
| type_code* | string | Content type code (required). |
list_content_typesList the org's content types and their fields.
Theme & sections14
build_sectionGenerate a customizer-editable Liquid section (body + complete {% schema %}) from a spec and write it to sections/<handle>.liquid. Always ships a preset so it shows in the 'add section' picker. After this, call set_section_settings to place it on a page template.
| Argument | Type | Description |
|---|---|---|
| overwrite | boolean | Allow overwriting an existing section file with the same handle. |
| spec* | nullarray | Section definition object: name (required), category, settings[] ({type,id,label,default,...}), blocks[] ({type,name,settings[],limit,blocks[] — blocks NEST recursively for item-within-item trees, max_blocks caps children}), presets[], and optional Liquid body. Settings use section.settings.<id>; reference the global palette via CSS vars like var(--accent) / var(--font-display). |
| theme_id | string | Theme id to write to. Defaults to the store's active theme. |
clear_storefront_cachePurge the storefront edge/Redis cache so theme/product edits show immediately. (Requires a key with settings/full-access scope.)
create_theme_previewCreate a short-lived preview token to view a theme (e.g. a draft) on the storefront without publishing.
| Argument | Type | Description |
|---|---|---|
| theme_id | string | |
| ttl_seconds | integer | Token lifetime; default 3600. |
customize_themeOpen a theme for editing — returns or lazily creates an unpublished draft clone you can safely edit before publishing.
| Argument | Type | Description |
|---|---|---|
| theme_id | string | Defaults to the store's active theme. |
get_theme_fileRead a single theme file's content by path.
| Argument | Type | Description |
|---|---|---|
| include_inherited | boolean | |
| path* | string | e.g. sections/header.liquid or templates/index.json (required). |
| theme_id | string |
list_liquid_objectsList the Liquid objects, per-template context variables, the dynamic `content` Drop, and custom filters the storefront exposes to theme sections. Use this BEFORE writing a section so you reference real variables (e.g. product.url_key, collection.products, content.<type>) instead of guessing.
list_theme_filesList theme files (path + content_type + source), optionally filtered by path prefix.
| Argument | Type | Description |
|---|---|---|
| include_inherited | boolean | Include files inherited from the parent theme. |
| path_prefix | string | Filter, e.g. 'sections/' or 'templates/'. |
| theme_id | string |
publish_draft_themePromote a draft (unpublished) theme to live (role=main).
| Argument | Type | Description |
|---|---|---|
| theme_id | string | Defaults to the store's active theme. |
restore_theme_versionRestore the theme to a snapshot taken by snapshot_theme: every file AND settings_data revert to exactly that checkpoint (files added since are deleted).
| Argument | Type | Description |
|---|---|---|
| version_id* | string | The theme_versions id returned by snapshot_theme (required). |
set_global_settingsMerge global theme palette/typography/spacing into settings_data (CSS variables). Reads current settings_data, merges the given top-level keys (never clobbering the nested `sections` map), and writes it back.
| Argument | Type | Description |
|---|---|---|
| settings* | object | settings_data keys to MERGE (others preserved), e.g. {"color_accent":"#2d4a3e","color_accent_2":"#c0532b","color_paper":"#faf6ec","font_heading":"Cormorant Garamond","font_body":"Inter","space_section":80,"radius":12}. These map to CSS vars (color_accent->--accent, color_accent_2->--accent-2 (the OPTIONAL secondary brand hue for bg-accent-2/text-accent-2), font_heading->--font-display, space_section->--section-y). |
| theme_id | string | Defaults to the store's active theme. |
set_section_settingsAdd or update a section instance on a page template (templates/<template>.json), setting its per-section settings/blocks and order. Reads the current template (inherited if the store has none), merges, and writes it back. ⚠️ CHROME sections (web-header / web-footer / announcement-bar) are LAYOUT-rendered, not template-placed: pass template:"layout" with their type and this writes the instance into the theme's settings_data.sections map — this is THE way to seed the header nav menu items (blocks: link + nested dropdown entries with real /pages/<slug> urls).
| Argument | Type | Description |
|---|---|---|
| blocks | nullarray | Block instances: [{"type":"feature","settings":{...}}]. |
| position | nullinteger | 0-based insert position in page order; appended if omitted. |
| section_id* | string | Unique instance id for the section on this page, e.g. 'hero' or 'features-1'. |
| settings | object | Per-section setting values (section.settings.*). |
| template* | string | Page template without extension: index, product, collection, page, blog, cart, etc. |
| theme_id | string | |
| type* | string | Section type = the section file handle (sections/<type>.liquid). |
snapshot_themeCapture an immutable checkpoint of the theme (every file + settings_data) into theme_versions. Returns the version id to restore later.
| Argument | Type | Description |
|---|---|---|
| label | string | Optional label shown in the version history. Default 'AI checkpoint'. |
| theme_id | string | Defaults to the store's active theme. |
update_page_sectionsAdd or update ONE section on a CMS page, INCREMENTALLY (store_pages.sections_data) — the page-record twin of set_section_settings. Reads the page's current sections, merges this one in (settings per-field: keys you don't pass are preserved; blocks replaced only when given), updates the render order, validates, and writes it back (auto-republishing a live page). Use it to build a CMS page SECTION-BY-SECTION so the user watches it fill in: create_page (empty) FIRST, then call this once per section, top to bottom — instead of dumping the whole page at once. Returns the page's storefront `path` so the preview follows to it.
| Argument | Type | Description |
|---|---|---|
| blocks | nullarray | Block instances: [{"type":"feature","settings":{...}}]. Replaces this section's blocks when given; preserved when omitted. |
| id* | string | Page id (required) — find it with list_pages. Create the page first (create_page) so it exists. |
| position | nullinteger | 0-based insert position in the page's section order; appended if omitted. |
| section_id* | string | Unique instance id for the section on this page, e.g. 'hero' or 'features-1' (required). |
| settings | object | Per-section setting values (section.settings.*). MERGED into the existing instance — settings you don't pass are preserved. |
| type* | string | Section type = the section file handle (sections/<type>.liquid). Build it first with build_section (required). |
upsert_theme_fileCreate or replace a theme file. Writes are validated against the platform design contract and REJECTED on violation: layout/theme.liquid must load assets/theme.js, render content_for_layout/content_for_header, AND carry the <style id="theme-settings-vars"> block (the customizer Theme-settings panel's canonical color_*/font_* keys only apply through it); sections/*.liquid need one complete {% schema %} whose settings include the canonical Style group (visible, bg_color, text_color, heading_color, padding_top/bottom, border_color/width/radius) and whose ids are referenced in the body; templates/*.json must be well-formed and only place existing section types. Error messages include the exact fix.
| Argument | Type | Description |
|---|---|---|
| content* | string | Full file content (required). |
| content_type | string | liquid|json|css|js|html|text. Inferred from extension if omitted. |
| path* | string | layout/|templates/|sections/|snippets/|assets/|config/|locales/ path (required). |
| theme_id | string |
Pages, blog & menus5
create_pageCreate a CMS page (default type 'custom'). store_id is auto-filled. Pass `sections` (page-builder document — THE standard for designed pages, visually editable afterwards) or `body` (prose HTML, text-only pages). Without either the page is BLANK. Publish it with publish_page.
| Argument | Type | Description |
|---|---|---|
| body | string | PROSE fallback: the page's content as HTML (page.body). Use ONLY for text-only pages (legal/privacy/terms/policies). Any DESIGNED page must pass sections instead — a prose page cannot be edited visually in the page builder. |
| meta_description | string | |
| meta_title | string | |
| page_type | string | home|product|collection|blog_index|cart|checkout|account|contact|faq|custom. Default custom. |
| sections | object | THE STANDARD for designed pages: a page-builder OBJECT {"sections":{"<id>":{"type":"<existing section type>","settings":{...},"blocks":[...]}},"order":["<id>",...]} — same shape as templates/*.json sections. Example: {"sections":{"main":{"type":"brand-hero","settings":{"heading":"Hi"}}},"order":["main"]}. The page then renders these sections AND is visually editable in the page builder. Takes precedence over body. |
| slug | string | |
| title* | string | Page title (required). |
delete_pagePERMANENTLY delete a CMS page (e.g. an accidental duplicate). Find the id with list_pages first; double-check it's the right page — this cannot be undone.
| Argument | Type | Description |
|---|---|---|
| id* | string | Page id (required) — find it with list_pages. Deletion is permanent. |
list_pagesList the store's CMS pages (id, title, slug, type, status, content mode). ALWAYS check here before create_page — creating an existing slug mints a -2 duplicate.
| Argument | Type | Description |
|---|---|---|
| status | string | Filter: draft|published. Omit for all. |
publish_pagePublish a CMS page so it's live on the storefront.
| Argument | Type | Description |
|---|---|---|
| id* | string | Page id (required). |
update_pageUpdate an existing CMS page: title/slug/meta, and its CONTENT — `sections` (page-builder document, the standard for designed pages) or `body` (prose HTML, text-only pages). Use this instead of re-creating a page.
| Argument | Type | Description |
|---|---|---|
| body | string | Replace the prose HTML body (switches the page to prose mode). Text-only pages. |
| id* | string | Page id (required) — find it with list_pages. |
| meta_description | string | |
| meta_title | string | |
| sections | object | Replace the page-builder document (switches the page to sections mode): {"sections":{"<id>":{"type":"...","settings":{...}}},"order":[...]}. |
| slug | string | |
| title | string |
Translation & i18n4
get_languagesGet the store's default language + the full set of languages the storefront serves (supported_locales). The default is served at the root URL; others at /<locale>/.
list_translationsList existing translation overrides for a language (optionally filtered by resource type). Returns rows of {resource_type, resource_id, field, value}.
| Argument | Type | Description |
|---|---|---|
| locale* | string | Language code to read overrides for, e.g. "vi". |
| resource_types | nullarray | Optional filter: theme_section | page_section | theme_setting | page | blog_post | product | collection | content_record | menu_item | eav_attribute | eav_option | brand | store | personalization_template | personalization_field | personalization_choice | sales_rule | customer_tier. Empty = all. |
set_languagesSet which languages the storefront serves (supported_locales on the store). Include the default locale. After this, translate content with upsert_translations and the storefront serves each non-default language at /<locale>/.
| Argument | Type | Description |
|---|---|---|
| locales* | nullarray | Full list of language codes the storefront serves, e.g. ["en","vi"]. MUST include the store's default locale. Empty list = single-language. Use short codes that become the URL prefix (vi → /vi/). |
upsert_translationsWrite per-language translation overrides into the content_translations overlay. The default-language record is never changed — only the given language. An empty value removes an override. The storefront serves it at /<locale>/. Enable the language first with set_languages.
| Argument | Type | Description |
|---|---|---|
| entries* | nullarray | Batch of translation overrides to write. |
Media2
search_stock_imagesSearch Pexels for real, royalty-free stock photos and return candidate image URLs. This is the DEFAULT image source for every slot — hero/section/blog/content photos. Pick the best-matching candidate URL and write it straight into the image setting; the server automatically re-hosts it into the store's media library (never hotlinked, no upload_image needed).
| Argument | Type | Description |
|---|---|---|
| orientation | string | landscape | portrait | square — match the slot (hero/banner=landscape, avatar/logo=square). Default any. |
| per_page | integer | How many candidates to return (1-20, default 8). |
| query* | string | What to search for — a concrete subject in English (e.g. 'minimalist ceramic coffee mug', 'modern green apartment building at golden hour'). One subject per call. |
upload_imageUpload an image (from a local file PATH or a remote URL) to the store's media library and return the hosted URL. Use this for ANY image — content-record galleries, section backgrounds, page OG images, blog featured/inline images — then pass the returned url into the matching field (a gallery value, a section image_picker, featured_image_url, etc.).
| Argument | Type | Description |
|---|---|---|
| alt | string | Alt text. |
| folder | string | Media folder, e.g. 'blog', 'content'. Default 'general'. |
| path | string | Local file path to upload. Use this OR url. |
| url | string | Remote image URL to fetch and re-host. Use this OR path. |
Skills2
get_skillLoad the full content of one shop skill (a build/redesign playbook) by name. Read shop-core-rules first — the other skills reference its §A–§I anchors.
| Argument | Type | Description |
|---|---|---|
| name* | string | The skill name, e.g. shop-core-rules, shop-builder, shop-content-site. Use list_skills to see all names. |
list_skillsList the available shop build/redesign skills (reusable playbooks) with a one-line description each. Call get_skill to load a full playbook before doing that kind of work.
Other5
check_linksVERIFY every internal link on ONE storefront page resolves (no 404s) — the core-rules §E acceptance check. Fetches the page, follows each internal href, returns the broken ones. Run it on EVERY page you created/changed and once on the homepage at the end; a page is NOT done while this returns broken links.
| Argument | Type | Description |
|---|---|---|
| path | string | Storefront path to check, e.g. '/' or '/pages/services'. Default '/'. |
fetch_urlFetch the TEXT content of a public http(s) URL — use this to read a design handoff (e.g. a claude.ai/design or Anthropic design-file export, an HTML/CSS file), a reference page to clone, or a JSON/Markdown spec the user links. Handles gzip-compressed responses automatically. Returns the raw body (HTML/CSS/JS/JSON/text), capped at 512KB. NOT for images: to put an image in the store, pass its URL to upload_image instead. Private/internal addresses are refused.
| Argument | Type | Description |
|---|---|---|
| url* | string | Public http(s) URL to fetch (a design HTML/CSS file, a reference page, a JSON spec). Returns the raw text. |
search_stock_videosSearch Pexels for real, royalty-free stock VIDEOS and return candidate looping-clip URLs (mp4, ~720–1080p) + a poster still. Use for a HERO / section BACKGROUND VIDEO when the design calls for a cinematic, motion-led look — NOT every store wants one. Write the returned `url` into the section's `video_url` setting and `poster` into `video_poster`; both auto re-host into the store's media library on write (never hotlinked). The hero renders it muted + autoplay + loop + playsinline with the poster as the still. For a plain still image use search_stock_images instead.
| Argument | Type | Description |
|---|---|---|
| orientation | string | landscape | portrait | square — match the slot (hero/banner=landscape, avatar/logo=square). Default any. |
| per_page | integer | How many candidates to return (1-20, default 8). |
| query* | string | What to search for — a concrete subject in English (e.g. 'minimalist ceramic coffee mug', 'modern green apartment building at golden hour'). One subject per call. |
set_commerce_enabledToggle the store between a shop (true) and a content-only website (false). Merges store.settings.commerce_enabled. (Requires a key with settings/full-access scope.)
| Argument | Type | Description |
|---|---|---|
| enabled* | boolean | true = normal shop; false = content-only site (404s ecom routes, hides ecom admin menus). |
update_store_brandingWrite the store's ADMIN-level SEO + branding (Settings ▸ Branding/SEO): meta_title, meta_description, og_image_url, logo_url, favicon_url. THIS is where the SEO pass PERSISTS store SEO — the storefront <title>/<meta description>/OG read shop.meta_title/meta_description from here (never bake SEO into the theme, and do NOT hand-write a graphql mutation — there is a real tool, this one). Call it in the SEO step from the real brand + what the store sells.
| Argument | Type | Description |
|---|---|---|
| favicon_url | string | Favicon URL (auto re-hosted). |
| logo_url | string | Brand logo URL (auto re-hosted). |
| meta_description | string | Store-level SEO meta description (~150 chars), real brand copy — not boilerplate. |
| meta_title | string | Store-level SEO <title> (~50-60 chars) — the site's default title + the homepage title. Derived from the real brand + what the store sells. |
| og_image_url | string | Open-Graph share image URL (auto re-hosted; never hotlink). |
