An MCP server for Israeli benefit clubs

Originally published as a LinkedIn post, expanded here.

I built a public MCP server over the benefits catalogues of five Israeli clubs — Behatsdaa and Hever, two Israeli membership benefit clubs, plus the card issuers Isracard, max and Cal — merged into one searchable catalogue of 22,877 offers. I built it because some of those catalogues sit behind a tedious login, and one of them behind an SMS one-time code as well. It turned out to be the cleanest case I have run into for MCP still being worth the effort.

The problem isn’t the benefits, it’s the friction

I genuinely don’t understand why so many membership clubs put their benefits catalogue behind authentication. It stops people from using benefits they already pay for — not because the benefit isn’t worth it, but because they never find out it exists, and the path to finding out is too long.

Plenty of people have tried to fix this. My read is that those attempts died from a combination of not enough public interest and card issuers with no reason to cooperate. There’s the FID app, but I don’t find its search intuitive enough either — and above all, it makes you install an app on your phone. Why isn’t this on the web?

When an MCP server is still the right call

MCP arrived like a storm and then went out of fashion once the built-in web-search tools got good. If the model can just browse to a page and read it, why install a server?

Three conditions. My rule of thumb is that you want at least one of them before the work pays for itself:

  1. The data is behind a wall. No search tool will ever see a catalogue that requires a login.
  2. It’s messy, and reading it takes domain knowledge. “20% off” means something different depending on whether it’s credited to a prepaid card, discounted on your statement, or taken off at the register.
  3. There’s too much of it. 22,877 rows do not fit into a model’s context, and they shouldn’t have to.

This case hits all three. Condition 3 is overkill here, but it is what makes the thing work: the data is filtered deterministically before it ever reaches the model, and the full terms are pulled only for offers already established as relevant.

Flow diagram: five benefit clubs each locked behind a member login, harvested from a signed-in browser session, cleaned and deduplicated into 22,877 deals, embedded into 22,877 semantic vectors, narrowed by the sources the user picks, searched by Claude, and answered with the terms cited.
The path from a locked catalogue to an answer. The yellow step in the middle — picking sources — narrows the search before it even starts. The diagram simplifies: at Isracard, max and Cal the public catalogue needs a real browser, but not a login.

What’s in it

Five organisations, nine source groups. They stay separate because they genuinely behave differently: Hever’s blue card is a network of physical merchants, Behatsdaa’s digital wallet is a monthly top-up budget, and a voucher is a product you buy up front.

Club Groups Offers
Behatsdaa vouchers, digital wallet 16,566
Hever black, yellow and blue cards, vouchers 4,101
Cal experiences store 1,208
max max benefits 682
Isracard Isracard benefits 320

All of it lives in one SQLite database with an FTS5 index over name, category and city. Public catalogue only — balances, monthly top-ups and a card’s last four digits are never stored, and there’s a unit test that pins that.

Harvesting was the dirty part

Not one source was collected with curl. All of them block requests that don’t come from a real browser, and two of them — Behatsdaa and Hever — also needed a signed-in session. Every one was different:

  • Behatsdaa — a private JSON API that rejects calls without an OrganizationId header (the app sends a native one too). There is no bearer token — auth is HttpOnly cookies, and logging in means an ID number followed by an SMS code. The catalogue is a tree you have to walk, and the server throttles: after roughly 1,500 nodes, latency climbs from about 0.6 seconds to about 3 seconds per request, so a full sweep has to be incremental.
  • Hever — the blue card is a single JSON file, for signed-in users only. The yellow card simply exposes the whole array as window.data. The credit network, by contrast, is a WebForms UI with no bulk dataset behind it, so that one is page by page.
  • Isracard — the entire public “benefits for everyone” catalogue is embedded as JSON inside the homepage HTML. One browser fetch is the whole harvest. No login needed, but Cloudflare blocks anything that isn’t a real browser.
  • max — a private JSON API behind an Angular app. Its club and region parameters take the literal string undefined; leave them out and the server returns an empty array with no error at all. That cost me a full pass.
  • Cal — behind a bot-challenge layer. The listing tiles are background images with no text, so names and prices had to come from the individual product pages.

This is the part that never shows up in a demo, and it is most of the work.

The deterministic part

Each of the 22,877 rows is embedded with Titan v2 at 512 dimensions. The result is a single 22,877 × 512 numpy array sitting on disk. A semantic search is one matrix multiply and a sort — brute force is instant at this size, so there is no vector database anywhere in this.

What matters is what doesn’t happen: the catalogue never enters the context. A search returns at most 50 thin rows, and the full terms — the fine print — come back through a separate call, keyed by a specific offer id. The model sees the fine print only after the offer has already been established as relevant.

What this catalogue doesn’t know yet

Offer-level terms exist for Hever only. 1,531 pages were harvested on 28 June 2026, but only 758 of them — the credit network — actually join to catalogue rows and return terms, and in about 97% of those the crediting mechanism isn’t stated on the page at all, because it’s a rule set at the programme level rather than per offer. Behatsdaa has no offer-level terms yet, since they sit behind that same SMS code.

There are holes in the catalogue itself, too. max’s statement-credit discounts never made it in — that endpoint returns nothing without a login. Isracard’s fields that only open up for a signed-in member are empty. So is Cal’s eligibility-gated category. Freshness is uneven as well: part of the catalogue is from July 2026 and part from June. A price or condition in an answer is a starting point for checking the club’s official site, not a replacement for it.

The server itself

Six read-only tools: list_sources, search_promotions, list_categories, semantic_search, get_club_terms, get_offer_terms. The descriptions and schemas come from the same definition the chat agent behind the site is built from — one source of truth, rather than two copies that drift apart.

The transport is stateless streamable HTTP with JSON responses — no session state between calls, and a reply any plain HTTP client can read. There is no auth: it’s a public catalogue and the tools only read.

The one tool that writes, report_issue, is excluded twice — from the tool listing and again at call time. That isn’t belt-and-braces for its own sake: the SDK forwards tool names that were never listed, so the listing filter is a courtesy and the call-time guard is the actual barrier. There’s a test for it.

The whole thing runs on a single t4g.small EC2 instance in eu-central-1 at roughly $14 a month, nginx in front of uvicorn, reaching Bedrock through an IAM role instead of static keys. A capacity limiter of eight concurrent jobs keeps MCP traffic from starving the chat.

Installing it

From Claude Code, one line:

claude mcp add --scope user --transport http yesh-et-ze https://yesh-et-ze.hopala.io/mcp

From the browser: Settings → Connectors → Add → Add custom connector, then paste the same URL.

Claude's settings screen on the Connectors tab, with the Add button circled and a dropdown showing the Add custom connector option circled.
Steps 1 and 2: Connectors → Add → Add custom connector.
The Add custom connector dialog: a name field reading yesh et ze, a URL field containing https://yesh-et-ze.hopala.io/mcp circled, and the Add button circled.
Steps 3 and 4: paste the MCP URL and press Add. No OAuth, no key.

There’s a chat UI too, and it’s closed

Over the same catalogue I also built a Hebrew chat interface, with a source picker and a meter showing the estimated cost of the current conversation in shekels. It’s behind a password at the moment; the MCP endpoint is the public surface.

The source picker in the chat interface: cards for Behatsdaa, Hever, Isracard, max and Cal, each listing its source groups and offer counts, with a meter reading an estimated 0.182 shekels for the conversation.
The source picker. Every box you tick narrows the search before it runs.
A chat answer about discounts and vouchers for Domino's Pizza, listing a Behatsdaa digital-wallet benefit at 20 percent off with a monthly top-up cap, plus a table of regions and cities for Hever's blue card.
One question, two clubs, including the monthly top-up cap and how you actually redeem it.

What I take from this

MCP hasn’t died and it hasn’t won. It’s a tool with clear conditions for use: data behind a wall, that takes knowledge to read correctly, and that there’s too much of to simply paste in. Most data in the world fails all three tests. A fair amount of the data sitting inside a company doesn’t.

If you have an internal system nobody opens because the journey to it is too long, this is how I work — starting with a map of what is genuinely locked and what only looks that way.

Questions people ask

How do I search Israeli credit-card and membership-club benefits in one place?

I built a public MCP server that merges the catalogues of five Israeli clubs — Behatsdaa, Hever, Isracard, max and Cal — into 22,877 offers. You connect it to Claude, either from the CLI or as a custom connector in the browser, and ask in plain language. It carries public catalogue data only, with nothing personal about your wallet or balance.

When is building an MCP server actually worth it, instead of letting the model search the web?

In my view, when the data sits behind authentication so no search tool can reach it; when it is messy enough that reading it correctly takes domain knowledge; and when there is far too much of it to fit in the model's context. A membership-club benefits catalogue ticks all three.

Why are Israeli benefit-club catalogues behind a login and an SMS code?

I do not have a good answer, and that is the point. The friction stops people from using benefits they are already paying for, simply because they never learn the benefits exist. None of the five sources could be collected with curl — every one needs a real browser, and Behatsdaa and Hever also need a signed-in session, Behatsdaa with an SMS code.

What does it cost to run a public MCP server like this?

About $14 a month. It runs on a single t4g.small EC2 instance in eu-central-1 behind nginx and uvicorn, and it reaches Amazon Bedrock through the instance's IAM role rather than static keys.