Inspiration

Chargers, cables, spare brushes: we buy them for things we already own. And the question is always the same. Will it fit? Store chatbots answer it with confidence and no proof. Then the box goes back.

One of us builds a chat consultant for a real electronics store in Ukraine, and shoppers there ask this all the time. We wanted Alexa to answer it the way a good clerk does. Remember what you own. Check the store's own listing. Say "yes, here's where the store says so" or "no, and here's what does fit". Never guess.

What it does

Shop Counter is an Alexa+ add-on for people who own a pile of gadgets.

  • It remembers your devices. Say "I just got an iPhone 15 and a MacBook Air" once. Your device closet belongs to you, not to a store: tell it at Satechi, and Roborock knows it too.
  • It answers fit questions with proof. "Will this charger work with my phone?" You never said which phone. Alexa uses the iPhone 15 from your closet and answers "the store lists your iPhone 15 for it", and the screen shows the line from the store's own listing. If the store lists only "iPhone 17" and you own an iPhone 17 Pro, it says exactly that instead of a yes. Two phones on file and "my phone"? It asks which one.
  • It says no, with a quote and an alternative. Sam asks if an accessory pack fits his Saros 10R. The store's listing says "Not compatible with Saros 10R", so Alexa says no and offers a part the store does list for his robot, $19.99.
  • It finds and compares up to 3 products under a budget, with a reason for each pick, from the live catalog.
  • It orders in two steps. A priced preview first ("Say confirm to buy"), the order only after a yes. Payment is simulated, in the style of Amazon Wallet.
  • It remembers orders. "Where's my order?" works the next day, in a brand new session.
  • It hands off to a person when the question is about discounts, returns or anything the catalog can't answer.

Two real stores run on it today: Satechi (141 products) and Roborock (311 products), read from their public Shopify catalogs. We are not affiliated with either.

Try it in your browser, no install and no keys: https://x2uph6avweit5yuv5crwm474240pwtzb.lambda-url.us-east-1.on.aws/sim/

How we built it

  • MCP server, spec 2025-11-25, Streamable HTTP. TypeScript on the MCP SDK v2 (@modelcontextprotocol/server 2.3.1). Stateless: a fresh McpServer per request, which is what lets it run on Lambda. 9 tools, one per shopper intent: find_products, compare_products, check_compatibility, remember_my_devices, my_devices, prepare_order, place_order, order_status, talk_to_staff. Every tool returns one or two sentences for Alexa to say and structured data for the screen.
  • MCP Apps. 8 of the 9 tools open a screen through @modelcontextprotocol/ext-apps 2.0.3. One HTML file draws all of them in an Echo Show style: product cards, a comparison table, the fit verdict with the store's quote, the order preview, "My devices". Buttons on the screen call tools back ("Place order", "Compare").
  • Agent Skill. skills/shop-counter/SKILL.md tells the Alexa+ model which tool to call for which phrase, how to speak on a screen device, and what it must never invent.
  • No LLM in the server. Compatibility, specs and product types are extracted with rules from the store data. A "yes" exists only when the store names your exact model and there's a literal quote to show; a listing for the series is reported as a series listing. That is why we can promise zero made-up facts.
  • An Echo Show simulator you can open in a browser, because the Alexa+ MCP toolkit isn't available to participants. It's a real MCP client: voice or text in, initialize, tools/list, tools/call over Streamable HTTP, the MCP App in a sandboxed iframe, and a live JSON-RPC log. It is served by the same Lambda at /sim/. Claude Haiku 5.5 plays Alexa, called from the Lambda with a daily spend cap; over the cap a small keyword router takes over so the demo always works. Every visitor gets a private shopper.
  • Account linking with OAuth 2.1. The server is its own small authorization server per the MCP authorization spec: protected resource metadata, PKCE (S256 only), client ID metadata documents and dynamic registration, a "Link Shop Counter to Alexa" consent page, tokens bound to the resource. The demo login stays as a fallback for curl.
  • AWS. Lambda with a Function URL serves the MCP endpoint, the simulator and the model calls; DynamoDB keeps the device closet, orders and the spend counters; CloudWatch and SNS email us at 2,000 calls an hour, switch the server off at 15,000, and an hourly check switches it back on once things calm down.
  • An open library underneath. Shelf to Alexa (https://github.com/DmitriyTopka/shelf-to-alexa) turns any Shopify storefront into the same 9 MCP tools. Roborock was connected with one config entry.
  • Measured, not eyeballed. npm run eval sends 81 real shopper requests through a real MCP client and checks every price, stock flag and quote in every answer against the raw store feed. A second eval runs 21 conversations with the live model.

Challenges we ran into

  • No Alexa+ to test against. We built the simulator first and wrote every assumption about Alexa+ into the Agent Skill.
  • Picking the SDK. The current MCP Apps package doesn't work with the 1.x SDK most examples use, and the v2 docs talk about a newer spec. A spike proved that v2 negotiates 2025-11-25 on the wire before we wrote product code.
  • Store data lies in small ways. Satechi tags USB-C cables as "magsafe charger". Roborock files its F25 and H60 under "Robot Vacuums" though neither is a robot, and lists warranty plans next to robots. Our first eval run caught 2 made-up facts and passed 17 of 39 requests. Fixing the search and compatibility code got it to 51 of 51, then 57 of 57. A second outside review then caught us calling an iPhone 17 tag proof for an iPhone 17 Pro; the fix is a separate "series only" answer. A third review found Roborock titles matched by substring ("for Qrevo Curv" passing as a yes for a plain Qrevo); 13 new cases check the meaning of the quote, and it is 81 of 81 now.
  • The model talks too much. A prompt rule kept Alexa to two sentences in 13 of 18 conversations. We moved the limit into code.
  • A new AWS account can't reserve concurrency, so our cost cap had to work without it.
  • Amazon Bedrock refused every model on our new account ("not available for this account"), so the model that plays Alexa is called through the Anthropic API from the Lambda. The Bedrock path is built and tested behind a flag.
  • Our own security review of the account-linking code found that fetching a client's metadata document could be pointed at internal addresses. It now refuses private addresses, connects only to the address it checked, and stops reading at 5 KB.

The full list, with steps and suggestions, is in the friction log: https://github.com/DmitriyTopka/shop-counter/blob/main/docs/submission/friction_log.md

Accomplishments that we're proud of

  • 81 of 81 shopper requests behave as expected, with 0 fabricated facts against the raw feed; 12 were written after the first fixes as a held-out check, and 11 cover the exact-model rule and device choice.
  • With Claude Haiku 5.5 as Alexa, 19 of 21 live conversations pass every check; it picked the right tool 20 of 21 times. Of the two misses, one answer ran long, and in the other the model checked both remembered phones instead of asking which one (each part of its answer was true). Development, every live eval and the video recordings together cost about $0.10 in API calls (to 2026-10-13).
  • The "no" path works end to end: a refusal quoted from the store, plus a real alternative.
  • One closet, two stores, live on AWS Lambda and DynamoDB since October 12.
  • 174 unit tests across the library, server, view and simulator, none of them touching the network.

What we learned

  • Put hard limits in code. The model followed our tool-routing table almost perfectly and our length rule only most of the time.
  • Test the path as well as the sentence. Haiku once said the right "no" without calling the tool, and our checker passed it.
  • Store tags are part spec sheet, part marketing. Treat a tag as proof only when the tag is the device itself.
  • An honest "the store doesn't list it" is a feature. Shoppers trust a no they can check.

What's next for Shop Counter

  • Real Alexa+ through the MCP toolkit, with a pre-registered confidential client for Alexa account linking next to our public-client OAuth.
  • More catalog formats beyond Shopify: CSV and the YML feeds common in Eastern Europe, starting with the Ukrainian store that inspired this.
  • Shipping cost and delivery dates from the store instead of "before shipping and tax".
  • Interruptions: pause a purchase for a timer, then "OK, order it" picks it back up.

Built With

Share this project:

Updates

Submission history