Skip to main content
Layers exposes two Model Context Protocol (MCP) servers that let AI assistants interact directly with your stores. Use them to manage merchandising, search tuning, catalog operations, and storefront queries through any MCP-compatible client.

Layers MCP server

The main MCP server exposes tools for managing your Layers stores. It uses OAuth authentication and requires the mcp: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:
When you connect for the first time, you’re redirected to the Layers dashboard to authorize the connection. After authorization, your MCP client stores the OAuth tokens and reconnects automatically. MCP connections are scoped to specific stores and specific permissions. On the authorization screen, you select which stores the connection can access and which of your own permissions it may use. A connection can never exceed your own access. If your access is later reduced, the connection’s access is reduced immediately to match. Because connections are store-scoped, 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 write tools are consolidated into a single *-manage tool per resource. Pass an action (for example list, create, update, delete) to control what the tool does, so listing and mutation share one tool per resource.

Submitting feedback about MCP tooling

Admin MCP connections can call mcp-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:
The response confirms the submission:
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 the bulk variants below. 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:
Write calls fail loudly instead of silently succeeding with no effect:
  • 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 create or update call whose payload resolves to nothing returns a validation error rather than reporting success: true with an unchanged record.
  • Invalid field values return a readable Validation failed: ... error naming the field.
If an assistant reports a successful update but nothing changed, check the tool response. A genuine write returns the refreshed record. A rejected write returns success: false with the validation message.

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, with source (built_in, analytics, or custom), value_type, coverage_percentage, unique_values, and last_seen_at. These are the codes accepted after SEGMENT BY in LayersQL.
  • contextual_fields — the context.* field names conditions accept in blocks-manage, merchandise-rules-manage, request-transforms-manage, sort-orders-manage, and product-sequences. Each entry carries a label, group, type, allowed operators, and the same coverage stats. Merchant renames from the Dimensions page flow through as label and description.
Filter with 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.
To sample values for one field before writing a condition:
Custom fields your storefront sends under 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 to store-dimensions:
Store-specific fields (custom parameters, merchant-renamed dimensions) are not enumerated in tools/list, so calling store-dimensions for the target store is the reliable way to see the current vocabulary before a write.

Example: create 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 calls merchandise-rules-manage with action: "create" and the appropriate parameters — handling pin positions, collection targeting, and expression configuration automatically.

Bulk actions

Several -manage tools accept bulk variants so an assistant can apply the same change to many records in one call:
  • blocks-managebulk_publish, bulk_unpublish, bulk_duplicate, bulk_delete (pass block_ids)
  • merchandise-rules-managebulk_enable, bulk_disable, bulk_delete (pass rule_ids)
Use bulk actions to act on many records at once — for example, unpublishing all draft blocks after a seasonal campaign, or disabling a batch of merchandising rules outside their window.
The response includes an affected_count so the assistant can confirm how many records changed.

Collaborative editor

Assistants edit merchandising rules, sort orders, and facet values 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 calls set_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)
  • Facet value sorting, grouping, and hidden values (referenced by attribute id or code)
For read-only inspection or listing, keep using merchandise-rules-manage, sort-orders-manage, and facet-values-manage with action: "list".
Direct write actions on merchandise-rules-manage and sort-orders-manage (create, update, delete, bulk_*, toggle_status, and so on) now return a compatibility error that points to the collaborative editor tools. Update your prompts and agents to use set_presence + apply_patch for writes.

Editing flow

1

Announce presence and read the document

Call set_presence with the store, resource_type, and resource_id. The first call for an agent run creates a new presence_id. 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, and successful apply_patch calls also refresh presence for that run. 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.
Example response:
Pass a sort order handle or id as resource_id when resource_type is sort_order. Concurrent runs from the same OAuth client each receive their own presence_id so they can expire independently.

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.

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.
Use 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.
Rules for notes:
  • Each key must match a path present in the same patches list. 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.
Agents that omit notes behave exactly as before.

Error handling

apply_patch returns deterministic errors so agents can recover automatically:

Requesting publish approval

apply_patch only updates the shared draft. To publish a merchandising rule, an agent asks a human reviewer to approve the change. The reviewer approves or rejects the request from the dashboard, and Layers records the agent’s identity in the config audit log when it publishes. Use request_publish when the user asks you to save or publish, then poll check_publish_request until the request settles. Do not call apply_patch again on the same rule while a request is pending unless the reviewer rejects it or the user explicitly asks for more edits. Publish requests are supported for resource_type: "merchandising_rule". Facet values and sort orders publish through their own flows (see Editing facet values).
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 same-origin review_url, and an expires_at timestamp.
2

Share the review URL and wait

Send the review_url to the user so they (or another grant owner) can open the review modal in the dashboard. While a request is pending, the shared draft is protected from reconciliation, so unrelated dashboard events will not overwrite it.
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 changes are live and config_version_id points at the resulting config version. On rejected or expired, you can edit the rule again and call request_publish again. On superseded, a newer request has replaced this one. Switch to the newer publish_request_id.
request_publish
Creates a pending publish request for the shared document the agent is currently editing. Requires an active presence_id from set_presence and the revision you last observed. The revision must still match the current room revision, or the tool returns a RevisionMismatch error. Refresh presence and try again.
Example response:
Requesting publish while another request is still pending for the same rule 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.
Example response after approval:
status values:

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 passing resource_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. position controls the manual storefront order, and facet_value_group_filter is { name } when the value belongs to a named group (all values sharing one facet_value_group_filter.name render as one group), or null when ungrouped.
  • hidden_values — a list of facet value strings that are hidden on the storefront.
Rows in 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 — it will be rejected. Facet value sorting, grouping, and hidden values can only be written through this shared editor plus facet-values-manage publish. 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 publish. Reorder a value:
Group two values under a shared display name by giving both entries the same facet_value_group_filter.name:
Hide a value from the storefront:
Publishing the draft
apply_patch only updates the shared draft. In the dashboard, a human clicks Save to commit that draft. When an agent is running on its own with no human editing the room, call facet-values-manage with action: "publish" and the target attribute to commit the draft to the store.
  • Publish is refused while a human is co-editing the room. In that case the response is { "published": false, "reason": "human_editing" } — keep co-editing with apply_patch and let the human click Save, or retry publish after they leave.
  • Publish is refused if you have not seeded or edited the draft in this session, to prevent an empty draft from wiping existing config.
  • Successful publishes write to the store via the same code path as the dashboard Save action and appear in the MCP audit log.

collaborative-facet-editor prompt

The Layers MCP server also exposes a collaborative-facet-editor prompt covering the presence-patch-publish 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 wraps length, width, and height. MCP tools treat these differently:
  • Groups are listed but not selectable. attributes-manage with action: "list" returns grouped attributes as read-only entries with their child attributes nested under children. Only the scalar children are marked selectable.
  • 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.
Use 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.

Fetching attribute values

Call attributes-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 values array. Pass the returned next_cursor back in a follow-up call to fetch the next page.
  • Numeric attributes return a range object with the minimum and maximum values in the catalog.
Both responses can be scoped to a collection with collection_handle so the values reflect only products in that collection.

Selecting product and variant fields

The attributes 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, and first_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 as cost are rejected.
Bare variant field names like 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.fooDid 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.
Toggling 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.

Diagnosing search coverage

Use product-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:
On dev stores that skip LLM content selection, the payload’s content_selection field is "skipped" — 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:
The response’s 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

Use search-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 in queries 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.
The response returns the run_id, the run status, total_searches, and the store’s current config_version_id:
If dispatch fails, the response carries status: "failed" and an error explaining why.

Reading results

Poll with action: "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:
A search job that fails is recorded as a failed row with its error message, so completed + failed always accounts for every search in the run. Runs and their results are pruned after 24 hours.

Testing ranking rule impact

Use excludeRuleIds 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.
The response echoes an excluded_ranking_rules block naming each held-out rule:
Use the echo to distinguish “the rule was excluded and results didn’t change” from “the exclusion didn’t take”. Behavior to know:
  • 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: false so you can tell the rule wasn’t running anyway.
  • bypassRankingRules: true takes 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.
To compare baseline results against results without a rule in one run, pass 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:
Ranks are computed over a bounded comparison window per sort order (reported in the response as comparison_window), not just the requested page. This catches the interesting case 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. The publish 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:
A 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:
The response returns a per-group results array plus rollup counts:
Each write is its own transaction, so partial results are accurate — check 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. Call blocks-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_types and every strategy key with its title, description, requirements, beta flag, relationship (complement, substitute, or sequence), readiness (ready and data_computed_at), and config_schema. The config_schema lists each accepted strategy_config key 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 replace and fill (see Fallback chains).
Pass 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. 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.

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_ids are not executed.
Optional parameters:
The response returns each product as { 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:
Call 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. The 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, 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 — either report (a saved LayersQL query) or dashboard (an ordered set of cards).
  • actionlist, get, create, update, or delete.
Preview a query with layersql-query before saving it. Once the rows and visualization look right, save the same query string as a report:
The response includes the report’s 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 Configure → 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:
Authentication uses the same storefront access token you use for the REST API. Pass it as a bearer token in the authorization header.

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.
If you only need quick read-only answers inside Shopify (zero-result searches, how a product is indexed, a collection’s rules or default sort), Shopify Sidekick can use the Layers tools bundled with the Shopify app without any MCP setup. See Shopify admin extensions.

Next steps