Skip to content

Filters & attributes ​

How to narrow product search by attribute β€” brand, price, sticker, vendor code β€” when your agent queries your catalog. This applies to the in-product sales agent (which builds filters for you automatically) and to any external agent you wire up over the Product (commerce) MCP. Read this when you need to constrain results by attribute, or when a filter "silently returns nothing."

In the app

You don't hand-write filters for the in-product agent β€” it applies them for you while it searches. You build filters by hand only when you connect your own agent to the catalog over the Product MCP. Either way, the catalog itself is connected and managed under Knowledge Base β†’ your product integration (https://app.mychatbot.app/knowledge-base).

Cheat sheet ​

Which filters each search tool honors ​

Every filter-accepting tool enforces all ten operators with the same semantics β€” including whole-catalog semantic_product_search. A filter is never silently ignored; the remaining skill is matching the operator to the intent and the attribute's shape.

Search toolWhat it doesFilters it honors
semantic_product_searchFree-text semantic search across your whole catalogall ten operators
filter_category_productsLists products in one category, with filtersall ten operators
get_available_filtersShows which attributes/values you can filter on within a categoryall ten operators
get_category_attributes, get_category_attribute_valuesDiscover the exact attribute names and their real valuesdiscovery only β€” no filters
get_product_details, get_product_variants, find_similar_products, get_products_by_ids, get_all_categoriesDetail / lookup / browseno filters

Which operator fits which intent

Exact values and list membership β†’ eq / in. Excluding a value or element β†’ ne. Partial text anywhere in a string, case-insensitive β†’ contains. Numeric ranges (price >= 20) β†’ gt/gte/lt/lte β€” bounds may be numbers or numeric strings, and the comparison is numeric even on attributes stored as text. Known-case prefixes/suffixes β†’ startswith/endswith (case-sensitive, whole stored string).

One nuance worth knowing. On a whole-catalog search, eq/in/contains also guide which candidate products get retrieved from the compact searchable copy of each product's attributes; the comparison and prefix operators don't steer that retrieval β€” they are applied as a strict constraint on everything that comes back. Practically: keep the descriptive intent in query, use filters as hard constraints, and make sure a range-filtered attribute holds values that read as plain numbers (get_category_attribute_values shows them). A range means the attribute exists and compares: products that lack the attribute don't match, and neither do values with no numeric reading against a numeric bound (decorated values like "1 200 Π³Ρ€Π½" are excluded, not passed through) β€” so a range on an attribute the catalog doesn't carry returns nothing.

What a filter looks like ​

A filter is a small object:

json
{ "attribute": "brand", "operator": "eq", "value": "Numbuzin" }
  • attribute β€” the attribute name exactly as it appears in your feed (case- and underscore-sensitive; MyChatBot does no rewriting). The reserved attribute name targets the product's top-level name.
  • operator β€” one of eq, ne, gt, gte, lt, lte, in, contains, startswith, endswith. All of them are enforced on every filter-accepting tool.
  • value β€” a single value, a list when operator is in, or a nonblank string when operator is contains. For the range operators a number and a numeric string (50 / "50") behave identically β€” both compare numerically.

Multiple filters are AND-ed together:

json
{
  "query": "hydrating serum",
  "filters": [
    { "attribute": "brand",     "operator": "eq", "value": "Numbuzin" },
    { "attribute": "skin_type", "operator": "in", "value": ["dry", "normal"] }
  ]
}

Range filter β€” works on semantic_product_search and the category tools alike, as long as the attribute's stored values read as plain numbers (they may be stored as text):

json
{
  "query": "hydrating serum",
  "filters": [
    { "attribute": "price", "operator": "gte", "value": 20 },
    { "attribute": "price", "operator": "lte", "value": 60 }
  ]
}

Look up the real attribute names first

Because attribute must match your feed exactly, discover the available attributes and their real values with get_category_attributes and get_category_attribute_values before you build a filter. In the app you can see the same attributes on your product integration's page (Knowledge Base β†’ your product integration β†’https://app.mychatbot.app/knowledge-base).

Partial string matching with contains ​

Use contains when the shopper knows only part of a product name or another string attribute. It performs a case-insensitive literal substring match: ASHEN matches a name such as The Ashen Evening Dress wherever the fragment appears.

json
{
  "query": "evening dress",
  "filters": [
    { "attribute": "name", "operator": "contains", "value": "ASHEN" }
  ]
}

attribute: "name" targets the product's top-level name rather than a feed attribute called attr_name. Use it with semantic_product_search for catalog-wide lookup or filter_category_products when the category is known. get_available_filters also accepts it to narrow facet counts, but does not return products; both category tools require a category_id.

contains accepts a nonblank string and applies only to string fields. It is not a numeric or boolean operator. Wildcard characters such as * and ? are treated as ordinary text, not as patterns.

Stickers, coverage lists & other multi-value attributes ​

Some attributes hold several values per product β€” a native list (stickers), or one string that joins values with commas (e.g. a cities within radius coverage list). eq matches these element-wise: it matches the full stored value exactly, or any single element of the list. Full-string equality is exact (case preserved); the element match is case-insensitive and ignores surrounding whitespace. in matches when any element equals any of several accepted values:

json
{
  "query": "gift sets",
  "filters": [ { "attribute": "stickers", "operator": "eq", "value": "ΠŸΠΎΠ΄Π°Ρ€ΡƒΠ½ΠΎΠΊ" } ]
}

This returns every product whose stickers include ΠŸΠΎΠ΄Π°Ρ€ΡƒΠ½ΠΎΠΊ, regardless of its other tags. Likewise { "attribute": "cities within radius", "operator": "eq", "value": "Rosneath" } matches a record whose comma-separated coverage list contains Rosneath as an element. A filter value that itself contains a comma can only match as the full stored string β€” it can never be a single list element.

How the other operators treat multi-value attributes:

  • ne is the exact negation of eq: it matches only when no element equals the filter value (case-insensitive) and the full stored value differs β€” cities within radius ne "Rosneath" excludes every record covering Rosneath.
  • gt / gte / lt / lte on a native list match when any element satisfies the comparison. A comma-separated string is not split for ranges β€” it compares as one string, which is rarely what you want; range-filter typed numeric attributes instead.
  • startswith / endswith on a native list match when any element carries the prefix/suffix (case-sensitive). A comma-separated string is tested whole β€” its elements are not split out; use eq/in for membership or contains for fragments.

Use eq for list membership β€” never contains

contains is a substring match and matches inside words: on a coverage list containing Rosneath, contains "Neath" wrongly matches, while eq "Neath" correctly does not (Neath is not an element). Filter list membership with eq/in; keep contains for genuine partial-text lookups in one string field.

Filtering by SKU or product code ​

Identifier attributes are not filterable on whole-catalog semantic search β€” they're deliberately kept out of the searchable-attributes copy and handled by exact-match ranking instead. An attribute is treated as an identifier when its name contains any of these as a whole word:

vendorcode, productcode, sku, upc, ean, isbn, mpn, asin, barcode,
model, part, product_id, item_id, catalog, article, Π°Ρ€Ρ‚ΠΈΠΊΡƒΠ»

Matching is by whole word, not substring β€” product_id and item_id count, but ordinary words that merely contain one of these (e.g. departure contains "part", compartment) are not treated as identifiers.

Filtering by SKU on semantic search returns nothing

An eq/in filter on sku, vendorcode, barcode, etc. can't be satisfied by whole-catalog search. To match exact codes:

  • Put the code straight in query. MyChatBot automatically boosts exact code/SKU matches and skips semantic ranking for code-like queries, so the exact item lands on top.
  • Fetch by id with get_products_by_ids when you already know the product id.
  • To filter on a code column directly, use filter_category_products inside that product's category (you may need a reindex first β€” see below).

The vendor-site URL attribute ​

URL-valued attributes (image links, a vendor site link) are excluded from filtering like other links. The Ukrainian vendor-site link attribute посилання Π½Π° сайт (romanized posilannya-na-sayt; Посилання_Π½Π°_сайт and посилання_Π½Π°_сайт are also recognized) gets extra ranking weight so "find the product at this vendor URL" queries land on the exact item. MyChatBot tunes this behind the scenes.

When a filter returns nothing ​

An empty result isn't always a real "no results"

A catalog indexed before the current searchable-attributes copy existed can have a missing attribute blob, so exact filters can't match even when the value genuinely exists.

Tell-tale: semantic_product_search with a filter returns [], but get_category_attribute_values (or filter_category_products) shows the value is really there.

Fix β€” a from-scratch reindex. This isn't a self-serve toggle. Either delete and re-add the integration in Knowledge Base (https://app.mychatbot.app/knowledge-base), or contact MyChatBot support with the integration id and ask them to reindex it.

MyChatBot tunes search relevance for you

Result ordering blends semantic similarity, keyword matching, exact-code boosts, and the special URL weighting above. These weights aren't self-serve β€” MyChatBot tunes relevance for your catalog. If ranking or filtering doesn't fit your inventory, contact support.

Best practices ​

Do

  • Use eq/in filters for categorical facets (brand, sticker, condition) and list membership (native lists and comma-separated attributes), contains for partial text in string fields such as name, ne to exclude a value or element, and gt/gte/lt/lte for typed numeric ranges β€” on semantic_product_search too.
  • Look up attribute names and values with get_category_attributes and get_category_attribute_values before building a filter, so attribute matches the feed exactly β€” and so you know a range-filtered attribute is really numeric.
  • Put SKUs/barcodes in query, not in a filter, and let exact-code boosting do the work.

Don't

  • Don't range-filter attributes whose values don't read as plain numbers ("1 200 Π³Ρ€Π½") β€” those pairs cannot be compared numerically. Bounds may be numbers or numeric strings; both behave identically.
  • Don't use startswith/endswith when case or position is uncertain β€” they are case-sensitive and test the whole stored string; contains is the forgiving option.
  • Don't use contains for list membership or numeric/boolean fields β€” it matches inside words (contains "Neath" matches Rosneath); use eq/in for membership and comparison operators for typed numbers.
  • Don't filter by SKU/vendorcode on semantic search β€” those aren't filterable there.
  • Don't assume a filter that returns [] is a real "no results" β€” on an older catalog it may be a stale index; fix it with a from-scratch reindex (delete & re-add, or ask support).

Test it (over the Product MCP) ​

json
// 1. Discover the exact attribute name + type
{ "tool": "get_category_attributes", "category_id": "skincare_serums" }

// 2. See the real values you can filter on
{ "tool": "get_category_attribute_values",
  "category_id": "skincare_serums", "attribute_name": "brand" }

// 3. Apply an eq filter on semantic search
{ "tool": "semantic_product_search",
  "query": "brightening serum",
  "filters": [ { "attribute": "brand", "operator": "eq", "value": "Numbuzin" } ] }

// 4. Verify a partial product-name match (case-insensitive)
{ "tool": "semantic_product_search",
  "query": "evening dress",
  "filters": [ { "attribute": "name", "operator": "contains", "value": "ASHEN" } ] }

// 5. Confirm range filters via the category tool
{ "tool": "filter_category_products",
  "category_id": "skincare_serums",
  "filters": [ { "attribute": "price", "operator": "lte", "value": 40 } ] }

If step 3 returns [] but step 5 (or get_category_attribute_values) shows the value exists, the catalog's searchable-attributes copy is likely stale β€” fix it with a from-scratch reindex (delete & re-add the integration, or ask MyChatBot support).

See also ​