Skip to main content

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:

  1. Call search_markets to resolve the market the user cares about
  2. Call search_retailers with country_code set to the market's code
  3. Use the returned slug in 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 haveTool to callIdentifier to extract
Brand name ("Nike")search_brandsslug
Product category ("dresses")search_product_searchesid
Market name ("Germany")search_marketsid
Sizing system ("EU Women's Apparel")search_size_groupid
Individual size ("M", "42")search_size_optionsid

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 typeExamplesUse
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:

  1. 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.
  2. research_article_search — find which reports are relevant. Returns one summary hit per report with a report_id. This is almost always the right first step for a topic query.
  3. research_chunk_search with report_ids — drill into specific reports to find the passages that answer the question. More precise than searching the full corpus.
  4. 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_search follows the same pattern: use after research_article_search and pass report_ids to 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.