Skip to main content
Glama

saveon-mcp

An MCP server that gives Claude live prices and stock from one Save-On-Foods store: 9th & Jasper, 10180 109 Street NW, downtown Edmonton. Ask what is on sale this week, search for an ingredient, or have Claude plan dinners from the flyer. It reads the same public storefront API that saveonfoods.com uses, so prices match the website.

It covers one store at a time and is read only. It does not place orders, sign in to More Rewards, or show personalised offers.

What you get

Five tools and one prompt.

  • search_products searches the catalogue with live prices and returns the match count plus a slim product list. Parameters: query, category_id, on_sale_only, sort (relevance, price, price desc), limit, skip. Fields per product: sku, name, price, unit price, on sale, sale end date, availability, category.

  • product_details returns one product by sku: regular and sale price, ingredients with the allergen statement, nutrition facts per serving, country of origin flags and an image URL. Fresh meat and produce usually carry no ingredients or nutrition.

  • price_check prices a whole shopping list in one call. For each item it returns the best match (preferring an on-sale hit), the cheapest match, and an estimated total.

  • find_stores lists Save-On-Foods locations in a city with the store id, address, hours, phone and pickup or delivery availability.

  • list_categories returns the department tree (Meat & Seafood, Fruits & Vegetables, Pantry, and so on) with the ids you pass to search_products.

  • meal_ideas is a prompt that walks Claude through pulling deals per department and proposing priced dinners.

Questions it answers well:

  • What is on sale for dinner this week?

  • Find the cheapest tofu.

  • Everything on sale in Meat & Seafood, cheapest first.

  • Plan three dinners under $20 each from the flyer.

  • Price this list: ground beef, taco kit, shredded cheese, sour cream.

  • Does the Tex Mex cheese contain anything besides milk?

Related MCP server: ai-shopping-list

Setup

You need Python 3.13 or newer and uv.

git clone https://github.com/d3v0psdan/saveonfoods-mcp.git
cd saveonfoods-mcp
uv sync
uv run python check.py   # hits the live API; prints "ok: ..." when the mapping still works

Register it with Claude Code so every project can use it:

claude mcp add -s user saveon-foods -- uv --directory /path/to/saveon-mcp run server.py

For Claude Desktop, add this to claude_desktop_config.json:

{
  "mcpServers": {
    "saveon-foods": {
      "command": "uv",
      "args": ["--directory", "/path/to/saveon-mcp", "run", "server.py"]
    }
  }
}

Restart the client. The tools show up as saveon-foods.

Using a different store

The store is set by the SAVEON_STORE_ID environment variable and defaults to 6613 (9th & Jasper). Any Save-On-Foods location works. To find a store number, list the stores and look at retailerStoreId:

curl -H "X-Site-Host: https://www.saveonfoods.com" \
  "https://storefrontgateway.saveonfoods.com/api/stores?take=300"

Then pass it at registration:

claude mcp add -s user -e SAVEON_STORE_ID=6609 saveon-foods -- uv --directory /path/to/saveon-mcp run server.py

How it works

The website talks to storefrontgateway.saveonfoods.com. The only header the gateway requires is X-Site-Host: https://www.saveonfoods.com. No login, no API key.

The site's own search endpoint, /api/stores/{id}/search, sits behind a Cloudflare challenge and returns 403 to anything that is not a browser. The per-category endpoint, /api/stores/{id}/categories/{categoryId}/search, is open and accepts the same q, sort, skip, take and fpromotions parameters. The server sends every query to that endpoint rooted at the Grocery department (id 30372), which covers the whole store.

fpromotions=True limits results to promoted items. Sale prices are temporary price reductions that run Thursday to Wednesday, and the server reads the end date from the active entry in tprPrice. The promotion index lags a little and returns a few items with no active markdown, so the server drops those when on_sale_only is set. The API caps page size at 100.

Responses are cut down to eight fields per product so a 50 item result stays small enough to reason over.

Files

  • server.py is the whole server: HTTP client, five tools, one prompt.

  • check.py is the smallest check that fails if the API or the field mapping breaks. Run it after any change.

  • pyproject.toml and uv.lock pin the dependencies: mcp and httpx.

Known gaps

  • Search results show the current price only. Call product_details for the regular price of a sale item.

  • price_check runs one search per item, so a 20 item list takes a few seconds.

  • The gateway is unofficial. If Save-On-Foods changes it, check.py is the first thing that will fail.

License

MIT.

Available Tools

5 tools
find_storesB

Save-On-Foods locations in a city with the store id to use as SAVEON_STORE_ID, address, hours, phone and whether pickup or delivery is offered.

Inputs: city. Returns: result

list_categoriesA

List departments under parent_id (default: top-level Grocery departments such as Meat & Seafood, Fruits & Vegetables, Deli & Ready Made Meals). Use the returned ids as category_id in search_products. depth 2 includes sub-departments.

Inputs: depth, parent_id. Returns: result

price_checkA

Price a shopping list in one call. For each item returns the best match (first relevance hit, or the first on-sale hit when prefer_sale is set) and the cheapest available match, plus an estimated total of the best matches. Items with no match are listed under missing.

Inputs: items (required), prefer_sale.

product_detailsA

Full detail for one product by sku (from search_products): regular and sale price, ingredients with allergen statement, nutrition facts per serving, country attributes and image URL. Fresh meat and produce usually carry no ingredients or nutrition.

Inputs: sku (required).

search_productsA

Search what the store stocks right now, with live prices.

query: free text ("chicken thighs", "tofu"); empty lists the whole category. category_id: a department id from list_categories; defaults to all of Grocery. on_sale_only: only items with a current promotion (this week's deals). Returns the API's total match count plus up to limit (max 100) slimmed products; page with skip.

Inputs: skip, sort, limit, query, +2 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 5 tools

    Disambiguation4/5

    Each tool has a distinct primary purpose: search vs. browse categories vs. batch price a list vs. find stores vs. fetch full product detail. The only mild overlap is search_products and price_check, which both return products with prices, but the descriptions clearly separate single-query search from list-wide pricing.

    Naming Consistency4/5

    Four tools follow a verb_noun pattern (search_products, list_categories, price_check, find_stores) while product_details breaks the pattern by being noun-first. The deviation is minor and the intent stays obvious.

    Tool Count5/5

    Five tools is well within the healthy range and each earns its place, covering the natural shopping workflow of browse, search, price, locate store, and inspect detail. Nothing feels redundant or padded.

    Completeness4/5

    The surface covers discovery (search, categories), evaluation (details, price_check) and logistics (find_stores) with no dead ends for a read-only grocery helper. Gaps are minor, such as no per-store stock or cart/order capability, which agents can work around.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers