How to query
This page covers the patterns that apply across EDITED's MCP tools — how to resolve identifiers reliably, how to check data quality before running analytics, and how to pick the right tool for a given question. For the complete tool catalogue with parameters and schemas, see the Reference.
Identifier resolution
Most EDITED query tools expect stable internal identifiers — slugs and integer IDs — rather than free-text names. Resolving these identifiers is a required step before calling any domain query tool, not optional pre-processing.
Resolving retailers: market first
Retailer slugs are not globally unique. The slug for a retailer in one region may not follow a predictable pattern, and passing a retailer name directly to a query tool without first establishing market context risks matching the wrong regional storefront.
The reliable sequence for any retailer-scoped query:
- Call
search_marketsto resolve the market the user cares about - Call
search_retailerswithcountry_codeset to the market's code - Use the returned
slugin downstream query tools
// Step 1 — resolve the market
const marketResult = await client.callTool({
name: "mdmcp-search_markets",
arguments: { query: "UK", search_limit: 1 },
});
const market = JSON.parse(marketResult.content[0].text)[0];
// → { id: "UK", name: "United Kingdom (UK)" }
// Step 2 — resolve the retailer within that market
const retailerResult = await client.callTool({
name: "mdmcp-search_retailers",
arguments: { query: "Zara", search_limit: 1, country_code: market.id },
});
const retailer = JSON.parse(retailerResult.content[0].text)[0];
// → { name: "Zara", slug: "zara", region: { iso_code: "GB", ... }, ... }
// Step 3 — use the slug in your query tool
Resolving other entities
Brands, product categories, markets, and sizing entities follow a simpler pattern — search, take the top result, extract the identifier.
| What you have | Tool to call | Identifier to extract |
|---|---|---|
| Brand name ("Nike") | search_brands | slug |
| Product category ("dresses") | search_product_searches | id |
| Market name ("Germany") | search_markets | id |
| Sizing system ("EU Women's Apparel") | search_size_group | id |
| Individual size ("M", "42") | search_size_options | id |
Brands are global — no market scoping required. The top result from
search_brands is reliable for named brands without additional filtering.
Resolving retailers for the promotions domain
The market-data domain and the messaging/promotions domain use different
retailer identifiers — a slug from mdmcp-search_retailers is not a valid
promo filter. Resolve the retailer again in the messaging domain with
messagingmcp-list_retailers: match the request against the returned
retailer_name, then pass that row's own retailer slug and a region it
reports to the promo tools. Don't carry a market-data slug across the boundary.
Batching
All identifier resolution tools accept either a single string or a list of up to ten strings. When you need to resolve multiple entities for the same query, batch them in a single call — it runs concurrently and saves round-trips.
// Resolve two retailers at once
const result = await client.callTool({
name: "mdmcp-search_retailers",
arguments: {
query: ["Zara", "H&M"],
search_limit: 1,
country_code: "UK",
},
});
const [zaraMatches, hmMatches] = JSON.parse(result.content[0].text);
Once resolved, reuse identifiers within a session rather than calling the resolution tools again for the same entity.
Scoping resolution to a vertical
search_product_searches resolves categories within a vertical, so it takes
the same optional vertical parameter as the market-data query tools. Resolve
categories under the same vertical you intend to query — otherwise the ids you
get back won't match the data you ask for. See
Choosing a vertical below.
Choosing a vertical
Market data covers three verticals — apparel, beauty, and homeware. The
vertical parameter is optional on market_data_options_search,
market_data_table, search_product_searches, and get_retailer_coverage.
Omit it unless the user is explicitly asking about another vertical. When omitted it resolves to the account's default vertical, which is the right behaviour for most queries. When you do set it, set it consistently across every tool in the workflow — resolving a category under one vertical and querying another returns mismatched results.
Entitlements vary by account. All three values appear in every tool's schema, but requesting a vertical the account can't access returns an error rather than an empty result. Check before offering vertical-specific analysis:
const entitlements = await client.callTool({
name: "mdmcp-market_data_entitlements",
arguments: {},
});
// → { verticals: ["apparel", "beauty", "homeware"],
// default_vertical: "apparel", currency: "USD" }
Note the token is homeware, not home. A vertical is a top-level data
segment, not a product category — categories such as dresses or mascara live
within a vertical and are resolved with search_product_searches.
Coverage checking
Before running analytics over a date window, call get_retailer_coverage to
verify that EDITED's data for the retailers in scope is complete and fresh
enough to support the question.
A clean aggregate from market_data_table can be silently wrong if a
retailer had a coverage gap in the date range. The aggregate will not signal
this on its own — it simply returns fewer products without explanation.
get_retailer_coverage answers the question directly.
const coverage = await client.callTool({
name: "mdmcp-get_retailer_coverage",
arguments: {
retailers: ["zara", "hm"],
start_date: "2026-01-01",
end_date: "2026-03-31",
granularity: ["weekly"],
},
});
Results are classified as no_data, low_volume, or high_staleness for
each period. If gaps exist, either narrow the date range, exclude the affected
retailer, or surface the caveat to the user before presenting results.
When coverage checking matters most:
- Any time-windowed trend or comparison query
- Period-over-period comparisons where a gap in one period would skew the delta
- Queries scoped to a single retailer, where a gap has nowhere to average out For a simple snapshot query ("what is Zara's current assortment"), coverage checking adds less value — the query is point-in-time and the user can see whether results look thin.
Picking the right tool
Market data: options vs table
The two Competitive Market Data query tools serve different question shapes.
| Question type | Examples | Use |
|---|---|---|
| Specific products | "Show me Zara's discounted dresses", "What are the cheapest in-stock trainers at H&M" | market_data_options_search |
| Aggregates and analytics | "Average price by retailer", "Share of discounted products this month", "How has product count changed week on week" | market_data_table |
A useful shortcut: if the user would want to see a list of products, use
market_data_options_search. If they would want to see a number, a
percentage, or a chart, use market_data_table.
market_data_table is the more powerful tool for analysis — it supports
breakdowns by up to three dimensions, period-over-period comparisons,
histograms, and percentiles. Use group_by: [] for a global snapshot with
no bucketing.
Research: discovery before drill-down
The Trend & Research tools are designed to be used in sequence. Going straight to a paragraph-level search or a full article read without a discovery step wastes context and often returns less relevant results.
The recommended sequence:
research_analyze_query(optional) — if the user named a relative window ("last quarter") or a topic you'd rather have parsed for you, run it to get back ISO dates and retrieval intent, and pass those to the search tools. It's composable, not required: the search tools accept explicit dates and intent axes directly, so skip it when you already know them.research_article_search— find which reports are relevant. Returns one summary hit per report with areport_id. This is almost always the right first step for a topic query.research_chunk_searchwithreport_ids— drill into specific reports to find the passages that answer the question. More precise than searching the full corpus.research_read_report— only when the user wants to read or summarise a full report. It returns the complete article body, which is a large payload; prefer chunk search when you only need specific passages. For image retrieval,research_image_searchfollows the same pattern: use afterresearch_article_searchand passreport_idsto search within relevant reports rather than the full corpus.
Messaging and promotions: structured and visual together
The messaging and promotions tools are designed to be used together. The
structured promo tools (count_promos, list_promos, aggregate_promos)
give you numbers and records; messaging_search gives you the creative
context those numbers came from; enrich_with_vm bridges them by fetching
the visual context for a known image_id.
A typical pattern: count or aggregate promotions to answer the analytical
question, then use list_promos to surface representative examples, then
enrich_with_vm to show the creative alongside the data.
Calling a tool doesn't require a model
It's easy to assume that because MCP is how AI agents reach EDITED's data, every MCP call has a model deciding which tool to use. It doesn't. MCP is a protocol — a server exposes tools, a client calls them — and nothing about that exchange requires an LLM to be the one choosing the tool or its arguments. Your own code can do that directly, deterministically, every time.
That gives you two ways to call a tool, not one:
- Call it directly, when you already know which tool and which arguments you need. No model involved — same tool, same result, every run.
- Let a model choose, when the right tool or the right arguments genuinely depend on something you only learn at runtime, and it's not practical to write out every case in advance. Default to calling the tool directly when you can. Reserve model-driven tool selection for the cases that actually need judgment — it costs more, runs slower, and won't behave identically twice.
// Known ahead of time -> call the tool directly, no model involved:
const result = await client.callTool({
name: "mdmcp-market_data_table",
arguments: {
retailers: ["zara"],
product_search_id: 138,
metric: "avg_price",
},
});
// Only knowable at runtime -> let a model choose:
const flaggedCategory = "dresses"; // would come from an earlier workflow step
const flaggedRetailer = "zara"; // would come from an earlier workflow step
const response = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "your-model-of-choice", // any MCP-compatible model works here
max_tokens: 1000,
messages: [{
role: "user",
content: `An inventory anomaly was flagged in ${flaggedCategory} for ${flaggedRetailer}. Check competitive pricing context for it.`,
}],
mcp_servers: [{ type: "url", url: EDITED_MCP_URL, name: "edited-mcp" }],
}),
});
Same server, same tool available either way — the difference is who's holding the steering wheel.
Using the server-defined prompts
EDITED ships three server-defined prompts — one per domain — that encode recommended routing and orchestration logic. These are the fastest way to build a well-behaved agent — rather than re-implementing the routing rules in your own system prompt, compose these in and extend from them.
Fetch them at runtime with prompts/get:
const prompt = await client.getPrompt({
name: "mdmcp-market_data_query_guide",
arguments: {},
});
// prompt.messages — prepend to your conversation context
mdmcp-market_data_query_guide
Covers the full workflow for Competitive Market Data queries: how to resolve
filter values using the identifier resolution tools, how to route between
market_data_options_search and market_data_table, and how to read the
inline result envelope including the truncation signal.
Use this as the foundation for any agent that will answer market data questions.
researchmcp-research_orchestration
Covers routing, stop conditions, source attribution, and image-description
rules for the three research search tools (research_article_search,
research_chunk_search, research_image_search). Encodes the
discovery-before-drill-down pattern and the rules for when to stop searching
and synthesise.
Use this as the foundation for any agent that will answer trend or research questions.
messagingmcp-messaging_orchestration
Covers routing, tool budget, lean-query, and provenance-citation rules for the
Messaging & Promotions tools — how to move between messaging_search and the
promo tools (count_promos, list_promos, aggregate_promos,
search_promo_text) and bridge them with enrich_with_vm. Consumer-specific
concerns — persona, output format, citation style — stay your agent's
responsibility.
Use this as the foundation for any agent that will answer messaging or promotions questions.
All three prompts are maintained server-side — when EDITED updates the
guidance, your agent picks it up on the next listPrompts call without a
redeploy. Browse the current prompt content in the Reference.