Skip to content

thebestco/bestprice-shopping

v2.8.1Apache-2.0

Read-only shopping decisions, product search, offers, and price history for Greece.

Changelog

All notable changes to this repository are recorded here. The format follows Keep a Changelog and the package version follows Semantic Versioning. The hosted server has its own version, recorded in server.json; see the Versioning section of the README.

Unreleased

Added

  • An Antigravity plugin in distribution/antigravity/bestprice-shopping/, with the hosted keyless MCP server, the canonical shopping skill, and an always-on read-only pricing rule. It passes agy plugin validate --strict.

Changed

  • Claude's plugin listing uses the name BestPrice, the square 1024×1024 icon, and the public privacy policy. Connecting still means the hosted HTTPS endpoint; the README no longer tells a host to clone the repository and run the stdio bridge.

2.8.1 - 2026-10-29

Security

  • The stdio bridge image is built from Node.js 22.23.4 (the 21 October 2026 security release) instead of 22.23.2.

Changed

  • The Cursor Marketplace manifest uses repository-root paths for its logo, skill, and MCP config, and the root Agent Plugin manifest declares Apache-2.0.
  • Registry and Docker icons use the square 1024×1024 PNG. The README matches the public guide: the ChatGPT plugin is temporarily unavailable, and this package is not on npm.
  • One-click install links for VS Code Insiders and Kiro. CI smoke-tests the live endpoint and rejects invalid skill frontmatter.
  • Directory descriptions share one short line and one long line. Skill frontmatter quotes the description so YAML parsers accept the colon in "BestPrice:".
  • Claude's plugin manifest points mcpServers at ./.mcp.json, so catalogs that read plugin.json see the remote MCP server. A Microsoft 365 Copilot app package and docs/connect.md use the same keyless URL.
  • The required CI job smoke-tests the live endpoint and fails when its version differs from server.json. The Copilot package drops the empty get_shopping_decision argument branch and is regenerated from tools/list.

2.8.0 - 2026-09-26

WebMCP contract 2.8 (bestprice.gr 1a601f6b16, live on www): specification sections in English. The 22 tools and the page lists are 2.6's; every tool is at 2.8.0. Contract 2.7 was a storefront trial it reverted, and has no package release.

Migration

Contract 2.6Contract 2.8
get_product_specifications { section: "Οθόνη" } (Greek titles only)section also takes an English name from the storefront's 40-section table: Display, screen, weight (→ Διαστάσεις), energy (both energy labels) … in any case; «&», «and» and «και» alike.
Rows { section, name, value, truncated? }Rows { section, section_en?, name, value, truncated? }: section_en where the table knows the section; none is guessed for one outside it.
A partial read's sections: ["Οθόνη", "Μνήμη", …] (strings)sections: [{ "section": "Οθόνη", "section_en": "Display" }, { "section": "Μνήμη", "section_en": "Memory" }, …] — a shape change: read entry.section (and entry.section_en) instead of the string.
Refusals naming sections Οθόνη, ΜνήμηΟθόνη (Display), Μνήμη (Memory)

Changed

  • The demo resolves English section names with the storefront's table, returns section_en on rows, lists a partial read's sections as objects (it listed none before), and names sections in both languages when it refuses.
  • The section input's description is the storefront's: «all, or a section name in English or Greek as a previous call returned it, e.g. Display or Οθόνη.»
  • No new dataset: no argument rule or required result property changed, so 16.0.0 grades contract 2.8 as it is.

2.6.0 - 2026-09-26

WebMCP contracts 2.3 to 2.6 (bestprice.gr 7210e5e554, 1bd0f2299f, b4981c7d10, 762f0a4bc7) in one release: the product page's shopper actions and the reads of the shopper's list and comparisons, and a Shopping Brain with structured inputs that only recommends. 22 tools (15 before); pages home 6, listings 11, product 16, every other page 5; every tool at 2.6.0.

Migration

Contract 2.2Contract 2.6
— (2.3)add_to_shopping_list, add_to_comparison, open_price_alert on the product page, for its product (product_id optional and must be it). Outcomes added/unchanged and awaiting_shopper; a full list or comparison is refused as limit_reached. Annotations: not read-only, idempotent, not destructive, not consequential, untrustedContentHint: false.
— (2.4)remove_from_shopping_list, remove_from_comparison: outcomes removed/unchanged, destructiveHint: true.
— (2.5)get_shopping_list (every page, limit 1–20, offset) and get_comparison (product page, offset, three categories a call), both read-only.
get_shopping_decision result statusoutcome alone: clarification (ask clarifying_question), no_match, or the kind of answer.
A budget or must-haves written into get_shopping_decision's messagemax_price_eur (0.01–10,000,000) and must_have (1–6 features, 1–40 characters, no repeats); the tool writes them into the message as «. Budget: up to €. Must have: a, b.». Argument refusals carry reason: invalid_argument.
get_shopping_decision result catalog_candidates, search_url (2.6)Gone: a no_match says nothing fit and names search_bestprice.

PAGE_TOOL_NAMES.product lists get_shopping_list, add_to_shopping_list, remove_from_shopping_list, get_comparison, add_to_comparison, remove_from_comparison and open_price_alert between show_offer and get_shopping_decision; every other page lists get_shopping_list right before get_shopping_decision.

Added

  • The seven tools, implemented by the demo as the storefront runs them, schema-valid against the strict and published contracts: a shopping list of 40 and one comparison of 6 per category, read before and after each change (unchanged both ways, never a toggle), limit_reached, missing_product off a product page, another page's product_id refused (pointing at open_product); the price-drop alert dialog opened once and never saved; the paged reads. New options shoppingList, comparisons and signedIn seed and word them.
  • The source reader follows tool factories — const make = (name, run, annotations = SET) => ({ name, … }) called make('add_to_shopping_list', …) — which is how the storefront registers the shopper actions; the snapshot also records js/modules/webmcp/shopping-list-tool.js.
  • Dataset 16.0.0 grades contract 2.6 and is the default: get_shopping_list and get_comparison join the admitted extra reads, and get_shopping_decision's argument rules take max_price_eur and must_have. 15.0.0 is frozen with its argument rules recorded; runs.v16.json starts empty. The demo passes 16.0.0 (and 15.0.0) with 42 passed and 5 refusals.

Changed

  • The demo's get_shopping_decision composes the budget and must-haves into the message as the storefront does, returns one outcome, no catalog_candidates, and refuses bad arguments with reason: invalid_argument.
  • Descriptions follow the storefront's plain-English rewording (2.6); webmcpContractToolCount is 22.

2.2.0 - 2026-09-25

WebMCP contract 2.2 (bestprice.gr 8d040a161a, live on www): open_search_results opens the address a search returned. The 15 tools and the page lists are unchanged; every tool is at 2.2.0.

Migration

Contract 2.1Contract 2.2
open_search_results { query, min_price_eur?, max_price_eur?, sort?, in_stock_only?, deals_only? }search_bestprice { query, …constraints }, then open_search_results { results_url } with the results_url it returned (it carries the constraints). Any other argument is refused.
open_search_results receipt query, applied, not_appliedRead them from the search_bestprice result; the receipt is { ok, outcome, results_url, page_title, results_kind, unconfirmed_reason, next_tools, next_step, note }.
—open_search_results refuses another origin, a non-results path (anything but /search, /cat/, /b/, /hub/, /item/) and a single-store /item/<id below 2^31> link (store_offer).

Changed

  • open_search_results takes one input, results_url (required); it reads that page first (confirmed) or opens it unread (dispatched, with unconfirmed_reason). The demo implements it: search results addresses now carry their applied constraints, and it opens search, category, brand, hub and product addresses with the storefront's refusals.
  • New descriptions for search_bestprice (and its query: a product name, brand, model or category) and get_shopping_decision (and its message: a described need or budget).
  • Dataset 15.0.0 grades contract 2.2 and is the default: multi-001 and multi-002 search first and open the results_url the search returned (the driver's plans do the same). 14.0.0 is frozen with its argument rules recorded; runs.v15.json starts empty. The demo passes 15.0.0 with 42 passed and 5 refusals.
  • A new search in the demo starts in the results page's default order instead of the current listing's.

2.1.0 - 2026-09-25

WebMCP contract 2.1 (bestprice.gr 8e13c733ab; registration revision 2026-09-25.14): every tool reads or acts, never both. Two tools are added (15), none removed; tools that both read and acted are split, and action results become receipts.

Migration

Contract 2.0Contract 2.1
search_bestprice { query, navigate: true } (the default) — read the results, then moved the tabopen_search_results { query, …constraints } moves the tab and answers with a receipt (outcome, results_url, results_kind, applied/not_applied, next_tools), never the products; read them there with get_visible_products.
search_bestprice { query, navigate: false }search_bestprice { query } — it only reads now. navigate is gone from the schema (the storefront, and the demo, tolerate and ignore it).
search_bestprice result navigated, outcome, next_toolsGone; next_step names open_product and open_search_results.
get_visible_products { load_more: true }load_more_products {} (listing pages), then get_visible_products { offset: <its next_offset> }. A load_more argument is refused with invalid_argument.
open_product result category, current_min_price_eur, offer_count, rating, rating_countget_page_product on the page it opened; open_product returns outcome, product_id, title, bestprice_url, next_tools, note.
Listing action action, applied, dispatched, changedoutcome: confirmed, observed_complete, dispatched, unconfirmed, or unchanged for every former *_already_* action.

get_visible_products and search_bestprice are now readOnlyHint: true; load_more_products is the one non-idempotent action. PAGE_TOOL_NAMES: home 5, listings 10, product page 9, every other public page 4 (open_search_results second on every page; load_more_products right after get_visible_products on listings).

Added

  • open_search_results on every page, and load_more_products on listings — both implemented by the demo, schema-valid against the strict and published contracts: the receipt and its dispatched fallback on an unreadable results page, and a new resultPageSize option that splits a listing into result pages to load.
  • Dataset 14.0.0 grades contract 2.1 and is the default (native runner, evidence audit, deterministic driver): a search whose listing the chain uses becomes open_search_results (multi-001, multi-002); cases no longer require navigated, open_product's facts or the listing actions' action (they require outcome); search_bestprice, read-only now, is an admitted extra read; no navigate or load_more argument. 13.0.0 is frozen with its argument rules recorded; runs.v14.json starts empty. The demo passes 14.0.0 with 42 passed and 5 refusals.
  • conformance.mjs also checks /.well-known/webmcp.json: the same tools, words and schemas, every tool at the contract's version, and the scanner pages hint placed after updated_at and before tools.

Changed

  • Descriptions are one short plain sentence (49–97 characters; the minimum is now 40) that names no tool; a read ends «changes nothing». Every tool is at version 2.1.0.
  • The snapshot reads js/modules/webmcp/annotations.js, where the storefront keeps its annotation sets, and the source reader follows export { a, b } lists and export { a } from re-exports to them.
  • Frozen datasets' tests check required result properties against what later contracts removed (test/helpers/contract-history.js) instead of the live contract alone; webmcpContractToolCount is 15.

2.0.0 - 2026-09-25

WebMCP contract 2.0 (bestprice.gr 2a849a63f1; registration revision 2026-09-25.13). The storefront consolidates the page surface from 16 tools to 13: four tools are removed, one is added. A major version, because code that calls or registers a removed tool breaks.

Migration

Removed in 2.0Use instead
open_visible_product { product_id }open_product { product_id } — any product, from every page, not only a card the page shows. It answers outcome: 'confirmed' with the product page's facts (no action, no nested product), or dispatched with unconfirmed_reason.
get_product_details { product_id, include?, navigate? }open_product { product_id }, then the product page's own reads (get_page_product, compare_page_offers, get_product_specifications, summarize_price_history). There is no read-in-place of another product.
get_listing_sort_options {}get_listing_filters {} — its overview returns sort_options (name, key, selected) and the active sort.
show_price_history {}summarize_price_history { show_chart: true } — the summary plus chart (opened_price_history, focused_price_history or unavailable).

PAGE_TOOL_NAMES is now home 4 (search_bestprice, get_visible_products, open_product, get_shopping_decision), listings 8, product page 8 and every other public page 3 (search_bestprice, open_product, get_shopping_decision). The demo adapter's readSection/sectionTimeoutMs options and its DETAIL_SECTIONS, DETAIL_SECTION_TIMEOUT_MS and readFixtureSection exports are gone with get_product_details; readPage now backs open_product.

Added

  • open_product on every page: it reads /item/<id>/ first and answers confirmed with the page's facts (title, category, price, store count, rating) before the tab moves; an id BestPrice has no page for is refused as not_found and the tab stays; an id below 2^31 — a single store's own offer — is refused as store_offer and never loaded. The demo implements all four answers, schema-valid against the strict and published contracts, with the dispatched fallback behind the injectable destination reader.
  • get_listing_filters returns the sort options and the active sort with the filters overview.
  • Dataset 13.0.0 grades contract 2.0 and is the default (native runner, evidence audit and the deterministic driver): 12.0.0's cases with each removed tool replaced by its successor in chains and required properties, the removed tools dropped from admitted reads, and neg-001 — «open the id a friend sent me», which 1.x refused — graded as open_product succeeding (expects_refusal: false, read by the grader before its id list, so frozen sets grade as before). 12.0.0 is frozen with its argument rules recorded; runs.v13.json starts empty. The demo passes 13.0.0 with 42 passed and 5 refusals.

Changed

  • Every description is one sentence of at most 160 characters, with one wording on every page (no page descriptions); only search_bestprice and get_shopping_decision name another tool, each other.
  • Output schemas: rigid boolean consts (changed, store_offer, more_pages, truncated, …) are plain booleans; next_tools and next steps name the 2.0 tools.
  • The snapshot reads open-product-tool.js in place of product-details-tool.js; webmcpContractToolCount is 13; the native read diagnostic no longer calls get_listing_sort_options.
  • The deterministic driver's scripted plans use the 2.0 tools and run dataset 13.0.0 by default; the frozen datasets grade tools the demo no longer implements, and their tests use recorded results instead.

1.5.0 - 2026-09-25

WebMCP contract 1.9 at the storefront's registration revision 2026-09-25.12 (bestprice.gr 116ed10e75, fd7b2bbb71, 6645a4e1c1). The contract version and the 16 tools are unchanged; several tools take new optional inputs.

Added

  • New optional inputs. compare_page_offers returns up to 12 offers (default 4) and continues with offset, returning offset and next_offset through every offer the page ranks. clear_listing_filters takes filter (and value) to remove one filter or one selected value (removed_filter, filter_already_clear). summarize_price_history takes show_chart to open the chart with the numbers (chart). get_listing_sort_options returns each option's sort key, and apply_listing_sort takes a key or a label.
  • Confirmed navigations. apply_listing_filter, apply_listing_sort and clear_listing_filters read the listing they lead to before the tab moves and answer outcome: 'confirmed', applied: true and destination (its URL, total, applied filters, sort key and first three products); open_visible_product answers opened_visible_product with the product page's own facts (product); a navigating search_bestprice or get_product_details answers confirmed. dispatched, with an unconfirmed_reason, remains only where the destination could not be read first.
  • The demo adapter implements all of it, schema-valid against the strict and published contracts, with an injectable destination reader (readDestination) for the dispatched fallback.
  • Dataset 12.0.0 grades the revision and is the default: 11.0.0's cases with argument rules regenerated (offer offset and limit 12, single-filter removal, show_chart, show_offer without merchant_id); get_visible_products and summarize_price_history stay admitted extra reads with load_more/show_chart admitted false only. 11.0.0 is frozen with its argument rules recorded; runs.v12.json starts empty. The demo passes 12.0.0 with 41 passed and the same 6 refusals.

Changed

  • Input schemas from the generated document. The storefront keeps every input schema in one module and writes it into webmcp-tools.json; the package now takes input schemas from there too (storefront-catalog.js), and contracts.js carries only each tool's annotations and pages. The parity reader checks that every page registers the document's input schema (INPUT_SCHEMAS.<name>), and the snapshot records input-schemas.js.
  • show_offer publishes offer_ref and merchant_name only — one of them, enforced by the tool; no input schema uses anyOf or another combinator. merchant_id is no longer published, and the demo refuses it.
  • get_visible_products (load_more, not idempotent) and summarize_price_history (show_chart) are no longer marked read-only.
  • Every nested output object is typed; repeated offer shapes require their core fields. The published schemas are about two thirds of the strict contract, and the relaxation check admits a nested shape that requires fewer fields than the strict one.

1.4.3 - 2026-09-25

WebMCP contract 1.9 at the storefront's registration revision 2026-09-25.9 (bestprice.gr 2401b434d2). The contract version, the 16 tools and every input are unchanged.

Changed

  • Lean output schemas. Every tool's published output schema is the storefront's lean projection of its strict contract: types, consts, enums, patterns, required fields and the success/refusal oneOf kept; bounds, formats, additionalProperties and non-essential descriptions dropped; objects nested two levels deep published as their type; refusals as ok/error/reason (search and details in full). About half the size; the package publishes them exactly as the storefront does.
  • Strictness kept in the tests. The snapshot also records the storefront's strict contract (webmcp/test/fixtures/storefront-strict-output-schemas.json, from the same module the published schemas come from); every demo result is validated against both, and the parity test checks that each published schema only relaxes the strict one.
  • The product id's input description follows the storefront's wording; the storefront reader passes essential(<text>) through as the text it marks.
  • No new dataset: no argument rule or required result property changed; 11.0.0 stays current (webmcp/evals/QUALIFICATION.md).

1.4.2 - 2026-09-25

WebMCP contract 1.9 as the storefront revised it again (bestprice.gr 21bce127ae; registration revision 2026-09-25.8). The contract version and the 16 tools are unchanged.

Changed

  • get_product_details is on the item page too: the product page registers 9 tools, the details tool right after search_bestprice, with its own wording there (pageDescriptions.product).
  • Tools answer before the tab moves. Every tool that moves or reloads the tab answers first — outcome: 'dispatched', destination_url or bestprice_url, and the next_tools the destination registers — and the navigation starts just after. search_bestprice says results_kind: 'product' when a search lands on one model's own page; get_product_details answers within its deadline with the sections it could read (the rest null, with why), still opens the product with navigate: true when the read failed, and summarizes an excluded unknown-shipping offer as cheapest_merchant. The output schemas are leaner.
  • The demo does all of it: its navigation tools answer before its page changes, a search for one model's full name lands on that product, and get_product_details time-boxes each section (with injectable readPage, readSection and sectionTimeoutMs) — within the published output schemas.
  • No new dataset: the revision changes no argument rule and no required result property, and get_product_details was already an admitted read everywhere; 11.0.0 stays current (recorded in webmcp/evals/QUALIFICATION.md).

1.4.1 - 2026-09-25

WebMCP contract 1.9 as the storefront revised it the same day (bestprice.gr 971aa25d79, b550a849e8; registration revision 2026-09-25.7). The contract version and the 16 tools are unchanged.

Changed

  • search_bestprice narrows by price, stock, deals and order: optional min_price_eur, max_price_eur, sort (relevance, price_asc, price_desc, biggest_price_drop, most_stores, newest), in_stock_only and deals_only; the result reports each requested constraint as applied or not_applied, with why.
  • One product id form everywhere, digits only (^\d{1,20}$): compare_page_offers, get_product_details and open_visible_product share one schema, and the MCP server's bp_<id> is refused with the digits to send.
  • get_product_details can open the product (navigate), so it is annotated as a navigation, not a read.
  • Descriptions follow the storefront's one scannable shape, at most 250 characters, and name only tools their page registers: the item page registers its own wording for search_bestprice and get_shopping_decision (TOOL_DEFINITIONS[name].pageDescriptions, registered by createTools). Input field wording follows the storefront's.
  • Dataset 11.0.0 is the default evaluation set: 10.0.0 with argument rules regenerated from the revision. get_product_details stays an admitted extra read only as a read (navigate: false); the grader now checks number arguments. 10.0.0 is frozen with its first-1.9 argument rules recorded; runs.v11.json starts empty.
  • The demo implements the constraints (its results page offers the two orders its listing renders, and reports the others not_offered), the single id form and navigate, within the published output schemas, and passes 11.0.0 with the same 6 refusals as before.
  • Parity and the release conformance check cover each page's own wording (pages[].descriptions); the storefront reader resolves constants imported through the bundler's aliases and re-exports.

1.4.0 - 2026-09-25

WebMCP contract 1.9, as the BestPrice.gr storefront registers it (bestprice.gr b43f47d55b, after 867fcffe5a).

Added

  • get_product_details — 16 tools. On the home page, listings and every other public page (not the item page, whose own tools cover the product in view), it reads one product by product_id — numeric, or bp_<id> — without moving the tab: its facts, up to four offers ranked by delivered price, key specifications and the price-history summary; include picks the sections. It is read-only.
  • The site page type. Every other public BestPrice page — articles and guides, deals, lists, stores, brands, collections, comparisons, stories — registers search_bestprice, get_product_details and get_shopping_decision. PAGE_TOOL_NAMES.site and createTools({ page: 'site' }) publish it; the home page now registers 5 tools and listings 10.
  • Dataset 10.0.0, the default evaluation set: 9.0.0 graded against contract 1.9 — get_product_details admitted as an extra read in every case (reading a product before opening it no longer fails a chain), and argument rules regenerated from 1.9, whose include list the grader now checks by length and items. 9.0.0 stays frozen, with its 1.8 argument rules recorded; runs.v10.json starts empty. No case starts on a site page yet.

Changed

  • get_shopping_decision returns the page tools' numeric product ids instead of the MCP server's bp_<id>, and search_bestprice names get_product_details among the tools its results page offers; the words and output schemas follow the storefront's.
  • The demo implements both from its fixture, within the published output schemas: get_product_details for any fixture product, and an article page with the site-wide tools. It passes 10.0.0 with 41 passed and the same 6 refusals as before.
  • The storefront reader follows the tool into product-details-tool.js and reads Object.freeze([...]) lists and list spreads (enum: [...DETAIL_SECTIONS]); the page lists fold the storefront's site page type.

1.3.0 - 2026-09-25

WebMCP contract 1.8, as the BestPrice.gr storefront registers it (bestprice.gr e0be10690f).

Added

  • get_shopping_decision on every page — 15 tools. It asks the BestPrice Shopping Brain (the public MCP endpoint's tool of the same name) with the shopper's own words (message, 1–2000 characters) and an optional Greek postal_code (10000–85999), and returns the outcome, the pick with its lowest price before shipping and BestPrice link, up to three alternatives, reasons, tradeoffs, unknowns, and a clarifying question when one is needed. It is read-only and never moves the tab.
  • search_bestprice answers with its results. New optional limit (1–8, default 6) and navigate (default true; false only reads); the result carries the product cards, the results page and its kind, whether the tab moved, and the tools the results page registers.
  • The home page browses its sections: it registers get_visible_products and open_visible_product too (4 tools). Listing pages register 9 tools and item pages 8, each with search first and the Shopping Brain last.
  • Further result pages and named products. get_visible_products takes load_more to load a listing's next result page and reports the pages loaded; compare_page_offers takes the product_id a decision names (bp_<id> or numeric; another product is refused with where to find it), states its ranking_basis, and names the unknown-shipping offer it leaves out; get_product_specifications reads a fact by its common English name.
  • Output schemas. Every tool publishes the storefront's own output schema, a closed oneOf of its success and its refusal; createTools returns it as outputSchema. TOOL_DEFINITIONS and WEBMCP_CONTRACT_VERSION are exported from webmcp/src/contracts.js.
  • Dataset 9.0.0, the default evaluation set: 8.0.0 graded against contract 1.8 — argument rules and admitted reads regenerated from the 1.8 contract, and home-001, home-002, home-005 and listing-012 check the structured search result (results_url, results_kind, products, navigated) instead of action, which 1.8 no longer returns. 1.0.0–8.0.0 stay frozen with their runs; runs.v9.json starts empty.
  • npm run webmcp:snapshot -- <storefront checkout> regenerates the storefront snapshot and webmcp/src/storefront-catalog.js, the words and output schemas the contracts publish.

Changed

  • Every title and description is the storefront's rewritten wording, at most 500 characters (what the tool does, when to use it, what it returns, what it changes), and input field descriptions match what the pages register word for word. Annotations are the storefront's exactly: every tool declares consequentialHint: false, and the read-only page tools carry readOnlyHint/consequentialHint/untrustedContentHint only.
  • Contract parity now covers every field. webmcp/src/contract-parity.js reads each tool's words and output schema from the storefront's generated extra/mcpDiscovery/webmcp-tools.json, its input schema and annotations from the page modules that register it (template literals, regular-expression and string bounds, and imported constants resolved), and each page type's tools from the manifest the storefront's PHP builder renders. The committed snapshot is now storefront-tools.v2.json; the sibling re-check runs on a checkout that contains the snapshot's source commit and names the one it lacks otherwise. The release conformance check also holds the served manifest's tool order, page lists, words and output schemas to the published contract.
  • The demo adapter returns only results its tool's published output schema admits (a new test validates every tool on every page, refusals included), accepts every argument the contracts declare (show_offer.offer_ref was refused), browses the home page's section, and answers get_shopping_decision from its fixture or an injected decide, never the network on its own. It passes dataset 9.0.0: 41 passed, and the same 6 refusals the page makes on 2.0.0.
  • The evaluation driver sets admitted reads aside when it counts a chain, as the grader does, and a scripted run of a case that expects no call ends in a refusal; the grader refuses a non-boolean boolean argument.
  • The native read smoke takes each page's expected tools from the published contract, and an evidence record's implementation fingerprint also covers webmcp/src/storefront-catalog.js, where the tools' words now live.

1.2.8 - 2026-09-25

Fixed

  • The stdio bridge connects again on Node 24, 25 and 26. Since 1.2.1, node stdio.mjs failed every handshake on current Node (undici 7.12 and later): the MCP SDK cancels the empty body of the 202 that answers notifications/initialized, and the UTF-8 response guard reported that cancellation as an upstream stream failure, which aborted the shared upstream connection before tools/list. Hosts saw the fallback bestprice-mcp-stdio server and "This operation was aborted" on every call. A body the consumer discards is no longer a failure; invalid UTF-8, oversize and truncated bodies, and real read errors, are still reported exactly once. Node 20 to 23 were unaffected.

Added

  • CI now also runs the full test suite on the current Node line (26), so a runtime change like undici 7.12 cannot break the bridge unnoticed again.

  • Routing guidance now treats completed shopping decisions and lookup-only searches as terminal for their original intent, preventing redundant BestPrice tool calls while preserving explicit offer/history follow-ups.

  • Gemini Interactions envelope validation now matches the actual four-tool allowlist, with regression coverage.

Added

  • First full measured Claude selection benchmark: the canonical Skill improved exact positive-case routing from 67.12% to 76.71% (+9.59 pp) on the frozen 186-case corpus; full provenance is recorded in docs/selection-results-2026-09-24.md.
  • Matched Anthropic selection runner for tools-only versus canonical-Skill routing on the frozen 186-case corpus, using synthetic read-only tool results so the benchmark cannot create commerce side effects.
  • CI-pinned Cline Marketplace remote-MCP contribution payload for the canonical BestPrice Shopping endpoint.
  • Provider-neutral selection benchmark scorer for actual ChatGPT/Claude/Gemini/Copilot/Grok traces, reporting activation recall, false activation, exact tool routing, optional outcome-quality metrics, and latency percentiles against the frozen 186-case corpus.

Fixed

  • Distribution status is now contract-tested against package/server versions, the four-tool public surface, canonical Skill URL, and the 14-tool WebMCP contract so discovery claims cannot drift silently.
  • Agent Finder metadata now uses the upstream-required owner/repository metadata.sourceSet form.

1.2.7 - 2026-09-24

Added

  • CI-pinned GitHub Agent Finder contribution metadata for the canonical BestPrice Shopping Skill.
  • CI-pinned Docker MCP Registry remote-server payload with Streamable HTTP, no authentication, and no copied tool inventory.
  • Machine-discovery pointers in llms-install.md for ARD, AI Catalog, the server card, official MCP Registry identity, and the verified MCP Skill resource.

Changed

  • Public protocol documentation now describes the live io.modelcontextprotocol/skills extension, skills/list, skills/get, and the third skill://bestprice-shopping/SKILL.md resource.
  • Provider guidance now documents MCP Skill import for OpenAI scanning, canonical root .mcp.json project discovery for Grok/VS Code/Copilot-compatible hosts, and the exact external Agent Finder contribution artifact.

Verification

  • Distribution tests pin the Agent Finder identifier/Skill URL and Docker ecommerce remote-server endpoint while rejecting OAuth or copied dynamic-tool configuration.
  • The full distribution CI passed before this release bump.

1.2.6 - 2026-09-24

Added

  • .agents/skills/bestprice-shopping/SKILL.md mirrors the canonical shopping Skill for agent-compatible repository scanners.
  • opencode.json auto-connects the public BestPrice remote MCP in OpenCode without copying any tool logic.
  • llms-install.md gives agents a compact, provider-neutral installation guide for the public endpoint.
  • Provider setup now includes the Factory Droid marketplace/install path.

Changed

  • Expand the bilingual direct/indirect/negative selection benchmark to 186 cases spanning recommendations, known-product lookup, delivered-price intent, price timing, and out-of-scope negatives.

Verification

  • Manifest tests pin OpenCode to https://mcp.bestprice.gr/mcp, require the agent-compatible Skill mirror, and keep every marketplace/extension version synchronized.
  • The selection corpus is validated for bilingual coverage and routing-class balance before release.

1.2.5 - 2026-09-24

Added

  • Native self-hosted marketplace manifests for GitHub Copilot CLI and Claude Code, both resolving bestprice-shopping to the repository root so they reuse the canonical Agent Plugin, MCP configuration, and Skill.
  • A checked-in lhm.plugin.json describes the hosted four-tool, three-resource BestPrice MCP surface for LobeHub Marketplace submission without relying on crawler inference.
  • A bilingual selection benchmark corpus for direct, indirect, and negative shopping-intent routing.

Changed

  • Hosted MCP Registry metadata now tracks server 1.8.1, the Skills-enabled server that publishes the BestPrice Shopping Skill over MCP alongside the four reviewed shopping tools.
  • Glama metadata now advertises recommendations, shopping decisions, delivered-price comparison, and price history rather than the older lookup-only surface.

Verification

  • Anthropic's Claude Code CLI validates the root plugin and self-hosted marketplace.
  • GitHub Copilot CLI can add this repository as the bestprice marketplace and browse the bestprice-shopping plugin.
  • MCP Registry publisher successfully published gr.bestprice/mcp version 1.8.1.

1.2.4 - 2026-09-24

Added

  • OpenAI portable install-surface metadata under extensions.com.openai, with the same reviewed interface as the Codex compatibility manifest.
  • The Codex compatibility manifest now points explicitly at the canonical ./skills/ directory.

Changed

  • Tighten the BestPrice Shopping Skill trigger around unbranded Greek shopping intent: what to buy, known-product lookup, cheapest delivered price, and price-timing questions, with explicit travel/services exclusions.
  • Re-run Google's official Gemini CLI extension validator whenever the shared skills/ tree changes, not only when the Gemini manifest or context file changes.

Verification

  • Distribution CI remains green with the portable Skill shared by Claude, Cursor, Gemini/Qwen context, Codex compatibility, and the root Agent Plugins package.
  • Gemini CLI 0.61.0 validation remains the provider-native gate for the extension package.

1.2.3 - 2026-09-24

Added

  • A provider-neutral skills/bestprice-shopping/SKILL.md routes unbranded Greek shopping intent to the four reviewed MCP tools and is shared with Cursor.
  • Claude plugin metadata packages the existing remote MCP and the same shopping Skill.
  • A compatibility PROVIDER_SETUP.md keeps old indexed documentation URLs pointed at the current four-tool guide.
  • Gemini extension validation runs with Google's official stable CLI.

Changed

  • Gemini/Qwen context guidance, marketplace metadata, and discovery documentation now describe unbranded recommendation, delivered-price, and price-timing intent explicitly.
  • Discovery documentation now treats ARD, the AI Catalog, the server card, the portable Skill, and the official MCP Registry as complementary distribution surfaces.

1.2.2 - 2026-09-21

Fixed

  • Keep the stdio protocol alive when a host closes its diagnostic stderr pipe, including during startup. Diagnostic failures no longer crash unrelated protocol work.
  • Route broken stdout through the existing bounded shutdown and upstream session cleanup. Preserve a nonzero exit status even when cleanup does not resolve before Node exits.
  • Keep the existing two-second shutdown watchdog, input byte limits and cancellation rules.

Verification

  • Add six real-OS-pipe entrypoint regressions and three separate real-SDK/loopback tests requiring exactly one upstream session DELETE after output loss or ordinary EOF.
  • Require all 75 installed-package tests on Node 20 and Node 22 before a new release.
  • Add a deterministic WebMCP lifecycle soak covering repeated registration, cancellation, sibling isolation, late outcomes, confirmation cleanup and refused stale callbacks.
  • These are bounded stability checks, not proof of all production allocations, external client upgrades, native real-model shopper qualification or memory-leak absence.

1.2.1 - 2026-09-21

Added

  • The item page's seventh WebMCP tool, show_offer: it scrolls the shopper's own tab to one offer the page already renders, marks it for four seconds, and never returns or opens a merchant URL. The surface is now 14 contextual contracts, live on production since 2026-09-11, and the natural-language dataset gains a 47-case v2 that carries every frozen v1 case unchanged.

  • Timestamped Shopping Brain v12 production verification with the full serving revision, sanitized canary results, and explicit limits on what was tested.

  • A release workflow tags every package version that reaches main and creates the GitHub Release from the matching changelog section.

Fixed

  • Validate stdin bytes before SDK parsing, preserve valid UTF-8 exactly, reject malformed or truncated input without logging shopper payloads, and bound every raw stdin frame at 8 MiB.
  • Close validated stdin promptly even while upstream initialization is stalled.
  • Give initialization response streams their own failure and completion lifetime: corrupt, oversized or broken initialization responses fail promptly, and a completed initialization SSE body closes without ending the negotiated session's event stream.
  • Preserve request-local deadlines, cancellation, session recovery and transport cleanup without replaying ambiguous failures or cancelling healthy sibling calls.
  • Keep WebMCP waiter cancellation private, snapshot invocation options once, refuse invalid signals, and adopt accessor-backed thenable results exactly once with their original receiver.

Verification

  • CI and new-version releases test the actual extracted package outside the checkout on Node 20 and Node 22, using the unchanged release lock and offline dependency installation.
  • Installed-package verification includes 72 stdio, UTF-8, framing, SDK and loopback-handshake tests, complete file inventories, runtime hashes and dependency-resolution checks. Releases attach the verified tarball and per-Node receipts after comparing the two tarballs byte for byte.
  • Tag lookup errors fail closed; release checks use genuine Git history. Existing qualification datasets, decision rules, evidence ledgers and benchmark-blind review remain unchanged.
  • These package and lifecycle checks do not certify external-client adoption, all production allocations, native real-model shopper journeys, or Shopping Brain recommendation quality.

1.2.0 - 2026-09-07

Changed

  • The stdio entry point is now a full MCP bridge built on the official SDK client. It forwards the remote server's identity, instructions, and capabilities at initialize, keeps the remote session, relays resources and prompts as well as tools, propagates upstream errors instead of returning an empty tool list, and accepts BESTPRICE_MCP_URL and BESTPRICE_MCP_TIMEOUT_MS.
  • Docker image pins Node 22, runs as the node user, and no longer falls back to an unlocked npm install.
  • WebMCP contracts declare page membership by name instead of array position and carry the full set of safety hints; the demo adapter is split into one handler per tool.
  • All plugin manifests share one description and credit BestPrice as the author.
  • PROVIDER_SETUP.md moved to docs/provider-setup.md; README restructured around a tool table and per-client quick start.

Added

  • Cursor Marketplace plugin (.cursor-plugin/) with an agent skill.
  • glama.json and a Docker-built stdio entry point so Glama can build and score the server.
  • Gemini Interactions API and Genkit examples.
  • The 43-case WebMCP natural-language evaluation dataset.
  • Biome lint and format, .editorconfig, .nvmrc, .dockerignore, Dependabot, a Node 20/22 CI matrix, and npm run test:coverage.
  • Four Shopping Brain review cases in the fixture: typed OIS evidence, optional feature groups, a conversational size correction, and a high-price verdict.
  • Bridge tests against an in-process fake remote and child-process tests for the entry point.
  • Tests for the WebMCP runtime timeout, cancellation, and teardown paths, the demo adapter's validation branches, and the shape of the natural-language evaluation dataset.
  • CONTRIBUTING.md, CODE_OF_CONDUCT.md, issue and pull request templates, and this changelog.
  • SECURITY.md now states scope, a five-business-day acknowledgement target, a 90-day coordinated disclosure window, and a good-faith research statement.

Fixed

  • examples/gemini-interactions.mjs crashed on its own error path by assigning to an imported binding.
  • The Cursor plugin logo path pointed at a directory that does not exist relative to the manifest.
  • The Gemini examples allowed three tools while the extensions publish four.

Removed

  • Internal marketplace submission notes, launch plans, and status logs that were checked into submission/ and CURSOR_MARKETPLACE_SUBMISSION.md. The review fixture moved to test/fixtures/, the screenshots to docs/images/, and the logo to assets/.

1.1.0 - 2026-08-31

Added

  • get_shopping_decision joins the published tool set in every manifest and guide.

1.0.1 - 2026-08-26

Added

  • DeepSeek Harness connection example.

1.0.0 - 2026-08-26

Added

  • Initial public release: Gemini CLI and Qwen Code extensions, Codex plugin, Agent Plugin manifests, official MCP Registry metadata, provider setup guide, and the WebMCP contracts, runtime, and evaluator.