Search Retailers (Market)
mdmcp-search_retailers
Find retailers to use in filter queries. Search by name, slug, region, or description.
A slug you already hold is a valid query and returns that retailer as
exact — worth knowing because slugs are not always the name: dvf is
Diane Von Furstenberg (US), groceriesatasda-uk is Asda (UK).
Use the returned retailers[].slug value when building retailer filters,
copied exactly — the filter matches it verbatim, case included.
One retailer per country: Zara (ES) and Zara (UK) are separate retailers
with separate data, so a bare Zara is exact on EVERY country it trades in.
Picking one is your job — choose on region, pass country_code, or name the
country in the query (Zara (ES)).
Every hit carries match: exact (query equals its name or slug, ignoring
case, accents, punctuation and spacing; a separator between two digits is kept, so
3-6 months is not 36 months; a region/code suffix on the name is ignored),
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").
Run get_retailer_coverage on the slugs you pick before reporting numbers
from the query tools — that, not match, answers whether data exists.
"Zara", "UK retailers", "fast fashion", "Amazon", "dvf".
Parameters
| Name | Type | Required | Constraints | Description |
|---|---|---|---|---|
query | string | string[] | yes | — | Single query string or list of query strings for batch search. |
search_limit | integer | no | default: 10 · 1–50 | 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. |
country_code | string | no | — | Optional country code to filter by region (e.g., "UK", "US", "ES"). EDITED codes are ISO 3166-1 alpha-2 with two exceptions: the United Kingdom is "UK" (not ISO "GB"; "GB" is accepted and mapped to "UK") and "EU" covers EU-wide retailers. Case-insensitive. |
Returns
- A RetailerSearchResult —
retailersplussearch_limit/ at_search_limit. A batch request returns one result per query, in the- same order as the queries.
Try it
Code examples
- curl
- TypeScript
- Python
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_retailers",
"arguments": {
"query": "Nike",
"search_limit": 10,
"country_code": "UK"
}
}
}'
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({ name: "demo", version: "1.0.0" }, { capabilities: {} });
await client.connect(
new StreamableHTTPClientTransport(new URL("https://mcp.edited.com/mcp"), {
requestInit: { headers: { "x-api-key": process.env.MCP_API_KEY ?? "" } },
}),
);
const result = await client.callTool({
name: "mdmcp-search_retailers",
arguments: {
"query": "Nike",
"search_limit": 10,
"country_code": "UK"
},
});
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
headers = {"x-api-key": os.environ["MCP_API_KEY"]}
async with streamablehttp_client("https://mcp.edited.com/mcp", headers=headers) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool(
"mdmcp-search_retailers",
{"query": "Nike", "search_limit": 10, "country_code": "UK"},
)
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.
{
"retailers": [
{
"name": "Zara (UK)",
"slug": "zara",
"region": {
"id": 561,
"iso_code": "UK",
"name": "United Kingdom"
},
"is_deprecated": false,
"visible": true,
"tier": {
"id": 6,
"name": "Mass",
"slug": "mass"
},
"match": "exact"
},
{
"name": "Zara Home (UK)",
"slug": "zarahome-uk",
"region": {
"id": 561,
"iso_code": "UK",
"name": "United Kingdom"
},
"is_deprecated": false,
"visible": true,
"tier": {
"id": 6,
"name": "Mass",
"slug": "mass"
},
"match": "lexical"
},
{
"name": "La Senza (UK)",
"slug": "lasenza-uk",
"region": {
"id": 561,
"iso_code": "UK",
"name": "United Kingdom"
},
"is_deprecated": false,
"visible": true,
"tier": {
"id": 6,
"name": "Mass",
"slug": "mass"
},
"match": "semantic_only"
}
],
"search_limit": 3,
"at_search_limit": true
}
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"
},
"country_code": {
"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": [
{
"description": "Retailer hits, the applied ``search_limit``, and whether the search filled it.",
"properties": {
"retailers": {
"items": {
"properties": {
"name": {
"type": "string"
},
"slug": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"region": {
"anyOf": [
{
"properties": {
"id": {
"type": "integer"
},
"iso_code": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"id",
"iso_code",
"name"
],
"type": "object"
},
{
"type": "null"
}
],
"default": null
},
"is_deprecated": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"description": "Constant (`false` or absent; ingest filters on it), not an availability signal — use `get_retailer_coverage` for that."
},
"visible": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"description": "Constant (`true`; ingest filters on it), not an availability signal."
},
"tier": {
"anyOf": [
{
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
}
},
"required": [
"id",
"name",
"slug"
],
"type": "object"
},
{
"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": [
"name",
"slug",
"match"
],
"type": "object"
},
"type": "array"
},
"search_limit": {
"minimum": 1,
"type": "integer"
},
"at_search_limit": {
"description": "True if the search filled search_limit. Retailer search is hybrid (lexical + semantic) and the vector arm has no similarity floor, so a full list does NOT mean more matches exist — low-relevance neighbours pad it out, and they are the rows reporting `match: semantic_only`. Raise search_limit (max 50) only if a retailer you expected is missing. `retailers` can be shorter than search_limit while this is true, if a matched record could not be returned (momentarily unavailable, or malformed).",
"type": "boolean"
}
},
"required": [
"retailers",
"search_limit",
"at_search_limit"
],
"type": "object"
},
{
"items": {
"description": "Retailer hits, the applied ``search_limit``, and whether the search filled it.",
"properties": {
"retailers": {
"items": {
"properties": {
"name": {
"type": "string"
},
"slug": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"region": {
"anyOf": [
{
"properties": {
"id": {
"type": "integer"
},
"iso_code": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"id",
"iso_code",
"name"
],
"type": "object"
},
{
"type": "null"
}
],
"default": null
},
"is_deprecated": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"description": "Constant (`false` or absent; ingest filters on it), not an availability signal — use `get_retailer_coverage` for that."
},
"visible": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"description": "Constant (`true`; ingest filters on it), not an availability signal."
},
"tier": {
"anyOf": [
{
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
}
},
"required": [
"id",
"name",
"slug"
],
"type": "object"
},
{
"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": [
"name",
"slug",
"match"
],
"type": "object"
},
"type": "array"
},
"search_limit": {
"minimum": 1,
"type": "integer"
},
"at_search_limit": {
"description": "True if the search filled search_limit. Retailer search is hybrid (lexical + semantic) and the vector arm has no similarity floor, so a full list does NOT mean more matches exist — low-relevance neighbours pad it out, and they are the rows reporting `match: semantic_only`. Raise search_limit (max 50) only if a retailer you expected is missing. `retailers` can be shorter than search_limit while this is true, if a matched record could not be returned (momentarily unavailable, or malformed).",
"type": "boolean"
}
},
"required": [
"retailers",
"search_limit",
"at_search_limit"
],
"type": "object"
},
"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"
]
}
]
}