Skip to main content

Search Product Categories (Market)

mdmcp-search_product_searches

Find product categories to use in filter queries. Search by category name or type.

Use the returned id value — an INTEGER — when building category/product search filters. Filtering on an id selects that category AND its whole subtree. Unlike retailer and brand_slug, product_searches takes no slug: curation_value (sub_cat_jeans_bottoms) is the taxonomy's internal keyword and is NOT a filter value, nor is name or the name_full path. Pass 1302, not "1302".

The categories form a tree, up to three levels deep: type is top_level_category, subcategory or style, and parent_id / parent_name give the level above (name_full is the whole path, and the value a product_searches group-by returns as its row label; it is null, never partial, for the rare record whose ancestor chain is incomplete). Names are NOT unique — three separate categories are called Shorts — so disambiguate on name_full, never on name. Beware Apparel (excl footwear & accessories): it has no parent and no children, so it reads as an ordinary top-level category, but it is a roll-up spanning most of the apparel assortment. Before summing anything across a category breakdown, see market_data_docs(topic="product_searches").

Every hit carries match: exact (query equals its name or name_full, ignoring case, accents, punctuation and spacing; a separator between two digits is kept, so 3-6 months is not 36 months; a pasted id is never compared), lexical (text search ranked it: a typo, a partial, or the name plus or minus a word), or semantic_only (only the vector arm returned it: a nearest neighbour, not a match — verify or discard). Nothing beats semantic_only = not found. No hit is evidence of data behind the name. Rules: market_data_docs(topic="lookup_matching").

Try queries like

"dresses", "mens shoes", "accessories", "outerwear", "tops".

Parameters​

NameTypeRequiredConstraintsDescription
querystring | string[]yes—Single query string or list of query strings for batch search.
search_limitintegernodefault: 10 · 1–50Maximum number of results to return (default 10, max 50). Raise it when validating or comparing many entities in one call so the list is not clipped at the default 10.
verticalstringno—Optional market vertical (apparel | beauty | homeware); resolves from config when omitted. Scopes results to that vertical's categories.

Returns​

  • When query is a string: list[ProductSearchHit]
  • When query is a list: list[list[ProductSearchHit]] with results in same order as queries.

Try it​

Loading interactive widget…

Code examples​

curl -s https://mcp.edited.com/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2025-06-18" \
-H "x-api-key: $MCP_API_KEY" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "mdmcp-search_product_searches",
"arguments": {
"query": "Nike",
"search_limit": 10,
"vertical": "example"
}
}
}'

Example response​

The payload — what you read from result.structuredContent.result. A refusal arrives on the sibling error key instead, with isError still false — see Concepts → Response shape.

[
{
"id": 138,
"name": "Dresses",
"vertical": "apparel",
"type": "top_level_category",
"category": "dresses",
"parent_id": null,
"curation_value": "dresses",
"match": "exact"
},
{
"id": 2956,
"name": "Bodycon",
"vertical": "apparel",
"type": "subcategory",
"category": "dresses",
"parent_id": 138,
"curation_value": "sub_cat_bodycon_dress",
"match": "lexical"
}
]

Input schema​

{
"type": "object",
"properties": {
"query": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"maxItems": 10,
"type": "array"
}
]
},
"search_limit": {
"default": 10,
"description": "Maximum number of results to return (default 10, max 50). Raise it when validating or comparing many entities in one call so the list is not clipped at the default 10.",
"maximum": 50,
"minimum": 1,
"type": "integer"
},
"vertical": {
"description": "Optional. The market vertical (top-level data segment) to search within: `apparel` | `beauty` | `homeware`. NOT a product category. Pass the same vertical you use on the analytics/options tools so discovered slugs/categories match the data you query. When omitted it resolves to the account's default vertical (reported as `default_vertical` by `market_data_entitlements`). Available verticals vary by account — only pass this when the user explicitly asks about a different vertical; otherwise omit it and let the account default apply. Requesting a vertical you're not entitled to returns an error; call `market_data_entitlements` to see yours.",
"enum": [
"apparel",
"beauty",
"homeware"
],
"type": "string"
}
},
"required": [
"query"
]
}

Output schema​

Describes both branches of the envelope — result on success, error on a refusal. Validate against this rather than pattern-matching the prose above; see Concepts → Response shape.

{
"type": "object",
"properties": {
"result": {
"anyOf": [
{
"items": {
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"vertical": {
"type": "string"
},
"type": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"category": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"parent_id": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
]
},
"curation_value": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"parent_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"name_full": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"match": {
"description": "What matched, not how well. Not a score. See the tool description.",
"enum": [
"exact",
"lexical",
"semantic_only"
],
"type": "string"
}
},
"required": [
"id",
"name",
"vertical",
"type",
"category",
"parent_id",
"curation_value",
"match"
],
"type": "object"
},
"type": "array"
},
{
"items": {
"items": {
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"vertical": {
"type": "string"
},
"type": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"category": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"parent_id": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
]
},
"curation_value": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"parent_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"name_full": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"match": {
"description": "What matched, not how well. Not a score. See the tool description.",
"enum": [
"exact",
"lexical",
"semantic_only"
],
"type": "string"
}
},
"required": [
"id",
"name",
"vertical",
"type",
"category",
"parent_id",
"curation_value",
"match"
],
"type": "object"
},
"type": "array"
},
"type": "array"
}
]
},
"error": {
"type": "object",
"description": "Present instead of `result` when the call was rejected. Branch on `code`; never string-match `message`.",
"properties": {
"code": {
"type": "string",
"enum": [
"invalid_input",
"not_entitled",
"upstream_unavailable",
"internal"
]
},
"message": {
"type": "string"
},
"field": {
"type": "string",
"description": "Offending parameter, when the failure is attributable to one."
},
"details": {
"type": "object",
"additionalProperties": true
}
},
"required": [
"code",
"message"
]
}
},
"x-fastmcp-wrap-result": true,
"oneOf": [
{
"required": [
"result"
]
},
{
"required": [
"error"
]
}
]
}