Browser-local WebMCP controls
The Layers dashboard also exposes browser-local WebMCP controls when you are signed in and using a browser that supportsnavigator.modelContext. These tools act on the active dashboard page through its existing UI handlers. They are separate from the remote Layers MCP server and Storefront MCP server, and do not call their endpoints.
Open the relevant conditions builder or picker in the dashboard before listing controls. The tools only expose builders and pickers that are currently mounted and visible.
For conditions builders:
- Use
layers_list_condition_buildersto find open builders, thenlayers_conditions_getto read the current query and the fields, operators, value types, and choices allowed in that builder. - Use
layers_conditions_setwith the builder id, a complete replacement query, andexpected_queryfrom the latest read. Nestedand,or, andnotconditions are supported where the builder allows them. Values must be literal; field-sourced values are not supported. - Setting conditions uses the existing UI handler and may sync the dashboard draft, but never submits or publishes it. If the builder is stale or locked, re-read it or unlock it before trying again.
- Use
layers_list_nested_comboboxesto find open pickers andlayers_combobox_get_optionsto read their choices. Option lookup supports search, group, offset, and limit; the default limit is 50 and the maximum is 100. - Use
layers_combobox_selectwith the picker id and an exact option value returned by the options tool, not its label. Disabled options are rejected. - If a picker id is stale or the picker is closed, open the relevant control and list the pickers again. Selection does not save or publish the dashboard.
Layers MCP server
The main MCP server exposes tools for managing your Layers stores. It uses OAuth authentication and requires themcp:use scope.
Connecting
The official Layers connector is available in the Claude directory. Add it from Settings > Connectors in Claude, then authorize Layers when prompted. If you are using a different MCP client, configure it with the following endpoint:store-list returns only the stores granted to the connection. Each store in store-list and store-details includes the permissions the connection was granted, so an assistant can check what it may do before calling a tool. If a tool is called for a store that wasn’t granted the permission it needs, the tool returns a permission error.
If a tool is called with a store identifier that doesn’t exist, the tool returns a not-found error with up to three near matches drawn from the connection’s accessible stores. This distinguishes a typo (fix the slug and retry) from a store that exists but wasn’t granted to the connection (ask the connection owner to grant it).
The store argument accepts a store’s UUID, slug, or primary domain (exact match), and also matches on the display name after ignoring case and punctuation, so Acme Outfitters, acme-outfitters, and acmeoutfitters all resolve to the same store. When a name matches more than one accessible store, the tool returns a 422 that names the conflicting slugs so the caller can retry with an exact identifier.
Granting access to future stores
By default, a connection only covers the stores you select on the authorization screen. Turn on Include future stores under the store picker to automatically grant the connection access to stores you gain access to after consenting. Use it for a personal assistant connection you want to keep in sync with your account instead of re-authorizing every time you’re added to a new store. When the switch is on, pick a permission preset for future stores:
Behavior to know:
- “Future” means stores you gain access to after consenting. Stores you could already access but left unselected stay excluded and are never granted automatically.
- Grants still never exceed your own access. When you gain a new store, the connection receives the preset’s permissions intersected with the permissions you actually hold on that store.
- New grants take effect on the connection’s next MCP request and appear in the store’s App Connections table like any other grant.
- Re-authorizing the same app replaces the future-store setting along with the store grants. The most recent consent wins.
- Revoking the connection for a store permanently excludes that store. Layers won’t re-grant it automatically, even if you still have access.
Available tools
Most resources use a*-manage tool for actions such as list, create, update, and delete. Some resources use separate list and collaborative editing tools instead.
Store
Store
Customers
Customers
Catalog
Catalog
Diagnostics
Diagnostics
Search
Search
Attributes
Attributes
Search tuning
Search tuning
Merchandising
Merchandising
Sort orders
Sort orders
Collaborative editor
Collaborative editor
Products
Products
Analytics (LayersQL)
Analytics (LayersQL)
Knowledge
Knowledge
Documentation
Documentation
Feedback
Feedback
Diagnosing collection and search overlap
collection-overlap is available on the admin Layers MCP server, not the Storefront MCP server. It summarizes page-one searches from the trailing 7-day window whose query text names a collection. Each row pairs a query and collection with a relation: exact means their names match, collection_broader means the collection name includes extra terms, and query_narrower means the query includes extra terms.
Pass store as a required store slug or domain. Filter results with relation, linked, min_searches, or max_members_served_share (a fraction from 0 to 1). page defaults to 1. per_page defaults to 15 and accepts up to 100 results. The response includes total matching rows and total_pages.
The tool orders rows by estimated coverage left on the table, calculated as searches multiplied by eligible collection members that search results did not serve. It then sorts by search count descending and query ascending. Each row includes search and collection counts such as searches, eligible_members, members_served, results_served, and results_in_collection, along with the corresponding shares.
median_result_count and max_result_count report the median and maximum total results returned per search. min_members_missing_per_search gives a lower bound on how many eligible collection members each search left out, based on the largest result count. It does not identify the exact missing members.
Collection labels come from a daily crawl of the storefront header navigation. The crawl excludes footer links and /collections/all, and runs again after collection data finishes syncing during onboarding.
The tool requires an authenticated admin MCP connection and admin access. It has no tool-specific request rate limit. Calls without admin access return HTTP 403:
Submitting feedback about MCP tooling
Admin MCP connections can callmcp-feedback to report friction with the MCP itself. Use it when an assistant hits a rough edge you want the platform to fix. Examples include a missing capability, a schema field that isn’t exposed, an action that takes too many calls, or a tool description that led an agent astray.
The tool accepts a short set of fields:
Example call:
delivered is false when feedback routing isn’t configured for the environment. The submission is still recorded.
Usage pattern
1
List your stores
Call
store-list to see all stores you have access to. Note the store slug for each store you want to work with.2
Pass the store slug
Include the store slug in all subsequent tool calls. For example, if your store is
my-store.myshopify.com, the slug is my-store.3
Use manage tools to make changes
Tools ending in
-manage accept an action parameter, commonly list, create, update, or delete, plus tool-specific actions such as toggle_status or bulk actions like bulk_publish. Read-only actions like list are safe to call freely.Write payload shapes
*-manage tools declare their writable fields inside a nested data object, but they accept the same fields at the top level of the arguments. Both of these calls apply the same update:
- Arguments the tool doesn’t recognize return a validation error that names each unsupported argument and lists the fields the tool accepts. A misspelled field can’t be dropped silently.
- A
createorupdatecall whose payload resolves to nothing returns a validation error rather than reportingsuccess: truewith an unchanged record. - Invalid field values return a readable
Validation failed: ...error naming the field.
success: false with the validation message.
Smaller MCP responses
List actions on updated manage tools acceptfields to keep only selected keys on each item. Identity and structure keys such as id, code, and children remain in the response. Omit fields to return the full item. If you request a key that an item does not contain, the response identifies it in unknown_fields.
Mutation actions return a compact confirmation with success, action, an identifier such as id, changed, and an optional message. Toggle and status actions also include the resulting state. Pass verbose: true or include=resource to include the full stored record in the response.
Discovering targetable fields
store-dimensions is the source of truth for what a store’s contextual conditions can target. It returns two lists in one response, both scoped to the store you pass:
dimensions— every dimension Layers records for the store, withsource(built_in,analytics, orcustom),value_type,coverage_percentage,unique_values, andlast_seen_at. These are the codes accepted afterSEGMENT BYin LayersQL.contextual_fields— thecontext.*field names conditions accept inblocks-manage,request-transforms-manage, sort orders, product sequences, and merchandising rules edited through the collaborative editor. Each entry carries alabel,group,type, allowedoperators, and the same coverage stats. Store-specific labels from the Dimensions page flow through aslabelanddescription.
search (matches name, label, or description) or group (for example, Geography, Marketing, Custom), and paginate with page and per_page. Pass dimension to fetch the values observed for a single dimension or field instead of the listing; the tool returns up to values_limit samples (default 25, max 100) drawn from real traffic.
custom on the contextual payload appear here automatically once Layers has seen them in traffic. There is no registration step. See Custom context fields for the discovery rules.
layersql-schema accepts the same store argument. When present, each dimension in the response gains a store block with the matching store dimension code, its coverage stats, and the context.* field name conditions can target. Use it to move from an analytics query to a targeting condition without a second lookup.
Write validation
Every write tool that accepts a conditions payload validates leaves against the same registry. Layers rejects any condition that names an unknown field, an unknown operator, or an operator that doesn’t fit the field’s type. The error includes the nearest valid field name and points back tostore-dimensions:
tools/list, so calling store-dimensions for the target store is the reliable way to see the current vocabulary before a write.
Managing query dimensions
Usequery-dimensions-manage to label queries with values from a product attribute and refine their rules. Read actions require ranking-rules.view; mutations require ranking-rules.edit.
listlists definitions.getrequirescodeand returns the available labels, keyword rules, check status, agreement, grouped top-search preview, and saved corrections.createtakesdatawithcode,name,attribute_code, andinstructions; it can also takeincluded_values. An attribute may have more than 150 distinct values, but a dimension can include at most 150 selected labels. Omitincluded_valuesto include all attribute values.updatetakescodeanddata; the code is immutable. An omittedincluded_valuesretains the current selection unlessattribute_codechanges, in which case the selection resets to all values.- Creating a dimension or changing its instructions, attribute, or included values starts background rule generation and checking. A name-only update does not. Use
getto follow progress. Rechecking compares rules without replacing corrections. update_rulestakescodeand the completeruleslist, replacing the entire list, including corrections. Preserve everysource: "correction"entry when sending an update, or those corrections will be lost. Each rule hasmatch,kind(phraseorword_pattern),labels, anddefer. Corrections usekind: "phrase"with the exact search words and must not defer. Empty labels explicitly mean no signal. Inspectdroppedin the response for rejected rules and their reasons. Valid rules save and are checked without regeneration.recheckcompares current rules again. Setregenerate: trueto regenerate generated and manually edited rules; this replaces those rules but preserves corrections. A normal recheck does not overwrite corrections.deleterequirescodeand is blocked while a ranking rule references the dimension, including unpublished rules.
request.query_dimension.<code>. A missing verdict does not count as an empty label or satisfy a no-signal condition. For a boost or bury action using the query’s labels, set filter.value_source to query_dimension, filter.value to the dimension code, filter.operator to in, and filter.property to that dimension’s attribute_code. Empty or unresolved labels skip that action. Use the collaborative editor to edit an existing ranking rule.
See query dimension setup and previews for the merchant workflow.
Managing store settings
Usestore-settings-manage for operational settings, and store-search-configuration for search behavior, prompts, and ranking weights. Both require the connection’s store.configure permission.
getreturns all sections by default. Passsectionsto request onlysync_settings,preferences,sales_channel, ormarkets.updateacceptsdatakeyed by those section names. Only supplied fields change; omitted fields keep their saved values. Read the current settings before making a change and check the returned sections afterward.sync_settingsmanages crawler signature headers. Their values are write-only: reads report whether the headers are set, never their secret contents. Enabling signatures requires both headers, which can already be saved.preferencescontrols Shopify resource syncing and inventory location scope. Sync overrides accepttrueto force on,falseto force off, ornullfor auto-detection. Reads include detection state and available inventory locations. Missing Shopify permissions can prevent a sync preference from being changed.sales_channelselects the Shopify channel treated as the app storefront. Read this section to discover available channels before selecting one.marketsselectsstrictfor market catalog eligibility and localized pricing,pricing_onlyfor localized pricing without catalog restrictions, oroffto ignore markets. Reads include active markets.
Managing banner types
Usebanner-types-manage to manage reusable banner definitions. This is separate from placing a banner in a merchandising rule: edit those placements through set_presence and apply_patch on /banners.
- Call
taxonomyto discover the supported field types, list support, and validation options. - Use
listorgetto inspect existing types.get,update, anddeleterequirebanner_type_id. - To
createa type, providedata.name,data.allowed_modes, anddata.field_schema. Placement modes areinjectfor banners between products andovertakefor replacing the grid. The name determines a permanent slug. - To
updatea type, send only the fields you want to change. If you sendfield_schema, it replaces the entire schema, not just individual fields.
Example: edit a merchandising rule
Ask your AI assistant:“Pin the product ‘Classic White Tee’ to position 1 in the Summer Sale collection, and boost all products where brand is ‘Nike’ using a soft boost expression.”The assistant uses
merchandising-rules-manage to find an existing rule, then calls set_presence and apply_patch to edit its draft. To create a rule, use the tool’s create action. Newly created merchandising rules start disabled and do not affect live results until published.
Bulk actions
blocks-manage can duplicate one block with action: "duplicate" and block_id. The response includes the source block_id, the new duplicated_id, a message, and next_steps for continuing with the draft.
blocks-manage—bulk_publish,bulk_unpublish,bulk_duplicate,bulk_delete(passblock_ids)
bulk_duplicate creates one copy for each entry in block_ids, in input order; repeating an id creates another copy. Unknown ids are returned in not_found_ids. Use bulk actions to update many blocks at once, such as unpublishing a batch of drafts after a seasonal campaign or deleting duplicate blocks.
affected_count so the assistant can confirm how many records changed.
Collaborative editor
Assistants edit merchandising rules, sort orders, recommendation blocks, facet values, ranking rules, and audiences through a collaborative editing flow instead of direct writes. An assistant announces presence on a resource, reads the current shared document and its revision, then applies small RFC 6902 JSON Patch operations. This lets multiple humans and agents work on the same resource without overwriting each other. It also powers the same real-time collaboration experience that shows other editors in the dashboard. When an agent callsset_presence or apply_patch, humans on the same page see the agent live in the dashboard. The agent gets its own presence avatar with a distinct color, and its focused field or selected rows are tinted and locked like any other collaborator’s. On the facet-values editor, a compact agent activity popover also surfaces the intent and message your agent supplies.
Provide a short, human-readable activity.intent and activity.message on set_presence, and a concise metadata.intent on apply_patch. This lets a human co-editor tell at a glance what your agent is doing.
Use the collaborative editor tools when your assistant needs to change:
- Merchandising rule fields, pins, or banners
- Sort order fields (referenced by id or handle)
- Recommendation block fields (referenced by block id)
- Facet value sorting, grouping, and hidden values (referenced by attribute id or code)
- Ranking rule fields, including targeting, actions, visual pins, and enabled status (referenced by rule id)
- Audience names, conditions, and optional SegmentQL source (referenced by audience id)
resource_type values are merchandising_rule, sort_order, block, facet_values, ranking_rule, and audience.
Use merchandising-rules-manage and sort-orders-manage to list or create those resources. Use blocks-manage with action: "list" or blocks-catalog, facet-values-manage with action: "list", ranking-rules-manage with action: "list", and audiences-manage with action: "list" or action: "get" to inspect other resources.
Use the collaborative editor to change existing merchandising rules, sort orders, blocks, or facet values.
ranking-rules-manage supports creating and deleting ranking rules; edit existing rules through the shared editor rather than direct update or toggle_status calls. New merchandising and ranking rules start disabled. Publishing a new draft turns it on when both its saved and draft states are off; if you explicitly turn an already-live resource off in the draft, publishing keeps it off. Newly created blocks remain drafts until published. A new sort order is not added to the storefront’s available sort menu, but it can still affect a request when a collection, rule, or block explicitly references it.next_steps: call set_presence with the indicated resource type and id, use validate_document and apply_patch if you need to edit its content, then call request_publish and check the result with check_publish_request.
The admin tool sort-orders-manage does not replace the storefront sort-orders-list tool, which remains available to list sort orders for storefront integrations.
Managing audiences
Useaudiences-manage to discover and create saved audiences. Reads require merchandising-rules.view; creation, deletion, and publishing edits require merchandising-rules.edit. Your MCP connection must have access to the store.
- Discover:
listsupports name search and pagination.gettakesaudience_idand returns the audience and its references, so you can check where a change will apply. - Choose fields:
attributeslists supported condition fields, operators, and SegmentQL codes. Usestore-dimensionsfor store-specific custom context fields. - Create: Pass
data.nameanddata.conditions. Names are unique within the store, ignoring case. An audience cannot reference another audience. - Estimate: Pass
audience_idfor a saved audience, ordata.conditionsfor a proposed definition. Estimates use recent recorded traffic and report conditions they cannot measure; they are not forecasts. See traffic estimate limitations. - Edit: There is no direct
updateaction. Callset_presencewithresource_type: "audience"and the audience id asresource_id, then validate and patch/fields/name,/fields/conditions, or/fields/segmentql. Finish withrequest_publishandcheck_publish_request. - Delete: Pass
audience_id. Deletion is refused while rules reference the audience, a person has it open, or a publish review is pending. Remove references or settle the review first; a refused deletion leaves the audience unchanged.
conditions is the authoritative audience definition. The optional segmentql text is retained for display, not compiled by audiences-manage or the shared-editor publish path. Do not patch only the query text and expect targeting to change. When changing conditions without matching source text, clear /fields/segmentql to null so the editor opens the builder instead of a stale query.
Audience drafts do not affect live targeting until saved. Approval or immediate publishing saves the definition used by every referencing rule; audiences do not have a separate enabled toggle. Audience publish responses use config_version_id: null.
Editing flow
The safe change-and-review sequence isset_presence -> validate_document -> apply_patch -> request_publish -> check_publish_request.
1
Announce presence and read the document
Call
set_presence with the store, resource_type, and resource_id. If you do not pass a presence_id, the tool creates an active session or reuses your existing one for that store and resource. The response includes the presence_id, current document, revision, active_editors, and an expires_at timestamp.2
Plan and (optionally) validate patches
Build small RFC 6902 patches against the public roots
/fields, /pins, and /banners. Prefer granular list operations like add /pins/-, replace /pins/5, remove /pins/3, and move over replacing the entire /pins or /banners collection. Call validate_document first when it would reduce risk, for example before a large or unusual patch.3
Apply the patch
Call
apply_patch with the same presence_id, the observed revision, and the RFC 6902 patch list. Patches are applied atomically: if any operation fails, no changes are committed and the revision is unchanged. On success, the response returns the new revision and document.4
Refresh presence and retry on conflict
Presence expires at
expires_at unless refreshed. Calling set_presence again with the same presence_id refreshes it; calling without an id reuses your active session for the same store and resource. Successful apply_patch calls also refresh presence. Use release: true to end the session when you are done. If a patch fails with a stale revision or a failed test operation, refresh presence to re-read the document and re-plan.set_presence
Declares an agent’s activity state and returns the shared document. Supported activity_state values are viewing, editing, thinking, and validating. An agent has one active presence per store and resource: calling without presence_id reuses that session and updates its activity state and expiry. Supply release: true with the presence_id or the resource locator to release it; activity_state is not required for a release. A successful release returns released: true; releasing an already missing or expired session is idempotent and returns released: false.
resource_id when resource_type is sort_order. Keep the returned presence_id for later editor calls, or pass it to set_presence to refresh or release the session.
validate_document
Validates the current document or a proposed set of patches without applying changes. Whole-collection replacements return warnings so agents prefer granular list operations. An active presence_id can identify the resource without resource_type and resource_id; if you pass both forms, they must identify the same resource.
apply_patch
Applies an atomic RFC 6902 patch. Requires an active presence_id from set_presence and the latest observed revision. Supported operations are add, remove, replace, move, copy, and test. Patch paths must be under /fields, /pins, or /banners.
Readable pin positions
set_presence, apply_patch, and validate_document responses include pin_positions alongside the shared document. Use this read-only summary to describe pin order without treating the document’s raw position values as shopper-facing slot numbers.
For example, a sequential pin with a raw ordering value of
2048 might be second in the sequence, not result 2048. A pin fixed at absolute position 10 reports that value separately and does not count toward sequential numbering. Use the returned path to patch the correct item, and refresh it after edits that change the array. Do not patch pin_positions itself.
Pin consistency
Each pin must be internally consistent. A pin withpin_type: "variant" requires a non-null pinned_variant_id. Any other pin type requires a null pinned_variant_id. If you omit pin_type, it defaults to product. apply_patch rejects any patch that leaves a pin inconsistent and doesn’t change the document. validate_document reports the same problem without writing.
To change a pin’s type, set both fields in the same patch. You can also remove the pin and add /pins/- a new, consistent one. apply_patch rejects a lone replace /pins/0/pin_type that leaves pinned_variant_id unchanged.
test before replace to catch concurrent edits:
Explaining edits with metadata.notes
metadata accepts an optional notes object that maps an exact patch path in the same call to a one-line reason for the change. Notes appear in the dashboard’s agent activity feed as the caption for that step, so a human co-editor can see why the agent made each change.
notes:
- Each key must match a
pathpresent in the samepatcheslist. Notes for unknown paths are dropped. - Values must be non-empty strings. Non-strings and empties are dropped.
- Notes are trimmed and capped at 240 characters.
- Write a short reason (why this helps the shopper), not a restatement of the operation.
notes is optional. Patches sent without notes apply the same way.
Error handling
apply_patch returns deterministic errors so agents can recover automatically:
Requesting publish approval
apply_patch only updates the shared draft. To save a change to the live store, use request_publish for any supported resource: merchandising rules, sort orders, recommendation blocks, facet values, ranking rules, or audiences. Human review is the default. For a new draft, the reviewer must explicitly choose Approve & save to activate it. A regular editor save can also settle a pending request as published, but it preserves the submitted live/enabled state, so a published status alone does not guarantee that the resource is enabled.
After requesting review, poll check_publish_request until the request settles. Do not call apply_patch again on the same resource while a request is pending unless the request is rejected or the user explicitly asks for more edits.
The Review changes dialog shows the requesting assistant and its summary. Review in editor closes the dialog so the reviewer can inspect the actual draft. Approve & save saves the current editor contents, so the reviewer should check the draft rather than relying only on the assistant’s summary.
Review and rejection are supported for all six resource types. Selecting Reject opens a confirmation step with an optional note and two choices:
- Discard draft, selected by default, restores the last saved version in the shared editor and removes unpublished changes. Confirm with Reject & discard draft.
- Keep draft for further edits leaves the shared draft available for revision. Confirm with Reject & keep draft.
check_publish_request to read the outcome and any note.
For facet values, approval requires a full dashboard save that submits both facet_value_group_sorts and hidden_values. A partial facet save leaves the request pending and preserves the shared draft, while a save to unrelated attribute settings does not approve it. See Editing facet values for the facet-specific workflow.
1
Request approval
Call
request_publish with the same presence_id and the latest observed revision. Include an optional message describing what changed so the reviewer has context. The response includes a publish_request_id, a dashboard review_url, and an expires_at timestamp.2
Share the review URL and wait
Send the
review_url to the user or reviewer. They can inspect the affected resource in the dashboard and choose Approve & save or Reject from the request review. A regular editor save can also settle a pending request as published while preserving the submitted live/enabled state. Do not make further edits in that shared room while the request is pending unless the request is rejected or the user explicitly asks for more changes.3
Poll for the outcome
Call
check_publish_request with the publish_request_id until settled is true. The final status is published, rejected, superseded, or expired. Publish requests expire after 72 hours.4
Handle the result
On
published, the resource was saved. A ranking rule’s enabled field still determines whether it runs on the storefront. Merchandising rules, sort orders, and ranking rules have a config_version_id; blocks, facet values, and audiences return null. For rejected or expired, review any resolution note before deciding what to do. On superseded, a newer request has replaced this one. Switch to the newer publish_request_id.request_publish
Requests human approval for the shared document the agent is currently editing. Review is the default; use publish_immediately only when the user explicitly asks to publish without review. Requires an active presence_id from set_presence and the latest revision you observed. The revision must still match the current room revision, or the tool returns a RevisionMismatch error. Refresh presence and try again.
request_publish while another request is pending for the same shared editor room marks the older request as superseded and returns the new publish_request_id.
check_publish_request
Returns the current state of a publish request. Safe to call as often as needed.
status values:
Publishing immediately
Setpublish_immediately: true on request_publish to apply the shared editor document straight to the saved merchandising rule, sort order, recommendation block, facet values, ranking rule, or audience, with no reviewer step. Use it only when the user has explicitly asked to publish without review. When you omit the flag or pass false, the tool creates a pending review request.
Requirements and behavior:
- Supported for
resource_type: "merchandising_rule",sort_order,block,facet_values,ranking_rule, andaudience. - The caller needs the resource’s edit permission on the store:
merchandising-rules.editfor merchandising rules and audiences,sort-orders.edit,blocks.edit,attributes.editfor facet values, orranking-rules.edit. Without it, the tool returns 403. - There is no
forceoverride for a stale revision or a human editing the room. - The provided
revisionmust still match the current room revision, or the tool returns 409RevisionMismatch. Callset_presenceto refresh and retry. - If a human is actively co-editing the room, or connects during the publish, the tool returns 409
HumanEditingInProgressand nothing is written. Ask the user to save from the dashboard, or retry once the human leaves. - The document is validated with the same rules the dashboard save uses. Validation errors are returned as 422 with per-field messages.
- On success, the response includes
status: "published", confirming the resource was saved.config_version_idis populated for merchandising rules, sort orders, and ranking rules, and isnullfor blocks, facet values, and audiences. Pass the returnedpublish_request_idtocheck_publish_requestto verify the saved result without waiting for review.
collaborative-merchandising-editor prompt
The Layers MCP server exposes a collaborative-merchandising-editor prompt that describes the full safe-edit workflow, including the request_publish handshake. MCP clients that surface prompts (for example, Claude Desktop) can select it to prime an assistant with the correct presence-then-patch-then-request sequence before making changes.
Editing facet values
Facet value sorting, grouping, and hidden values live inside a filterable attribute’s configuration. Assistants co-edit them through the same collaborative editor tools by passingresource_type: "facet_values" and the attribute id or code as resource_id. The shared document exposes two keys under /fields:
facet_value_group_sorts— an ordered list of{ facet_value, position, facet_value_group_filter }entries.positioncontrols the manual storefront order, andfacet_value_group_filteris{ name }when the value belongs to a named group (all values sharing onefacet_value_group_filter.namerender as one group), ornullwhen ungrouped.hidden_values— a list of facet value strings that are hidden on the storefront.
facet_value_group_sorts carry no ids. The server keys sorts by facet_value and groups by name (both distinct per attribute) and owns the underlying UUIDs. Never send an id on a sort entry or on facet_value_group_filter. Layers rejects it.
Facet value sorting, grouping, and hidden values are edited in the shared document. Use request_publish to request human review, or publish_immediately only when the user explicitly asks to publish without review. attributes-manage create and update reject facet_value_group_sorts and hidden_values with a 422 that points back to the shared editor. Don’t try to set them alongside other attribute fields.
Facets don’t have /pins or /banners, so patches must target /fields/facet_value_group_sorts or /fields/hidden_values. The attributes.view permission is required to read a facet’s document and attributes.edit is required to apply patches or call request_publish.
Reorder a value:
facet_value_group_filter.name:
Sampling and grouping facet values
facet-values-manage exposes two actions that operate on facet values directly, without drafting RFC 6902 patches by hand.
samples shows what a facet value actually resolves to on the storefront. For each requested value it returns the shopper-visible product count (computed on the same filter path the storefront uses, so counts match what a shopper sees), the display name, the swatch (metaobject or option), and a few sample products and variants:
values reports { facet_value, display_name, product_count, swatch, samples }, where each sample is { product_title, product_handle, variant_title, image_url }. For a facet that isn’t filterable on the storefront (for example, one not visible on the storefront), product_count is null and the entry carries an error note instead of failing the call.
upsert places individual values into groups inside the shared collaborative draft. Use it when you want to group a handful of values without rewriting the whole facet_value_group_sorts list with apply_patch. Call set_presence first to get a presence_id; the draft’s current revision is resolved for you.
Each row in rows is { facet_value, group, after? }:
facet_value— the value to place. All existing memberships of that value are removed before the new row is inserted.group— the group name to place the value in. A new name creates the group;nullungroups the value. Required on every row.after— optional. Place the value directly after this value inside the target group; when omitted or whenafterisn’t in that group, the row lands at the end of the group. A moved value keeps its position only when staying in its current group.
revision and the changed_rows that were applied. upsert requires attributes.edit and an authenticated user, and writes into the same shared draft apply_patch edits. Request review of the finished draft with request_publish.
Requesting approval for the facet-values draft
apply_patch and facet-values-manage upsert only update the shared draft. By default, call request_publish with the active presence_id, the latest revision, and an optional message to request human review. See Requesting publish approval for the review and polling workflow, and Publishing immediately only when the user explicitly asks for no review.
The reviewer approves by saving from the dashboard review URL. A facet-values approval requires a full save that submits both facet_value_group_sorts and hidden_values. Partial saves leave the request pending and preserve the shared draft; saves to unrelated attribute settings do not approve it. check_publish_request reports config_version_id: null for facet values.
request_publish shape described in Requesting publish approval. For facet values, config_version_id is null. The removed facet-values-manage publish action is not supported: cached clients that call it receive an error directing them to request_publish with the presence_id and latest revision from set_presence. The list, samples, and upsert actions are unchanged.
collaborative-facet-editor prompt
The Layers MCP server also exposes a collaborative-facet-editor prompt covering the presence-patch-review flow, /fields patch boundaries, and the human-in-the-loop rule for publishing. Select it before asking an assistant to reorder, group, or hide facet values.
Working with grouped attributes
Some attributes are containers that hold other attributes rather than a single filterable value, for example a “dimensions” attribute that wrapslength, width, and height. MCP tools treat these differently:
- Groups are listed but not selectable.
attributes-managewithaction: "list"returns grouped attributes as read-only entries with their child attributes nested underchildren. Only the scalar children are markedselectable. - Search, browse, facets, and sort orders reject group codes. Passing a group, object, or otherwise non-selectable attribute code to
filter_group,facets, or a sort order returns a validation error. When the parent has scalar children, the error lists them so your assistant can retry with a valid code.
attributes-manage with action: "list" to discover which attributes are selectable before building filters or sort orders. Pass usable_for: "attributes" to get exactly the codes accepted as result attributes, or usable_for: "facets" for the codes accepted in facets and filter_group.
Checking the keyword weight budget
Thelist response includes a top-level keyword_weight_holders summary of the store’s keyword search weight budget. Check it before you set keyword_search_weight so your assistant knows how much budget is left. The summary lists every attribute holding a weight, including group or structured metafield attributes that never appear as individual entries in the list:
totalandremainingare the combined weight in use and the weight still available, out of 10.is_searchableisfalsefor attributes that hold a weight but aren’t searchable. Their weight still counts toward the budget.hiddenistruefor attributes that don’t appear as selectable entries in thelistoutput.
attributes-manage rejects a keyword_search_weight on an attribute that isn’t searchable. To add a weight, set is_searchable: true in the same update request.
Fetching attribute values
Callattributes-manage with action: "values" to enumerate the values available for a single scalar attribute. Use it before building filter_group conditions when your assistant needs to know what values a facet actually contains. For example, list every vendor or size before choosing one to filter on.
The response depends on the attribute’s type:
- Categorical attributes return a cursor-paginated
valuesarray. Each entry is{ "value": "<string>", "kind": "group" | "value" }. Pass the returnednext_cursorback in a follow-up call to fetch the next page. - Numeric attributes return a
rangeobject with the minimum and maximum values in the catalog.
collection_handle so the values reflect only products in that collection.
When the attribute has facet value groups, the first page lists each group with kind: "group" before any raw values, and raw members of a group are hidden from the results. Pass the group name as the filter value and Layers expands it to the group’s members at match time. Ungrouped raw values are returned with kind: "value".
Selecting product and variant fields
Theattributes argument on search-semantic, browse, and related tools accepts three kinds of selectors, all discoverable through attributes-manage with action: "list":
- Attribute codes — any storefront-visible attribute code (
vendor,color,size). - Core product fields — top-level product columns like
title,handle,featured_image,body_html,product_type,tags. Dotted sub-paths (images.src) are only accepted under jsonb product columns. - Qualified variant selectors — variant fields must be qualified with a container:
variants.<field>returns the value for every variant, andfirst_or_matched_variant.<field>returns the single variant that matches the current filter (or the first variant when no variant filter is active). Hidden variant columns such ascostare rejected.
price are rejected with a message that names the qualified forms (variants.price, first_or_matched_variant.price). Unknown sub-paths on a core product field return a 422 that suggests the parent field, for example title.foo → Did you mean ‘title’.
attributes-manage with action: "list" lists the qualified variant selectors alongside attribute codes so an assistant can discover the full vocabulary in one call. When a query matches nothing, the response includes a suggestions list of the top-5 nearest codes.
Classifying attributes for query understanding
attributes-manage create and update accept a data.classes array that controls how the query-understanding pipeline uses an attribute. Set it separately from is_searchable, keyword_search_weight, and enable_as_storefront_facet. Each switch controls a different behavior.
Pass one or more classes; values are lowercased and deduped server-side. To leave the existing classes unchanged on
update, omit the classes key. Passing null or any non-array value returns a validation error rather than clearing the field. Adding identifier to a searchable attribute, a non-metafield attribute, or a store that already has five identifier attributes also returns a validation error.
is_searchable triggers a catalog reindex, so batch those changes.
The attribute-setup prompt walks an assistant through the full workflow: discovering the attribute, sampling values with query_catalog, picking classes, and verifying with product-search-diagnostics. Select it from an MCP client that surfaces prompts (for example, Claude Desktop) before asking an agent to classify attributes.
Creating and publishing computed attributes
attributes-manage create, update, publish, and delete operate on computed attributes. Shopify options, metafields, and other catalog fields sync automatically and can’t be created or removed through MCP.
What each action does:
Rules
create enforces:
data.typemust becalculatedorderived.data.codeis auto-prefixed withcalculated.when it has no reserved namespace, sostyle_numberbecomescalculated.style_number. A code that already targets a synced namespace (contains a dot, for exampleoptions.sizeormetafields.custom.x) is rejected. A code that matches an existing attribute case-insensitively (options.Sizewhenoptions.sizealready exists, or a barevendor) is rejected too. Calllistto confirm what’s already there.type: "calculated"requiresdata.source_code.type: "derived"requiresdata.calculated_logic.- Exactly one implementation may be set per attribute.
create,update, andpublishall reject a request whose effectivesource_codeandcalculated_logicare both non-blank. Passnullon the field you’re clearing in the same request. data.output_schemais a list of{ "name": "<string>", "type": "<string>", "nullable": <bool> }objects, never a bare object.- A multi-field
output_schema(more than one entry) can’t setenable_as_storefront_facet: trueon the parent. Enable the facet on the specific virtual child code instead, for examplecalculated.dimensions.width.
create a JavaScript computed attribute:
create, update, and publish validate data.source_code synchronously before persisting. Source that can’t compile is rejected with a 422 carrying the parser’s rejection, instead of being accepted and surfacing later as an asynchronous compile_error. The same applies to data.input_query, which must be a bare selection set (a query { ... } document is rejected). publish validates the effective payload, so a bad draft saved earlier is also rejected at publish time.
Input query validation. data.input_query is checked against your store’s schema at every level. Unknown fields are rejected with the valid sibling fields and a closest-match suggestion, as are sub-selections on fields that have none and calculated, which always resolved to null inside an input query. Metafield names and reference sub-selections are checked against your store’s metafield definitions. draft_update applies the same input_query and output_schema rules as create, update, and publish, and an unknown output type lists the allowed ones.
Previewing before publishing. Use preview to confirm an input query returns the data your function expects before you publish:
products array carries the resolved input and, with run_function: true, the function’s output (or an output_error for a product where it failed). Values over 16 KB per product come back truncated. run_function needs an attribute whose compile_status is ready, and it always runs the live function on the live input query. Draft source never runs server-side, so publish it and wait for ready first. When the previewed query differs from the live one, the response includes a note saying the output came from the live query.
After publish reaches ready, Layers recomputes only that attribute’s values on each product. A full catalog rebuild runs only when the attribute feeds search, sequences, families, merchandising rules, or variant breakout conditions.
Drafts and publishing. draft_update writes to draft_source_code, draft_input_query, draft_output_schema, and draft_test_state on the live attribute. A draft is an editor autosave buffer only. Nothing compiles until publish promotes it into the live fields. A partial draft_update only touches the keys you send. Omitted draft fields keep their saved value, and an explicit null clears just that one field.
publish promotes the draft. Compilation runs asynchronously, so poll get (or list) afterward to read compile_status and compile_error:
source_code, input_query, and output_schema resolves independently on publish. An explicit data.* value beats a saved draft, which beats the current live value. Publishing a single-field override, for example just data.output_schema, doesn’t drop a saved draft for the other fields. calculated_logic is only touched when you pass it explicitly.
Deleting a computed attribute. delete runs the same usage guard the dashboard does, extended to cover reports and every virtual output-schema child. A blocked delete names the context, for example Cannot delete attribute that is used in a sort order. When the blocking usage sits on a virtual child, the message adds (referenced via output field '<child code>') so you know which field to detach first. Catalog attributes always fail this action. Use the dashboard or Shopify to remove those sources.
Diagnosing search coverage
Useproduct-search-diagnostics when a product is missing from search-semantic results, to verify what content reached its search document, or to confirm an attribute change flowed through.
Resolve a product by numeric id, Shopify gid (gid://shopify/Product/...), or handle. Pass include_variant_documents: true on per-variant-indexed products to include the rendered document text for each variant.
The response has three sections:
content_selection field is "skipped", and the store indexes the full unfiltered catalog instead.
Diagnosing missing facets
product-search-diagnostics also explains facet availability. Pass facet_codes (and optionally a collection handle) to check why a facet you requested from the Facets API is missing from the response:
facet_diagnostics section lists the requested codes, which were included, and which were dropped with a reason: attribute_not_found, not_enabled_as_facet, attribute_not_filterable, facet_still_building, facet_build_failed, or facet_cardinality_exceeded (Layers turned the facet off automatically because it has too many distinct values). These are the same readiness checks the Facets API applies when serving requests, so a dropped code here explains a missing facet in storefront responses. See When a facet goes live for how facet builds work.
For a store-wide rollup, call store-operational-status and read search_documents. It returns aggregate ready, pending, and needs_attention counts across the catalog. The same response includes a facets section with each facet’s build phase and last refresh time under states, plus a withheld list naming any enabled facets the API is currently holding back and why.
Batch search testing
Usesearch-batch to test search relevance across many queries at once. For example, check a regression list after tuning ranking weights, or compare how a configuration change affects a set of important queries. Runs are deterministic and unjudged: the tool records what each search returned, with no LLM grading. For judged, admin-managed evaluation runs over stored query sets, use store-evaluations instead.
The tool is action-based, like the publish-request flow: start kicks off an asynchronous run and returns a run_id, get polls progress and reads results, list shows recent runs, and cancel stops a run.
Limits per run:
Starting a run
Each entry inqueries is a plain string or an object with query, an optional expect (a product id, handle, or title the query is expected to return), per_page (1-25, default 10), and an optional filter_group. Attributes and every filter_group are validated synchronously when you call start, so an invalid code fails the start call instead of failing jobs mid-run.
Each entry in variants accepts a label, bypass_cache, an excludeRuleIds list of ranking rule ids to hold out (see Testing ranking rule impact), and the same tuning, searchStrategy, and pipeline bypass options as search-semantic (bypassQueryExpansion, bypassIntentModifiers, bypassAICuration, bypassAIDiversity, bypassRankingRules). Layers validates rule ids in excludeRuleIds when you call start, so an unknown id fails the start call before any searches run. When variants is omitted, the run uses a single baseline variant. Batch searches bypass the results cache by default so comparisons reflect live behavior; set bypass_cache: false to opt out.
run_id, the run status, total_searches, and the store’s current config_version_id:
status: "failed" and an error explaining why.
Reading results
Poll withaction: "get" and the run_id. Partial results are readable while the run is in progress; settled turns true once the run reaches completed, failed, or cancelled. Results paginate with page and per_page (max 25).
Every
get response also reports config_changed_during_run. When true, the store’s search configuration changed after the run started, so discard the comparison and start a new run.
include: "diff" tracks the baseline variant’s top product across the other variants. For each query, every variant reports the rank of that product in its own results (compared_product_rank) and the rank_delta_from_baseline. If the product dropped out of a variant’s results entirely, the rank is null with the reason baseline_top_product_not_in_variant_results.
Queries with an expect product report whether it was found and at what rank:
completed + failed always accounts for every search in the run. Runs and their results are pruned after 24 hours.
Testing ranking rule impact
UseexcludeRuleIds on search-semantic to hold specific ranking rules out of a single search. This answers “is this rule still earning its place?” with one read-only call, instead of disabling the rule in live config, testing, and re-enabling it.
Pass an array of ranking rule ids (up to 50). Get ids from ranking-rules-manage with action: "list", or from debug.appliedRankingRules on a previous debug search. The debug payload reports each applied rule as an {id, name, type} object. The tool also accepts exclude_rule_ids as an alias.
excluded_ranking_rules block naming each held-out rule:
- Unknown rule ids fail with a validation error rather than being silently ignored, so an inert exclusion never reads as an inert rule.
- Disabled rules are accepted. The echo reports
enabled: falseso you can tell the rule wasn’t running anyway. bypassRankingRules: truetakes precedence: no rules run at all and the exclusion list has no effect.- Layers treats searches with a non-empty exclusion list as diagnostic, so holdout sweeps stay out of search analytics and zero-result reporting.
excludeRuleIds on a search-batch variant and read the diff:
Pin actions share a single pin budget across all ranking rules. Holding out a pin-heavy rule can let later rules’ pins land, so result movement can exceed the excluded rule’s own pins. This matches what deleting the rule would do.
Comparing sort orders
sort-orders-preview accepts sort_order_codes (up to 3) to compare how the same products rank under different sort orders. The response aligns each product’s rank across every requested code and includes rank_deltas relative to the first code:
comparison_window), not just the requested page. The window catches cases where a product sits on page 1 of one sort order and page 3 of another. A product outside the window reports a null rank with the reason outside_comparison_window. Use sort_order_code (singular) for a plain paginated preview of one sort order.
Explaining sort order rankings
sort-orders-preview returns a compact product payload with a 1-based position for each product. Image URLs and variant details are omitted to keep responses small. Pass explain: true to attach the full ranking explanation to every product on the page. The explanation contains the same sort effects the dashboard preview renders, including matched soft boosts, position movement, lift, and any boost-mode switch.
To explain one product, pass explain_product with a product ID, GID, handle, or SKU. This requires a singular sort_order_code. The tool scans a bounded window of results (up to 500 products) for the product and returns its position and full explanation:
Browsing without a sort order
browse picks a sort order automatically when you omit sort_order_code. It uses the collection’s default when one is set. If the collection has no default, it falls back to the store’s storefront-visible relevance sort order, and then to the first storefront-visible sort order (ordered by display order, then creation time). The call only fails with a 422 when the store has no storefront-visible sort orders at all.
The response echoes the resolved sort order so an assistant can confirm what actually ran:
Pass
sort_order_code explicitly to override both the collection default and the fallback.
Publishing product sequences
Publishing a product sequence is two-phase. Thepublish action records intent immediately by setting is_published, but the sequence only starts serving after a background evaluation confirms it is eligible. A sequence needs at least two searchable products and must satisfy any configured conditions. The evaluation runs immediately after publish, create, update, and single-group reevaluate calls and normally settles within seconds.
Read activation_status in the response instead of the raw is_published and is_active flags:
For example, publishing a sequence returns its current state:
pending response usually resolves within seconds; follow up with get to see the settled state. If a sequence was previously blocked, publishing preserves the blocking inactive_reason so an assistant can see why the sequence won’t activate and fix the cause instead of retrying.
publish and unpublish also accept a group_ids array to change many sequences in one call. Prefer this over one call per group when flipping publish intent across a batch:
results array plus rollup counts:
results for per-group errors instead of assuming success from the rollup. evaluation_queued reports whether the background eligibility job was dispatched; a false value with a warning means the status was saved but the evaluation didn’t queue and you can retry with reevaluate. unpublish settles is_active synchronously and omits evaluation_queued.
Call reevaluate with a group_id to re-run the eligibility check for one sequence; the response includes evaluation_queued: true plus the group’s current payload. Omit group_id to queue a re-evaluation across every sequence in the store.
The list action returns a slim projection for each group (ids, names, flags, activation_status, and products_count) without per-group products or contextual_conditions. Call get with a group_id when you need the full sequence payload.
The product-sequence-builder prompt walks an assistant through creating groups in one batch call, setting is_published on the create/update payload (which already is the publish step), and verifying with activation_status. Select it from an MCP client that surfaces prompts (for example, Claude Desktop) before asking an agent to build sequences.
Building blocks with the catalog
Recommendation blocks combine anchor-dependent strategy types, strategy-specific configuration keys, and rollup-driven readiness. Callblocks-catalog before creating or updating a block so an assistant works from the real vocabulary instead of guessing:
- Anchors — for each anchor type, the allowed
strategy_typesand every strategy key with its title, description, requirements, beta flag,relationship(complement,substitute, orsequence), readiness (readyanddata_computed_at), andconfig_schema. Theconfig_schemalists each acceptedstrategy_configkey with its type, whether it’s required, and any allowed values or limits. See Strategy configuration keys for the current schema. - Rules — the block rule vocabulary: condition fields, their operators and allowed values, combinators, and the four action types.
- Fallback modes — one-line definitions of
replaceandfill(see Fallback chains).
anchor_type to scope the response to one anchor. A strategy key with ready: false is still computing its first data rollup; a block using it serves its fallback chain until data_computed_at is set.
The default detail: "summary" response keeps payloads bounded. Without a strategy filter, each anchor includes only strategy type, key, requirements, and readiness; a filtered strategy also includes its title, description, and configuration field names. The summary lists only rule operators, combinators, and action names. Use detail: "full" for the complete configuration schemas and targeting rule vocabulary, or filter by anchor_type, strategy_type, or strategy_key to keep the response focused.
blocks-manage validates writes against the same catalog. strategy_type, strategy_key, and rule action types are enums, and unknown strategy_config keys are rejected with a validation error that names the accepted keys and their allowed values. Cross-field errors list the strategy types allowed for the block’s anchor, so an assistant can correct a payload in one retry.
Fallback trees and block validation
A block’sfallback_tree has the shape [{ id, conditions?, chain: [{ block_id, mode }] }]. Each branch has an id, optional conditions, and an ordered chain of fallback blocks:
chain. replace serves the fallback instead of the primary results; fill tops up the primary results with fallback products.
For recommendation blocks, validate_document applies the same validation rules as publishing, including when it checks the current document without proposed patches. apply_patch validates the simulated result before writing and rejects a patch with 422 InvalidField when a top-level field touched by that patch is invalid. An unrelated pre-existing invalid field does not prevent a patch to another field.
When a manual block uses collection mode, a non-collection anchor requires a non-empty strategy_config.collection_handle. A collection-anchored block uses its anchor collection and does not need this handle.
Anchor-relative filter values
In a block rule’sapply_filter, promote, or demote action, a filter_group expression can take its values from the anchor product instead of a fixed values list. Set value_source: "context" and leave out values:
When more than one anchor value resolves (several matching tags, or several cart items), Layers ORs them:
eq becomes in and neq becomes notIn. If no value resolves, the expression is dropped for that request. value_source: "context" requires anchor_type product or cart. blocks-manage rejects it for any other anchor, and rejects value_property or value_prefix unless value_source is "context".
collection::women and collection::men, the second expression matches products tagged with either, so the block returns women’s, men’s, and unisex products from the anchor’s vendor.
If you save with an incompatible anchor, blocks-manage returns a validation error keyed to the expression, for example rules.0.action.filter_group.expressions.0.value_source, and the message names the block’s anchor type: Anchor-relative filter values (value_source "context") read the anchor product, so they need a product or cart anchor; this block's anchor type is 'collection'. To fix it, change anchor_type to product or cart, or replace the expression with static values.
Previewing blocks
blocks-preview runs a block’s configuration against the live catalog and returns a compact product list without touching stored config. Provide exactly one of:
block_id— preview a saved block. This runs the full recommendation pipeline, including the block’s fallback chain.data— preview an inline block definition before saving it. Inline previews run only the primary configuration;fallback_block_idsare not executed.
Both saved and inline previews apply
filter_group and exclude_product_ids. The shopper filter is combined with the block’s rule filters rather than replacing them.
{ id, handle, title, price, position } plus the resolved configuration after rules ran (strategy, strategy_config, safeguards, and whether a rule hid the block). processing: true means the strategy’s data rollup is still computing.
With explain: true, the trace lists pipeline events in order: block selection, each rule evaluation and applied action, strategy resolution and readiness, strategy product counts, applied safeguards, exclusions, and fallback traversal with its result. Use the trace to answer “why did this block return these products”, for example to spot a rule that unexpectedly matched or a fallback that replaced the primary strategy.
Reading block performance
blocks-manage with action: "list" returns rolling 7-day performance counters for each block: impressions_7d, clicks_7d, ctr_7d, purchases_7d, and metrics_computed_at. Pass sort (ctr_7d, impressions_7d, or the default priority) to rank blocks by performance, and anchor_type to filter the list.
A published block with zero impressions usually means the block isn’t wired into the theme. Rendering is theme-side, so Layers can’t detect a missing Liquid binding. See Rendering blocks in Liquid. For deeper analysis, query the blocks LayersQL dataset through layersql-query.
Example: run an analytics query
Analytics is exposed through LayersQL. Ask your assistant to inspect the schema first, then run a query:layersql-schema to discover available datasets, metrics, and dimensions. Omit dataset to get a compact syntax cheat-sheet with clause order, operators, and two example queries. Pass include_reference: true for the full syntax reference. Call layersql-validate-query with the target store and the query to check it before you run it. Validation confirms every metric and dimension exists on the dataset, and errors list the available names so an assistant can correct the query without a retry loop.
To render the result as a chart, include a VISUALIZE clause in the query. layersql-query returns a visualization chart config alongside the rows, so an assistant can pick the chart type, x-axis, and series without a second call.
layersql-query returns 50 rows by default and accepts up to 500 rows per call. Use columns to project the result to selected columns. When the row cap is hit, the response sets "truncated": true and includes next_offset. Pass that value back as offset on the next call to page through the remaining rows, or narrow start_date and end_date to shrink the result set:
search-health-triage prompt walks an assistant through triaging zero-result or unhealthy search traffic: discovering metrics with layersql-schema, ranking terms by the canonical zero_results measure, and splitting catalog-coverage misses (identifier_lane_misses) from relevance failures. Select it before asking an agent to investigate search health.
The request-transform-authoring prompt covers the shape of a request transform: request_types, the action types accepted by request-transforms-manage (replace_query, modify_query, add_filter_group, set_default_selected_options, modify_tuning_parameters, override_sort_order), and the targeting condition vocabulary (context.* for session context, request.* for the request itself). Select it before asking an agent to author or edit a transform.
Managing saved reports and dashboards
analytics-manage reads and writes the same saved reports and dashboards that appear in the Layers dashboard under Analytics. Use it when an assistant should turn an ad-hoc LayersQL query into something a merchant can revisit, or assemble a set of reports into a dashboard.
resource— eitherreport(a saved LayersQL query) ordashboard(an ordered set of cards).action—list,get,create,update, ordelete.
layersql-query before saving it. Once the rows and visualization look right, save the same query string as a report:
columns, rows, visualization, and a url deeplink that opens the report in the Layers dashboard.
A dashboard is an ordered list of cards. Each card either references an existing report by report_id or creates one inline with query and name. Inline creation runs in a single transaction, so a bad later card leaves no orphan reports. Set each card’s width to full, half, or third. Layers computes each card’s position and size on a 12-column grid from those widths, so do not send raw coordinates:
get, create, and update responses return every card’s rows, visualization, position, size, and per-card truncation flags, plus a url deeplink to the dashboard. list returns lightweight metadata for reports and dashboards. Setting is_default: true on a dashboard unsets the previous default for that store.
create, update, and delete require the analytics edit permission on the store. list and get require the analytics read permission. Deleting a report that is referenced by a dashboard card returns an error. Remove or replace the card first.
MCP audit log
Every write action your assistant performs through the Layers MCP server is recorded alongside dashboard configuration changes in the store’s Activity Log. Each MCP entry captures the tool, action, user, store, and timestamp. Review activity in the dashboard under Settings → Access & Security → Activity Log. MCP actions appear in the same feed as configuration edits, so you can see everything that changed in a store in one place. Filter by event, action, or free-text search, and open any entry to inspect its details. The operational context attached to an MCP call is only visible to users with API key management permissions. Lower-privilege users still see that an MCP action happened, but not its raw context.Storefront MCP server
The Storefront MCP server exposes read-only storefront operations as MCP tools. It uses the same access token as the Storefront REST API, so you can integrate AI assistants into customer-facing experiences.Connecting
Configure your MCP client with the storefront endpoint and your API token:Available tools
Common parameters
Most search and browse tools accept these optional parameters:By default,
search-text and browse strip the _meta payload from responses to keep results compact. Pass debug: true when you need scoring diagnostics, for example when debugging why a product ranked where it did.filter_group, facets, and sort orders only accept scalar attribute codes. Group or container attribute codes are rejected with a validation error that lists the selectable child attributes when they’re available.Example: text search with debug
When to use each server
- Use the Layers MCP server when you want an AI assistant to help manage your store: creating merchandising rules, tuning search behavior, building sort orders, or exploring analytics.
- Use the Storefront MCP server when you want to integrate AI-powered product discovery into a customer-facing experience. It’s also useful when building AI agents that need to search and browse your catalog.
Next steps
- Manage API access to create storefront tokens
- Learn about request transforms and merchandising to understand what you can configure through MCP
- Explore the API reference for the underlying REST endpoints