shelfatlas-mcp
ShelfAtlas MCP server
Danish grocery catalog and shelf data as MCP tools. Ask "where is Pepsi Max
cheapest right now?" and get live, structured answers: current offers across
every major Danish chain, nearest-store geo search, product name and EAN
lookup, and a purpose-built find_cheapest_offers tool. Community shelf-stock
signals are included where approved, with confirmation counts.
Endpoint:
https://api.shelfatlas.com/api/v1/mcp(Streamable HTTP)Auth:
Authorization: Bearer sa_live_<your-key>— create a free key at https://app.shelfatlas.comDocs: https://shelfatlas.com/docs (tools, quotas, error codes)
Tools
Tool | What it answers |
| Resolve a product name to id + EAN before calling other tools |
| Look up a product by EAN-13 barcode |
| "Where is this product cheapest right now?" — live offers, cheapest first, chain resolved |
| Catalog offers with price and validity window (live-only by default; chain/EAN/product filters) |
| Paginated store list, or nearest-first geo search |
| All retail chains (id, slug, name) |
Related MCP server: TilbudsTrolden
Claude Desktop
Claude Desktop reaches remote servers through mcp-remote:
{
"mcpServers": {
"shelfatlas": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://api.shelfatlas.com/api/v1/mcp"],
"env": {
"MCP_REMOTE_HEADER_AUTHORIZATION": "Bearer sa_live_<your-key>"
}
}
}
}Clients with native Streamable HTTP support connect directly to the endpoint
with the Authorization header.
Run locally (stdio)
For clients that only speak stdio, this repository is also a small local server that serves the hosted tools over stdio (Node.js 20+):
git clone https://github.com/SlambertDK/shelfatlas-mcp && cd shelfatlas-mcp
npm ci
SHELFATLAS_API_KEY=sa_live_<your-key> node index.jsOr with Docker: docker build -t shelfatlas-mcp . and
docker run -i --rm -e SHELFATLAS_API_KEY=sa_live_<your-key> shelfatlas-mcp.
Listing the tools works without a key; calling them needs SHELFATLAS_API_KEY.
server.json is the manifest for the official MCP registry.
Available Tools
6 toolsfind_cheapest_offersAInspect
Answer 'where is this product cheapest right now?' in one call: the currently-valid offers for one product (by EAN or product id), cheapest first, with chain slug and name resolved. Combine with get_stores(lat/lng, chain_slug) to find the nearest store carrying the winning chain's offer. Self-serve keys see published campaign offers only — not everyday shelf prices, which are Salling-only and restricted to partner keys.
| Name | Required | Description | Default |
|---|---|---|---|
| ean | No | EAN-13 barcode of the product. | |
| limit | No | Max offers (1–50). Default: 20. | |
| product_id | No | ShelfAtlas product id (alternative to ean). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses that results are currently-valid offers only, that they are ordered cheapest first, and critically that self-serve keys see published campaign offers but not everyday shelf prices, which are Salling-only and restricted to partner keys. This is exactly the kind of auth/plan-scoping context an agent needs. It doesn't cover pagination behavior beyond the schema's limit, nor what happens on empty results or invalid identifiers.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the question the tool answers, then the composition pattern with get_stores, then the access caveat. Every sentence earns its place. The first sentence is dense with several ideas packed around a colon, which slightly hurts scannability but not enough to call it verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by sketching the return shape -- offers for one product, cheapest first, chain slug and name resolved -- plus the key access restriction. The main gap is that required_parameters is 0 in the schema, yet the tool clearly needs either ean or product_id; the description never says so, leaving an agent able to call it with neither.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all three parameters are already documented (EAN-13 pattern, UUID product id, 1-50 limit with default 20). The description only restates that the product is identified 'by EAN or product id,' adding little beyond the schema. Baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource -- return currently-valid offers for one product, cheapest first, with chain slug and name resolved -- and frames it as answering 'where is this product cheapest right now?'. It implicitly distinguishes itself from search_catalog_offers through the cheapest-first ordering and single-product scope, but never names the sibling directly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete usage context: use it for a single product's cheapest offer, then combine with get_stores(lat/lng, chain_slug) to find the nearest store carrying the winning chain. It also states the data-visibility constraint for self-serve keys. What's missing is an explicit exclusion -- e.g. 'use search_catalog_offers instead when you want to browse offers across products' -- and a note that at least one of ean/product_id must be supplied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_product_by_eanBInspect
Look up a product in the ShelfAtlas catalog by its EAN barcode.
| Name | Required | Description | Default |
|---|---|---|---|
| ean | Yes | EAN-13 barcode, e.g. "5700382342773". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. 'Look up' weakly implies a safe read, but it says nothing about what happens when the EAN isn't found, whether an error or empty result is returned, or what the response shape looks like (no output schema either).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence with zero filler; the resource and the lookup key come before anything else. Nothing in it is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-parameter lookup with full schema coverage, the description covers the core purpose, but with no annotations and no output schema it leaves the not-found / error behavior entirely unspecified. That is the one thing an agent most needs for an exact-key lookup.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% — the schema already gives the EAN-13 pattern and an example. The description names the parameter domain ('EAN barcode') but adds no format or handling detail beyond what the schema states, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb ('look up') plus resource ('product in the ShelfAtlas catalog') plus key ('by its EAN barcode'), so the agent knows exactly what this does. It doesn't distinguish itself from siblings like search_products or search_catalog_offers, which an agent could easily confuse with an exact-EAN lookup.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'by its EAN barcode' phrasing implicitly frames this as an exact-identifier lookup, which a careful agent can contrast with its search-shaped siblings. However, no explicit when-to-use or when-not-to-use guidance is given, and no alternative is named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_storesAInspect
List stores in the ShelfAtlas catalog. Filter by chain slug, or pass lat/lng for a nearest-first geo search (optionally capped by radius_km; geo results are not paginated).
| Name | Required | Description | Default |
|---|---|---|---|
| lat | No | Latitude for nearest-first search. | |
| lng | No | Longitude for nearest-first search. | |
| limit | No | Max results (1–50). Default: 20. | |
| cursor | No | Pagination cursor from previous response (ignored for geo search). | |
| radius_km | No | Only stores within this many km (requires lat/lng). | |
| chain_slug | No | Chain slug, e.g. "rema". Omit for all chains. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose a genuinely non-obvious trait: geo results are not paginated (and by extension cursor is ignored). It omits auth/permission needs and rate-limit behavior, so it is good but not complete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with what the tool returns, followed by the mode-switching rule. No filler or repetition of schema text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description still does not say what a store record contains or how results are ordered in non-geo mode. Otherwise it covers the mode selection and pagination caveat needed to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns above that by explaining cross-parameter interaction — lat/lng selects geo mode, radius_km optionally caps it, and pagination does not apply in geo mode. It adds real semantics rather than restating field docs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List stores in the ShelfAtlas catalog") and immediately names the two query modes. Sibling tools are all offer/product/chain oriented, but the description never contrasts itself with list_chains, which is the closest potential source of confusion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear per-mode routing: use chain_slug to filter, or pass lat/lng for nearest-first geo search. It does not name an alternative tool or a 'when not to use this' case, so it stops short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_chainsBInspect
List all retail chains available in the ShelfAtlas catalog.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full disclosure burden, yet it only hints that the result is exhaustive via "all". It says nothing about whether the list is paginated, ordered, cached, or whether authentication is required to read the catalog.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single 11-word sentence with the resource front-loaded and zero filler. Nothing to trim and nothing buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a trivial zero-param read the description is minimally sufficient to invoke, but with no output schema and no annotations it leaves the return shape (chain names? IDs? objects with metadata?) and any sibling relationship unexplained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline of 4 applies; there is no parameter semantics to document and the description correctly signals the call is unfiltered.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb + resource: "List all retail chains available in the ShelfAtlas catalog" clearly identifies an enumeration of chain entities. It does not, however, distinguish itself from the sibling get_stores, which an agent could plausibly confuse with a chain-listing operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance, no exclusions, and no mention of the sibling tools (get_stores, search_catalog_offers) that overlap with this one. The zero-parameter signature implies a lookup/reference call, but that is inference rather than stated guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_catalog_offersAInspect
Search catalog offers (promotions and listed products) from Danish retail chains. Returns ONLY currently-valid offers unless include_expired is set. Filter by chain slug, product id, or EAN. Offers carry chainId — resolve names via list_chains. Self-serve keys see published campaign offers (tilbudsaviser, month-campaigns) only — not everyday shelf prices, which are Salling-only and restricted to partner keys.
| Name | Required | Description | Default |
|---|---|---|---|
| ean | No | Filter to offers matched to this EAN-13. | |
| limit | No | Max results (1–50). Default: 20. | |
| cursor | No | Pagination cursor from previous response. | |
| chain_slug | No | Filter to one chain, e.g. "rema". | |
| product_id | No | Filter to offers matched to this product id. | |
| include_expired | No | Include offers past their validity window. Default: false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it discloses the default validity-window filtering, the key-tier scoping (self-serve sees only published campaign offers; everyday shelf prices are Salling-only and partner-restricted), and that results carry chainId requiring resolution. Gaps remain around pagination and rate/limit behavior, though limit/cursor exist in the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four dense sentences, front-loaded with what the tool returns and the default validity behavior, then constraints, then the chainId resolution tip. No filler and nothing repeated from structured fields unnecessarily.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given six optional params, no output schema, and no annotations, the description covers the important hidden context: validity defaults, key-tier access limits, and chainId resolution. It omits pagination mechanics and any hint about result shape, which leaves a small but real gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description restates the chain/product/EAN filter trio that the schema already documents, but it does add genuine nuance that include_expired governs whether past-validity offers appear. That is incremental value, not a full semantic expansion.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb plus resource with scope ('Search catalog offers (promotions and listed products) from Danish retail chains') and states the default validity filter. It does not explicitly distinguish itself from close siblings such as find_cheapest_offers or search_products, so an agent still has to infer which search surface to pick.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It sets clear usage context: default excludes expired offers unless include_expired is set, and it tells the agent to resolve chainId names via list_chains. It also excludes everyday shelf prices for self-serve keys, which is a real usage boundary. It stops short of naming an alternative tool by condition (e.g. when to prefer find_cheapest_offers).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_productsAInspect
Resolve a product NAME to its ShelfAtlas id and EAN — use this BEFORE calling find_cheapest_offers or search_catalog_offers when you only have a product name (e.g. from a user question) and not an id or barcode. Matches on the canonical product name, case-insensitive, substring match. Returns id, name, ean (null for self-serve keys — every EAN is Salling-sourced and restricted to partner keys), and size (volumeMl/unitCount/quantityUnit) where known.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | Product name (or part of it) to search for, e.g. "Pepsi Max 50cl". Minimum 2 characters. | |
| limit | No | Max results (1–20). Default: 10. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden, and it does disclose matching behavior (case-insensitive, substring, canonical name) plus an important scoping caveat that EAN is null for self-serve keys because EANs are Salling-sourced and partner-restricted. It doesn't mention pagination, rate limits, or ordering of results, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and the routing instruction, then matching semantics and return fields. The parenthetical about Salling-sourced EANs is slightly dense but still earns its place; no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema available, the description enumerates the returned fields (id, name, ean, size with volumeMl/unitCount/quantityUnit) so the agent knows what it gets back. Matching rules, prerequisites, and result-field caveats are all covered for a two-parameter lookup tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning: 'q' is matched as a case-insensitive substring against the canonical product name, which the schema property text does not state. The 'limit' parameter is left entirely to the schema, which is acceptable at full coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Resolve a product NAME to its ShelfAtlas id and EAN'. It also names the sibling tools it precedes (find_cheapest_offers, search_catalog_offers), so an agent can distinguish the role without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger condition — use this BEFORE the offer-search tools when you only have a product name, not an id or barcode — and rules out the case where an id or barcode is already known. That directly routes the agent between siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
- First observed
find_cheapest_offers - First observed
get_product_by_ean - First observed
get_stores - First observed
list_chains - First observed
search_catalog_offers - First observed
search_products
TDQS
Scored across 6 tools
Each tool targets a distinct resource: chains, stores, products by EAN, products by name, offers search, and cheapest-offer ranking. The main overlap is between search_catalog_offers and find_cheapest_offers, both returning currently-valid offers; the descriptions differentiate them (general search/filter vs single-product cheapest-first), but an agent could still hesitate.
All tools follow a verb_noun snake_case pattern (list_chains, get_stores, search_products, get_product_by_ean). Minor inconsistency in verb choice for the same concept (search_catalog_offers vs find_cheapest_offers), and qualifier suffixes vary (catalog, by_ean), but the set remains predictable.
Six tools is well-scoped for a retail-catalog/offers domain, with each tool earning its place (chain lookup, store lookup, product resolution, offer search, price comparison). No filler tools and no obvious missing slice of the surface.
The lifecycle is largely covered: chains → stores (with geo) → products (by name and EAN) → offers → cheapest-offer answer, with the intended search_products-then-find_cheapest_offers flow documented. Minor gaps exist, such as fetching a single offer or store by id and browsing product lists, but agents can work around these via the existing filters.
Maintenance
Related MCP Connectors
Product catalogues, prices and stock from online stores and supermarkets.
Live prices, deals & optimal multi-stop shopping routes for German grocery & drug stores.
Compare 18M+ prices across Denmark, Sweden, Norway and Germany: product search, wishlists. No login.
Product search, store prices and price history from Norwegian web shops. Read-only, no login.
Related MCP Servers
- FlicenseAqualityAmaintenanceA Model Context Protocol server for real-time Swiss grocery shopping that searches and compares products across 8 major Swiss retailers (Migros, Coop, Aldi, Denner, Lidl, Farmy, Volgshop, Otto’s), normalizes per-unit prices, surfaces promotions, computes optimal multi-store shopping plans, and works with any MCP-compatible client without API keys or accounts.27132 npm37-
- AlicenseAqualityAmaintenanceAn MCP server for Nordic grocery shopping that finds deals across supermarkets in Denmark, Norway, Sweden, and Finland, plans weekly dinners around cheap ingredients, and generates shopping lists grouped by store.1847MIT
- AlicenseNot gradedqualityCmaintenanceFind discounted food waste from Danish supermarkets (Salling Group) via the Model Context Protocol. Provides tools to search nearby stores or get products by store ID.1MIT
- AlicenseAqualityDmaintenanceMCP server that queries Norwegian grocery store flyers (kundeaviser) to help AI agents plan cheap meals based on current offers.71MIT