_ registry / mcp http-sse · checked 5h ago

fordeal

https://fordeal.ai

Registry code: e42d21ca995afb2f

api record

Fordeal answers one question: where to buy a product cheapest today in Czechia or Slovakia (more countries coming), by the real product price with the shipping shown separately for every offer, and whether the shop can be trusted.

Call find_best_price with the product (text, model, EAN or a product URL) and deliver_to_country. Read verdict, headline, best.total (goods = product price, shipping, total), best.shop.trust and best.captured_at; send the buyer to best.url.

endpoint
https://fordeal.ai/mcp
protocol
http-sse ·2025-06-18
authentication
none observed
public key
none — nobody has proven they own this listing · is it yours? claim it
karma
0 · newcomer
_ is it live, free and safe measured by this hub
Is fordeal live?
Yes — it answered the hub's last check (checked 5h ago). It answered 100% of checks over the last 30 days.
Is fordeal free to use?
Yes — the hub reached it with no key and no payment.
What tools does fordeal have?
55 tools: list_shops, price_history, list_my_favorites, save_favorite, remove_favorite, delete_comparison, delete_list, send_cooperation_inquiry, ….
Is fordeal safe to connect?
The hub found no text in its card or tool descriptions aimed at the agent reading them. It measures what the server answers, not its code — grant it only the access its tools need.
reachable
live
uptime, 30 days
100%

90 days 100%· all time 100%

latency
130ms

last good check

priced tools
0

of 55 tools

_ answered our checks, 90 days 1 checks · signed record
  • unknown → live
_ usage and payments 30 days

Calls placed through this hub's router, from its own receipts. Every caller and every payer counts the same; the chain total is counted from three payers.

accounts
0

through this hub

calls served
0

successful

paid through this hub
0 USDC

what callers paid

_ what it can do 55 tools
3 open 52 never probed 3 of 55 classified

Price is per tool, not per server. An agent whose handshake is open can hold tools that demand a key or a payment, and one figure for the whole agent sends callers into a wall.

  • api_price_breakdown open 5h ago

    What a month of AI API use costs per bill item for every model we compare (or one provider / chosen models): fresh input, input read from the cache, input written into the cache, output, and the total, per request and per month in the price list's currency (USD) and in the buyer's currency by the Czech National Bank rate (fx_date), each item's whole-percent share, every other item the price list names (batch discount and whether it applied, the dearer long-prompt band and whether the request is in it, the context window, cache_write_not_stated when the price list names no write price and writes were billed as ordinary input), what is included, and the official source_url with verified_on. Default scenario: 1 000 requests a month, 1 500 input and 600 output tokens each, 40 % of the input read from the cache and 10 % written; every field can be changed. Nothing is estimated beyond the stated prices.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "batch": {
          "enum": [
            "true",
            "false"
          ],
          "type": "string",
          "description": "Batch processing at the provider's batch discount, where it offers one."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "models": {
          "type": "string",
          "maxLength": 400,
          "description": "Comma-separated plan ids from /digital/plans (category ai-api), e.g. claude-sonnet-5-5."
        },
        "currency": {
          "type": "string",
          "maxLength": 3,
          "minLength": 3,
          "description": "Override the local currency."
        },
        "provider": {
          "type": "string",
          "maxLength": 60,
          "minLength": 2,
          "description": "Only this provider's models (Anthropic, OpenAI, Google, DeepSeek, Mistral, xAI, AI21 Labs, Amazon...), case-insensitive."
        },
        "cache_share": {
          "type": "number",
          "maximum": 1,
          "minimum": 0,
          "description": "Share of the input read from the cache (0-1). Default 0.4."
        },
        "input_tokens": {
          "type": "integer",
          "maximum": 2000000,
          "minimum": 1,
          "description": "Input tokens of one request. Default 1 500."
        },
        "output_tokens": {
          "type": "integer",
          "maximum": 200000,
          "minimum": 1,
          "description": "Output tokens of one request. Default 600."
        },
        "cache_write_share": {
          "type": "number",
          "maximum": 1,
          "minimum": 0,
          "description": "Share of the input written into the cache (0-1, with cache_share at most 1). Default 0.1."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "The buyer's country; decides the local currency."
        },
        "messages_per_month": {
          "type": "integer",
          "maximum": 10000000,
          "minimum": 0,
          "description": "Requests a month. Default 1 000."
        }
      }
    }
    arguments 73 lines
  • compare_energy open 5h ago

    An indicative calculation, not yet checked by an independent expert (verified: false): present the result as an estimate, never as a guaranteed price; show estimate_note (the sentence with the day of the data, in `locale` cs | sk | en) with every result. Household electricity and gas offers (Czechia for now) ranked by the yearly bill for a stated consumption in one distributor's area, with VAT. The bill is split into the regulated part (distribution, system services, renewables support, market operator, tax: set by the energy regulator for the distributor, the same with every supplier) and the supplier part (commodity price and monthly fee: what switching changes). Every offer has the supplier's official price list (source_url, verified_on, valid_from) and says whether the price is fixed (fixed_months or fixed_until) or variable. Spot and formula prices are never ranked; they are listed in not_ranked. Offers whose price list was read only for another distributor's area are left out. Electricity: distributor (cez-distribuce | egd | pre-distribuce), rate (D01d, D02d, D25d, D26d, D27d, D35d, D45d, D56d, D57d, D61d), mwh = yearly high-tariff (or all) consumption, nt_mwh = low-tariff consumption; breaker = main breaker (1x25, 3x10, 3x16, 3x20, 3x25 default, 3x32, 3x40, 3x50, 3x63; it sets the fixed monthly distribution price from the regulator's table); postcode (5 digits) instead of distributor picks the distributor area as an estimate (area.estimate = true; two candidates when the postcode spans an area boundary: then pass distributor). Every result is an estimate (result_type: estimate, guaranteed: false): the binding bill depends on the actual consumption, the distributor stated on the bill and the contract. Gas: distributor (gasnet | gas-distribution | ppd), mwh = yearly consumption up to 63 MWh; postcode instead of distributor picks the gas area the same way (estimate; two candidates around Prague or on an area boundary: then pass distributor). Call without a distributor to get the distributors, rates (rate_info: low-tariff hours a day), products and the regulated price tables. COMPARISON TEMPLATE (20 Oct 2026): every ranked offer carries the forDeal score 0–10 (score, score_parts price / conditions / rating, score_weights as used, score_missing when a part is absent), labels (cheapest = lowest total of the list; best_value = highest score), a one-sentence reason, conditions (fixation months and bucket, term indefinite | fixed_term, notice_months, termination_fee none | stated, green; null = the price list does not state it) and the supplier's public rating (source, score, scale, count, source_url, fetched_on; counted only from 10 reviews; null = we have none, and the weights are renormalised, the answer says so). Filters: fixation none | 12 | 24 | 36 (variable price, or fixed up to 1 / 2 / 3+ years), pricing fixed | variable | spot (spot = market-price products, listed without a total), green true, no_penalty true (no fee for leaving stated); filter_counts says how many offers each chip would leave. sort score (default) | price. compare = up to 3 offer ids: the answer adds comparison with the same parameters side by side. Method and weights: scoring. What the household pays today, best first: current_offer (an id from products), or its own prices current_vt_price + current_nt_price + current_fee_month (current_prices_vat), or current_monthly (the advance); each offer then carries saving_year against it and the answer states saving_basis (offer | own_prices | advance) and warnings (e.g. nt_mwh_missing for a two-tariff rate without low-tariff consumption).

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "mwh": {
          "type": "number",
          "maximum": 63,
          "minimum": 0,
          "description": "Yearly consumption in MWh (electricity: high tariff or all; default 2.5 electricity, 10 gas)."
        },
        "rate": {
          "type": "string",
          "maxLength": 5,
          "description": "Electricity distribution rate, e.g. D02d (default) or D25d (two tariffs)."
        },
        "sort": {
          "enum": [
            "score",
            "price"
          ],
          "type": "string",
          "description": "score (default: forDeal score, highest first) | price (yearly total, lowest first)."
        },
        "green": {
          "type": "string",
          "maxLength": 5,
          "description": "Filter, true: only products whose price list states electricity of renewable origin (none stated yet)."
        },
        "limit": {
          "type": "integer",
          "maximum": 100,
          "minimum": 1
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of estimate_note: cs | sk | en (default en)."
        },
        "nt_mwh": {
          "type": "number",
          "maximum": 63,
          "minimum": 0,
          "description": "Electricity low-tariff consumption a year in MWh (two-tariff rates only)."
        },
        "breaker": {
          "type": "string",
          "maxLength": 8,
          "description": "Electricity main breaker: 1x25 | 3x10 | 3x16 | 3x20 | 3x25 (default) | 3x32 | 3x40 | 3x50 | 3x63."
        },
        "compare": {
          "type": "string",
          "maxLength": 400,
          "description": "Comma-separated offer ids (2–3) for a side-by-side comparison in `comparison`."
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "CZ (default)."
        },
        "pricing": {
          "enum": [
            "fixed",
            "variable",
            "spot"
          ],
          "type": "string",
          "description": "Filter: fixed | variable (price-list products, ranked) | spot (market-price products: listed in not_ranked without a total, never ranked)."
        },
        "fixation": {
          "type": "string",
          "maxLength": 4,
          "description": "Filter, one of none | 12 | 24 | 36: none = variable price without fixation; 12 / 24 / 36 = fixed price up to 1 / 2 / 3 or more years."
        },
        "postcode": {
          "type": "string",
          "maxLength": 8,
          "description": "Postcode of the supply point (e.g. 602 00), electricity or gas; picks the distributor when none is given. An estimate from the post's postcode list and the distributors' coverage by district."
        },
        "commodity": {
          "enum": [
            "electricity",
            "gas"
          ],
          "type": "string",
          "description": "electricity (default) | gas"
        },
        "household": {
          "type": "string",
          "maxLength": 40,
          "description": "Household type (energy v3) instead of rate + consumption: electricity byt | chata | bojler | akumulace | elektromobil | tepelne-cerpadlo | elektricke-topeni; gas plyn-vareni | plyn-voda | plyn-byt | plyn-dum. Sets the rate, a typical yearly consumption and its low-tariff share (stated assumptions, see `households`); mwh overrides the total, rate and nt_mwh override the rest. With current_monthly and no mwh, the consumption is estimated from the payment (consumption_basis: from_monthly)."
        },
        "no_penalty": {
          "type": "string",
          "maxLength": 5,
          "description": "Filter, true: only products whose terms state no fee for leaving (an indefinite term)."
        },
        "distributor": {
          "type": "string",
          "maxLength": 40,
          "description": "Distributor of the place: electricity cez-distribuce | egd | pre-distribuce; gas gasnet | gas-distribution | ppd."
        },
        "current_offer": {
          "type": "string",
          "maxLength": 120,
          "description": "Id of the household's current product from `products` (energy v2): today's yearly total is then priced from that price list for the same need, and saving_year compares like with like (saving_basis: offer). Takes precedence over current_vt_price and current_monthly."
        },
        "current_monthly": {
          "type": "number",
          "maximum": 1000000,
          "minimum": 0,
          "description": "What the household pays today a month with VAT (the current advance), in the country's currency. Each offer then carries saving_year = current_monthly × 12 − total_year (positive = cheaper than today; an estimate)."
        },
        "current_nt_price": {
          "type": "number",
          "maximum": 100000,
          "minimum": 0,
          "description": "Today's low-tariff commodity price per MWh (two-tariff electricity rates; required when nt_mwh > 0)."
        },
        "current_vt_price": {
          "type": "number",
          "maximum": 100000,
          "minimum": 0,
          "description": "Today's commodity price per MWh from the household's bill or price list (electricity: high tariff or all; gas: the gas price). With current_fee_month it gives today's yearly total (saving_basis: own_prices); takes precedence over current_monthly."
        },
        "current_fee_month": {
          "type": "number",
          "maximum": 100000,
          "minimum": 0,
          "description": "Today's monthly fee of the supplier (stálá platba)."
        },
        "current_prices_vat": {
          "enum": [
            "excluded",
            "included"
          ],
          "type": "string",
          "description": "Whether current_*_price and current_fee_month include VAT: excluded (default, as price lists state them) | included (as a bill often shows them)."
        }
      }
    }
    arguments 142 lines
  • cheaper_abroad open 5h ago

    Products whose cheapest total (goods + shipping + FX to `deliver_to_country`) comes from a shop abroad and beats the cheapest domestic offer, with the saving in the deliver-to currency (`saving_kind: "estimate"`: the difference at the prices and shipping captured at `captured_at`, with `saving_basis`; present it as an estimate, never a guaranteed result). Cross-border offers carry EU warranty and returns but support may be in another language; find_best_price shows the `cross_border` block for one product.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "limit": {
          "type": "integer",
          "maximum": 50,
          "minimum": 1
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."
        }
      }
    }
    arguments 23 lines
  • list_shops unknown never probed

    The shops whose prices flow today for a delivery country (with their rating 0..1, rating source and trust label) and the shops still waiting for their feed. Use it to answer "can I trust shop X" or "do you compare shop Y".

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."
        }
      }
    }
    arguments 12 lines
  • price_history unknown never probed

    Daily lowest price of a product across compared shops for up to 365 days (the last point, today, is the product price the product page shows as its main price), plus every current offer with its capture time. `product` is the slug from find_best_price (`product.slug`) or a product id. Use it to say whether today's price is a low, and how much it moved. `price_verdict` {level low|usual|high|short_history|stale, percentile, days, basis} rates the latest price against the last 90 days of our own captured daily lows (no judgement under 14 days; never a discount claim); find_best_price carries the same object. Next: find_best_price for the current recommendation.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "product"
      ],
      "properties": {
        "days": {
          "type": "integer",
          "maximum": 365,
          "minimum": 7,
          "description": "Window in days. Default 365."
        },
        "product": {
          "type": "string",
          "minLength": 1,
          "description": "Product slug or id from find_best_price."
        },
        "currency": {
          "type": "string",
          "maxLength": 3,
          "minLength": 3,
          "description": "Currency of the points. Default: the currency of the first offer."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "Country whose shown price is the last point (today). Default: the country of the currency."
        }
      }
    }
    arguments 32 lines
  • list_my_favorites unknown never probed

    Products (kind product, by slug, with the total saved at that time) and digital plans (kind digital, by plan id) the person saved with the heart, newest first. Needs the person's access token. Live prices: search_products / compare_digital.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {}
    }
    arguments 5 lines
  • save_favorite unknown never probed

    Adds a product (kind product, `id` = slug) or a digital plan (kind digital, `id` = plan id from compare_digital or compare_mobile) to the signed-in person's favourites. Saving twice changes nothing.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "kind",
        "id"
      ],
      "properties": {
        "id": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2
        },
        "kind": {
          "enum": [
            "product",
            "digital"
          ],
          "type": "string"
        }
      }
    }
    arguments 22 lines
  • remove_favorite unknown never probed

    Removes a product or a digital plan from the signed-in person's favourites. `removed: false` when it was not there.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "kind",
        "id"
      ],
      "properties": {
        "id": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2
        },
        "kind": {
          "enum": [
            "product",
            "digital"
          ],
          "type": "string"
        }
      }
    }
    arguments 22 lines
  • delete_comparison unknown never probed

    Deletes one of the signed-in person's saved comparisons; its share link stops working.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "comparison_id"
      ],
      "properties": {
        "comparison_id": {
          "type": "string",
          "maxLength": 64,
          "minLength": 8,
          "description": "The comparison's id from list_my_comparisons."
        }
      }
    }
    arguments 15 lines
  • delete_list unknown never probed

    Deletes one of the signed-in person's lists with its products; its share link stops working. Another id answers not_found.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "list_id"
      ],
      "properties": {
        "list_id": {
          "type": "string",
          "maxLength": 64,
          "minLength": 8,
          "description": "The list's id from list_my_lists."
        }
      }
    }
    arguments 15 lines
  • send_cooperation_inquiry unknown never probed

    The cooperation forms (docs/texty/formulare.md 2–4) without the website. `kind` partner (an affiliate network, a feed provider or a technical integration: organization, website, markets as ISO codes, cooperation_type affiliate | feed | integration | other, message = the offer and its terms), media (name, organization = the newsroom, message = the topic or the information needed, optional deadline YYYY-MM-DD and links) or creator (name or channel, website = the main channel, topic = the content's topic and audience, message = the idea, optional links: other channels, media kit). A shop that wants to be compared uses register_shop instead. A person reads every message; the sender gets a confirmation of receipt (not an approval) and the operator one notice. The same message twice within a day answers the first id with duplicate true. Public, no key; five messages a minute per caller. 503 not_available until migration 0065 is applied.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "kind",
        "name",
        "email",
        "message"
      ],
      "properties": {
        "kind": {
          "enum": [
            "partner",
            "media",
            "creator"
          ],
          "type": "string",
          "description": "Who writes: partner | media | creator."
        },
        "name": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2,
          "description": "The contact person (partner, media) or the name of the channel (creator)."
        },
        "email": {
          "type": "string",
          "format": "email",
          "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
          "maxLength": 200,
          "description": "Where the confirmation and the answer go; never shown."
        },
        "links": {
          "type": "string",
          "maxLength": 1000,
          "description": "Documentation, a feed, the article, other channels or a media kit (links as text)."
        },
        "topic": {
          "type": "string",
          "maxLength": 1000,
          "description": "The creator's topic and audience (required for a creator)."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of the confirmation (cs, sk, en; others get English)."
        },
        "ip_hash": {
          "type": "string",
          "maxLength": 64,
          "description": "sha-256 of the sender's address with a daily salt (the website computes it); counts the per-visitor limit. Never stored as an address."
        },
        "markets": {
          "anyOf": [
            {
              "type": "array",
              "items": {
                "type": "string",
                "maxLength": 2,
                "minLength": 2
              },
              "maxItems": 20
            },
            {
              "type": "string",
              "maxLength": 80
            }
          ],
          "description": "Markets the offer is about, ISO codes (partner, required): an array or a comma-separated string."
        },
        "message": {
          "type": "string",
          "maxLength": 4000,
          "minLength": 10,
          "description": "The offer and its terms (partner), the topic or the information needed (media), the idea (creator)."
        },
        "website": {
          "type": "string",
          "format": "uri",
          "maxLength": 500,
          "description": "The partner's website or the creator's main channel (required for both)."
        },
        "deadline": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "The day the media need an answer by (YYYY-MM-DD)."
        },
        "nickname": {
          "type": "string",
          "maxLength": 200,
          "description": "Leave empty (spam trap: a filled value is discarded quietly)."
        },
        "organization": {
          "type": "string",
          "maxLength": 200,
          "description": "The company or network (partner, required), the newsroom or medium (media, required)."
        },
        "cooperation_type": {
          "enum": [
            "affiliate",
            "feed",
            "integration",
            "other"
          ],
          "type": "string",
          "description": "What a partner offers (required for a partner)."
        }
      }
    }
    arguments 110 lines
  • list_my_comparisons unknown never probed

    Comparisons the person saved (2 to 4 digital plans each), newest first, with the page address and, when the person chose to share one, its share link. Private unless `shared: true`.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        }
      }
    }
    arguments 12 lines
  • compare_internet unknown never probed

    Compare provider-level home internet summaries from docs/data/internet.json. Filter by country, technology, advertised speed, listed monthly price, commitment duration, or provider; sort by price, indicative price per advertised Mbps, or speed. Each result includes the provider's address-availability checker and source links. This source contains summarized ranges, not individual address quotes; unknown values stay null, and availability must be confirmed with the provider.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "country"
      ],
      "properties": {
        "sort": {
          "enum": [
            "price",
            "price_per_mbps",
            "speed"
          ],
          "type": "string"
        },
        "limit": {
          "type": "integer",
          "maximum": 100,
          "minimum": 1
        },
        "offset": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": 0
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."
        },
        "provider": {
          "type": "string",
          "maxLength": 100,
          "minLength": 1
        },
        "max_price": {
          "type": "number",
          "minimum": 0
        },
        "min_price": {
          "type": "number",
          "minimum": 0
        },
        "technology": {
          "enum": [
            "FTTH",
            "FTTB",
            "optical",
            "xDSL",
            "CATV",
            "FWA",
            "other-fixed"
          ],
          "type": "string"
        },
        "min_speed_mbps": {
          "type": "number",
          "maximum": 100000,
          "minimum": 0
        },
        "commitment_months": {
          "type": "integer",
          "maximum": 120,
          "minimum": 0
        }
      }
    }
    arguments 68 lines
  • search_products unknown never probed

    The website's category and search grid for an agent: products with the product price of their shown offer (`lowest_goods`, in the `deliver_to_country` currency; its shipping `lowest_shipping` and the total `lowest_total` beside it, with capture time and `price_status` verified | estimate | incomplete), number of shops, best shop and trust label. Give `query` (free text, every word must match; 8 to 14 digits are an EAN, matched exactly) and/or `category` (a slug from GET /api/v1/deals/categories, e.g. letni-pneumatiky, mobilni-telefony), or neither to browse the whole catalogue (the website's /produkty page), or `slugs` (product slugs) to compare named products side by side; then any filters: price_min/price_max, brand, shops, shop_country (e.g. DE for offers from Germany), in_stock, on_sale, free_shipping, min_shop_rating, min_product_rating, attr (key:value pairs); sort price (lowest product price first, the default), price_desc, total (lowest total with shipping, opt-in; or include_shipping=true), total_desc, discount, shops, popular, rating, score, name. Answers at most `limit` products (default 20) from `offset`; `total_matches` counts every match, and `facets: true` adds the brands, shops, price range and attribute values with counts over the whole filtered list. Next: find_best_price with a product name for the full card with every offer, or price_history with `slug`.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "q": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2,
          "description": "Short name of `query` (the same search; `query` wins when both are given)."
        },
        "attr": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 2000
            },
            {
              "type": "array",
              "items": {
                "type": "string",
                "maxLength": 200
              },
              "maxItems": 50
            }
          ],
          "description": "Attribute filter as `key:value` pairs (comma-separated in a query string, or repeated). The same key twice means any of its values; different keys must all match. Keys and values are those of `facets.attributes` (stored attributes plus storage_gb, ram_gb, diagonal and tyre_size read from the name), e.g. attr=storage_gb:256 GB,storage_gb:512 GB,ram_gb:8 GB."
        },
        "sort": {
          "enum": [
            "relevance",
            "price",
            "price_desc",
            "total",
            "total_desc",
            "discount",
            "shops",
            "popular",
            "rating",
            "score",
            "name",
            "goods",
            "newest"
          ],
          "type": "string",
          "description": "relevance = best match first (the default with `query`; the answer card names the first row), price = lowest product price first (the default without `query`; shipping is shown per product, not counted), price_desc = most expensive product price, total = lowest total with shipping first (opt-in, the same as include_shipping=true), total_desc = highest total with shipping, discount = biggest discount, shops = most shops, popular = most searched and clicked, rating = best rated product (shops' and forDeal reviews, fewer reviews count less), score = forDeal score 0–100 (popularity, shops, price vs. 30 days, shop rating, product rating; each product carries `score.parts`), goods = older name of price, name = alphabetical."
        },
        "brand": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          ],
          "description": "Brand or brands (comma-separated in a query string)."
        },
        "limit": {
          "type": "integer",
          "maximum": 100,
          "minimum": 1
        },
        "query": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2,
          "description": "Free text; every word must appear in the product name. 8 to 14 digits are an EAN (exact match on the product's or an offer's barcode)."
        },
        "shops": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          ],
          "description": "Shop slugs (e.g. datart-cz); a product passes when one of them prices it."
        },
        "slugs": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 4000
            },
            {
              "type": "array",
              "items": {
                "type": "string",
                "maxLength": 200
              },
              "maxItems": 200
            }
          ],
          "description": "Product slugs (comma-separated or an array): only these products, every filter still applies. The website's product comparison (/produkty/porovnat?p=a,b,c) compares up to 4."
        },
        "facets": {
          "type": "boolean",
          "description": "true = also answer `facets` over the WHOLE filtered list, not just this page: brands, shops and shop countries with counts, the price range (min/max total), in_stock/on_sale/free_shipping counts and attribute values with counts. Each facet is counted over the products that pass every other filter, so the counts say what picking that value would give. With `facets` (or `attr`) every product's `attributes` also carries the derived keys (storage_gb, ram_gb, diagonal, tyre_size). `facets.categories` counts the leaf categories of the filtered list, `facets.price_p99` is the total 99 % of products stay under (a slider's upper end), `facets.price_p05` the total 95 % of products are at or above (a robust lower end; one wrong 0 price does not move it)."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "offset": {
          "type": "integer",
          "maximum": 100000,
          "minimum": 0,
          "description": "Rows to skip before `limit` (paging). `total` in the answer is the number of matching products before offset and limit, so offset + count < total means there is another page."
        },
        "on_sale": {
          "type": "boolean",
          "description": "Only products with a shop discount or a measured drop."
        },
        "category": {
          "type": "string",
          "maxLength": 80,
          "minLength": 2,
          "description": "Category slug (leaf, main category or group)."
        },
        "in_stock": {
          "type": "boolean",
          "description": "Only products whose shown offer is in stock."
        },
        "price_max": {
          "type": "number",
          "description": "Highest product price in the deliver-to currency (shipping not counted).",
          "exclusiveMinimum": 0
        },
        "price_min": {
          "type": "number",
          "minimum": 0,
          "description": "Lowest product price in the deliver-to currency (the shown offer's goods price, shipping not counted)."
        },
        "shop_country": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          ],
          "description": "Country codes of the shops (e.g. DE to see offers from Germany)."
        },
        "free_shipping": {
          "type": "boolean",
          "description": "Only products with free delivery at the shown offer."
        },
        "min_shop_rating": {
          "type": "number",
          "maximum": 1,
          "minimum": 0,
          "description": "Lowest rating of the shown shop, 0..1 (0.9 = 90 % / 4.5 stars)."
        },
        "facet_attributes": {
          "type": "boolean",
          "description": "false = facets without `attributes` (the whole catalogue without a category has about 1 800 attribute keys; the website's /produkty asks without them)."
        },
        "include_shipping": {
          "type": "boolean",
          "description": "Order by the total with shipping to `deliver_to_country` instead of the product price (sort=total). Default false."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."
        },
        "min_product_rating": {
          "type": "number",
          "maximum": 1,
          "minimum": 0,
          "description": "Lowest rating of the product itself, 0..1: the shops' own customer reviews and forDeal reviews (0.9 = 90 %)."
        }
      }
    }
    arguments 188 lines
  • find_best_price unknown never probed

    Where to buy a product cheapest today: offers ranked by the real product price (converted to the buyer's currency with a dated rate), the shipping to the buyer's country shown as its own value on every offer, and whether the shop can be trusted. `sort=total` (or include_shipping=true) orders by goods + shipping instead. `query` is free text ("washing machine under 12 000, 60 cm"), a model name, an EAN, or a product URL from any e-shop. Returns one card: `match` (exact | close: close means the nearest product is another variant than the query names, e.g. iPhone 16 Plus for "iPhone 16 256 GB"; `match_note` says how, `warnings` opens with it and `reasons` carries close_match; never present a close card as the asked-for item), verdict (buy_now | wait | buy_alternative | no_offer) with a headline and explanation in `locale`, the recommended offer `best` (shop, trust label verified | rated | unknown, rating 0-1, total.goods = the product price and total.shipping in the deliver-to currency, total.total = their sum, FX date, capture time), `cheapest_total` (the offer with the lowest total including shipping), three alternatives (cheapest domestic, cheapest cross-border, best rated), every shown offer with its blockers and `price_status` (verified = goods + stated shipping, the sum the buyer pays; estimate = the shop states only its lowest "from" shipping rate; incomplete = shipping to the country unknown or import duties open, a lower bound that is never the cheapest), a 90-day price history, and `commission_disclosure`. Every offer carries `labels` (lowest_price = the lowest product price; recommended = `best` when it is dearer than that, never call it the cheapest; lowest_verified_total = the cheapest total with a stated, not "from", shipping), `shipping_is_estimate` (a "from" or unknown shipping: the total is a lower bound) and `saving_is_estimate` (its `savings_vs_best` rests on such a shipping: say estimated, never a certain saving). Rules: a shop on a consumer-protection risk list is never shown; a shop without a rating is never `best`; an offer with unknown shipping or a price older than 36 hours is never `best`. Cross-border offers carry `cross_border` (EU warranty, returns, support languages). Send the buyer to `best.url` (Fordeal's click URL, which forwards to the shop) and tell them the product price, the shipping and the capture time. Next: price_history for the trend, or find_best_price again with verified_only=true.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "query"
      ],
      "properties": {
        "deep": {
          "type": "boolean",
          "description": "Let the model weigh the verdict and write the explanation (adds seconds). Default false: stored prices and the rules answer in under 2 s; `refresh_pending` true means the shops are being asked again in the background."
        },
        "sort": {
          "enum": [
            "product",
            "total"
          ],
          "type": "string",
          "description": "Order of `offers` and the price `best` is chosen by: product = lowest product price (the default; every offer still carries its shipping and total), total = lowest total with shipping to `deliver_to_country`. The card says which in `sort`; `cheapest_total` is the lowest total either way."
        },
        "query": {
          "type": "string",
          "maxLength": 300,
          "minLength": 2,
          "description": "Product name, model, EAN, or a product URL."
        },
        "budget": {
          "type": "number",
          "description": "Budget in the deliver-to currency; a total above it turns the verdict into buy_alternative.",
          "exclusiveMinimum": 0
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "verified_only": {
          "type": "boolean",
          "description": "Only shops with a customer rating."
        },
        "include_shipping": {
          "type": "boolean",
          "description": "Same as sort=total: count shipping in the order (the website's \"Zahrnout dopravu\"). Default false."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "Where the buyer wants delivery (ISO 3166-1 alpha-2). Default: the first compared country."
        }
      }
    }
    arguments 52 lines
  • get_product unknown never probed

    The same card as find_best_price and the website's product page /{locale}/p/{product}, for a product id you already hold (`product.slug` / `product.variant.id` from search_products, find_best_price or product_variants), without reading a query: no risk of landing on another variant. `product.variant` names the variant (storage, colour, model words, connectivity, size, `family_id` shared by its siblings). Answers from stored prices with the rule-based verdict; every offer carries `source_name`, `captured_at`, `blockers`, and the card `reasons` and `warnings`. An unknown id is `error.code` not_found. Next: product_variants for the other capacities or colours, price_history for the trend.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "product"
      ],
      "properties": {
        "ai": {
          "type": "boolean",
          "description": "Also run the shops live and let the model write the verdict (slower). Default false: stored prices and the rules."
        },
        "sort": {
          "enum": [
            "product",
            "total"
          ],
          "type": "string",
          "description": "Order of `offers` and the price `best` is chosen by: product = lowest product price (the default; every offer still carries its shipping and total), total = lowest total with shipping to `deliver_to_country`. The card says which in `sort`; `cheapest_total` is the lowest total either way."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "product": {
          "type": "string",
          "maxLength": 120,
          "minLength": 2,
          "description": "Product slug (the stable product id), e.g. apple-iphone-16-128-gb."
        },
        "verified_only": {
          "type": "boolean",
          "description": "Only shops with a customer rating."
        },
        "include_shipping": {
          "type": "boolean",
          "description": "Same as sort=total: count shipping in the order (the website's \"Zahrnout dopravu\"). Default false."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "Where the buyer wants delivery (ISO 3166-1 alpha-2). Default: the first compared country."
        }
      }
    }
    arguments 47 lines
  • product_variants unknown never probed

    The variants of one product, each with a stable `id` (its product slug), `current` (true for the one asked for, always listed), storage, size, colour and `color_id`, its lowest total for `deliver_to_country` and stock. `family_id` names the set (a garment's item group, or the model line `line:<words>`), `axes` says what tells them apart. Use it to switch from a card to the exact variant the buyer asked for, then get_product with that id. A product without siblings answers itself only. Mirrors GET /api/v1/deals/products/{slug}/variants.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "product"
      ],
      "properties": {
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "product": {
          "type": "string",
          "maxLength": 120,
          "minLength": 2,
          "description": "Product slug (the stable product id)."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."
        }
      }
    }
    arguments 27 lines
  • daily_deals unknown never probed

    Discounts at rated shops today, biggest absolute saving first: with 30 days of our own history for the offer, the discount is measured only against its lowest price in the 30 days before the reduction (EU Omnibus, CJEU C-330/23; discount_basis "lowest_30d", price_before = lowest_30d); until that history exists, only against the old price the shop itself states (discount_basis "shop_stated", not verified by us, at most 50 %). Never an average or other shops' prices. For one country, optionally one category of any level and a minimum percent. for one country and optionally one category slug (from the deal categories). Shops on a risk list and shops without a rating are never included. Each row carries the current price, the previous price, the drop, the shop with its trust label and the capture time. Next: find_best_price with the product name for the full comparison.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "limit": {
          "type": "integer",
          "maximum": 50,
          "minimum": 1
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "Country of the shops. Default: the first compared country."
        },
        "category": {
          "type": "string",
          "description": "Category slug of any level of the tree, e.g. mobily, elektronika, televize."
        },
        "min_percent": {
          "type": "number",
          "maximum": 90,
          "minimum": 0,
          "description": "Only discounts of at least this many percent."
        },
        "stated_only": {
          "type": "boolean",
          "description": "Kept for compatibility; every row carries a struck price (the offer's 30-day low or, until 30 days of history exist, the shop's stated price), with or without it."
        },
        "max_per_shop": {
          "type": "integer",
          "maximum": 50,
          "minimum": 1,
          "description": "Shop diversity: the first 48 rows take the shops in turns, at most this many rows per shop; the rest follows by saving. The website asks 4."
        }
      }
    }
    arguments 37 lines
  • list_coupons unknown never probed

    Coupon codes and promotions of compared shops, valid today, from the affiliate network eHUB (refreshed every 3 hours; never from newsletters or e-mails, never a shop on a risk list). For one country (the shop's country), the soonest ending first. Each row: the shop, `type` voucher (has a `code`) | action (no code), the advertiser's `title`, `discount` read from it (percent or amount with currency; `up_to` = "up to"; null when the text states no size of the discount, never a guess), `min_order` {amount, currency} when the text names a minimum order ("nákup nad 1 000 Kč"; it is never the discount), `valid_from`, `valid_until` (a date = the whole day), `url` the network's tracked link (Fordeal earns a commission on a purchase through it; the ranking never depends on it), `image` the card photo with `image_source` "shop_product" (a product of the shop's own offers in its main `category`) or "category" (our picture of that category; null = none, show `logo_url`), and `fetched_at` of the list. Next: find_best_price with a product name to compare the shop's prices.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "limit": {
          "type": "integer",
          "maximum": 100,
          "minimum": 1
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "Country of the shops. Default: the first compared country."
        }
      }
    }
    arguments 17 lines
  • product_rows unknown never probed

    The rows the website shows above the full product list (/produkty) for a buyer country, each a list of up to 12 products with the same summary fields as search_products: `deals` (today's price drops; discount against the offer's lowest price of the 30 days before the drop when 30 days of its history exist, else against the shop's own stated price; never an average), `trending` (trend = (1 + interest) × 0.5^(age_days / 14), interest = searches, product-page views and shop clicks of the last 30 days, age = days since the product entered the catalogue; 2+ shops only) and the seasonal rows of the buyer country's calendar (Black Friday, Christmas gifts by budget and for whom, Valentine's, Mother's Day, Father's Day, back to school, summer), e.g. `christmas:budget-500` or `christmas:for_her`. No product stands in two rows, one shop is behind at most 3 cards of a row, a row under 4 products is left out. `formulas` states every rule; `seasons` the active windows. `date` (YYYY-MM-DD) reads the calendar of another day with today's products. Next: get_product with a product slug for the full comparison.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "date": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "The day the seasonal calendar is read for (default today)."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."
        }
      }
    }
    arguments 23 lines
  • trending_new_products unknown never probed

    The products the home page's first row shows, found by the data and not by a list of model names: new products people look for, up to 12, each a summary like search_products (total price with shipping at a rated shop, shops, in stock, capture time) plus `trending` with `score`, `parts` (the points of generation, newness, interest, gsc, growth, keyword, seed) and `raw` (model number and its place among the line's generations, days since the family entered the catalogue, decayed interest, Search Console weight, shops that started to list it, variants). A product qualifies when its model number is the newest or the one before in its line (iPhone 18 against iPhone 17), or its model family entered the catalogue in the last 75 days, and someone searched for it, clicked to a shop, found it on Google or a shop started to list it; the score adds model generation 40, newness 10, searches (halved every 7 days over 28 days) and human clicks 25 × log2(1 + n), Search Console 15 × log2(1 + n), new shops 12 × log2(1 + n). Colours and capacities are one card (the cheapest variant); at most 4 cards per category, 3 per brand and 3 per shop. Only products with two or more shops, a rated shop with known shipping and a price in stock; a shop on the ČOI/SOI risk list is never shown. Recomputed by the worker each night; `generated_at` says when, null before the first run. Next: get_product with a product slug for the full comparison.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "limit": {
          "type": "integer",
          "maximum": 12,
          "minimum": 1,
          "description": "Cards to return, at most 12 (default 12)."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."
        }
      }
    }
    arguments 24 lines
  • report_issue unknown never probed

    When an offer on a product page is wrong (the shop's page shows another price, the offer is another variant or product, the link leads to the wrong shop or page, or anything else), file a report: `kind` price | variant | category | shop | other, `product_slug` (the stable product id from find_best_price or search_products), the `offer_id` of the offer (from the card's offers; optional) and a `message` saying what you saw (at most 1000 characters). An optional `email` gets the founder's answer; it is never shown. Every report goes to a queue a person reads; the same report sent twice within a day answers the first id with duplicate true. Public, no key; the anonymous rate limit applies.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "kind",
        "product_slug",
        "message"
      ],
      "properties": {
        "kind": {
          "enum": [
            "price",
            "variant",
            "category",
            "shop",
            "other"
          ],
          "type": "string",
          "description": "What is wrong: the price, the variant or product, the category the product is filed under, the shop or link, or something else."
        },
        "email": {
          "type": "string",
          "format": "email",
          "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
          "maxLength": 200,
          "description": "Where the answer goes. Optional, never shown."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of the answer."
        },
        "ip_hash": {
          "type": "string",
          "maxLength": 64,
          "description": "sha-256 of the reporter's address with a daily salt (the website computes it); the per-visitor limit of five reports a minute counts by it. Never stored."
        },
        "message": {
          "type": "string",
          "maxLength": 1000,
          "minLength": 5,
          "description": "What you saw, e.g. the price on the shop's page and when."
        },
        "website": {
          "type": "string",
          "maxLength": 0,
          "description": "Leave empty (spam trap)."
        },
        "offer_id": {
          "type": "string",
          "format": "uuid",
          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
          "description": "The offer the report is about (offer_id in the card)."
        },
        "page_url": {
          "type": "string",
          "format": "uri",
          "maxLength": 500,
          "description": "The page the report was made on."
        },
        "shop_slug": {
          "type": "string",
          "maxLength": 120,
          "minLength": 2,
          "description": "The shop's slug, when known."
        },
        "product_slug": {
          "type": "string",
          "maxLength": 120,
          "minLength": 2,
          "description": "Product slug (the stable product id)."
        },
        "user_agent_hash": {
          "type": "string",
          "maxLength": 64,
          "description": "sha-256 of the reporter's user agent (the website computes it); only for spotting floods."
        }
      }
    }
    arguments 80 lines
  • report_illegal_content unknown never probed

    A notice under Article 16 of the Digital Services Act that content on fordeal.ai is illegal (a user review, product information, an offer, an image or anything else). Give `content_kind` review | product_info | offer | image | other, the `page_url` of the content (and the `product_slug` when it is on a product page), an `explanation` of why the content is illegal (20–4000 characters), the notifier's `name` and `email`, and `good_faith: true` confirming the notice is accurate and complete to the best of the notifier's knowledge. A person reviews every notice; the e-mail gets a confirmation of receipt at once and the decision later. For a wrong price or variant use report_issue instead. Public, no key; the anonymous rate limit applies.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "content_kind",
        "explanation",
        "name",
        "email",
        "good_faith"
      ],
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2,
          "description": "The notifier's name (Art. 16(2)(c))."
        },
        "email": {
          "type": "string",
          "format": "email",
          "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
          "maxLength": 200,
          "description": "The notifier's e-mail: the confirmation of receipt and the decision go there."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of the confirmation."
        },
        "ip_hash": {
          "type": "string",
          "maxLength": 64,
          "description": "sha-256 of the notifier's address with a daily salt (the website computes it); counts the per-visitor limit."
        },
        "website": {
          "type": "string",
          "maxLength": 0,
          "description": "Leave empty (spam trap)."
        },
        "page_url": {
          "type": "string",
          "format": "uri",
          "maxLength": 500,
          "description": "The exact page of the content (Art. 16(2)(b))."
        },
        "good_faith": {
          "type": "boolean",
          "const": true,
          "description": "Confirms the bona fide belief that the information is accurate and complete (Art. 16(2)(d))."
        },
        "explanation": {
          "type": "string",
          "maxLength": 4000,
          "minLength": 20,
          "description": "Why the content is illegal (Art. 16(2)(a))."
        },
        "content_kind": {
          "enum": [
            "review",
            "product_info",
            "offer",
            "image",
            "other"
          ],
          "type": "string",
          "description": "What content the notice is about."
        },
        "product_slug": {
          "type": "string",
          "maxLength": 120,
          "minLength": 2,
          "description": "Product slug when the content is on a product page."
        }
      }
    }
    arguments 76 lines
  • compare_mobile unknown never probed

    Compare the sourced CZ and SK mobile tariff records in docs/data/mobilni-tarify.json. Filter by country (required), operator, minimum data, unlimited calls, commitment, eSIM and 5G; legacy needs filters for minutes, SMS, no commitment and EU roaming also work. Sort by listed monthly price or the sourced price per GB. Every result includes its source URL, checked date and quote. Unknown values remain null and never satisfy positive filters.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "country"
      ],
      "properties": {
        "sms": {
          "type": "integer",
          "maximum": 100000,
          "minimum": 0
        },
        "esim": {
          "type": "boolean"
        },
        "sort": {
          "enum": [
            "price",
            "price_per_gb"
          ],
          "type": "string"
        },
        "limit": {
          "type": "integer",
          "maximum": 100,
          "minimum": 1
        },
        "five_g": {
          "type": "boolean"
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "CZ | SK; required so results and currency stay within one market."
        },
        "data_gb": {
          "type": "number",
          "maximum": 10000,
          "minimum": 0,
          "description": "GB of mobile data a month (default 0)."
        },
        "minutes": {
          "type": "integer",
          "maximum": 100000,
          "minimum": 0,
          "description": "Call minutes a month (default 0)."
        },
        "operator": {
          "type": "string",
          "maxLength": 80,
          "minLength": 1
        },
        "no_commitment": {
          "type": "boolean",
          "description": "Only tariffs without a contract period."
        },
        "roaming_eu_gb": {
          "type": "number",
          "maximum": 1000,
          "minimum": 0,
          "description": "EU roaming data needed a month."
        },
        "unlimited_calls": {
          "type": "boolean",
          "description": "Filter to tariffs with unlimited calls (true), or explicitly finite calls (false)."
        },
        "commitment_months": {
          "type": "integer",
          "maximum": 120,
          "minimum": 0
        }
      }
    }
    arguments 74 lines
  • compare_digital unknown never probed

    Prices of digital services for a buyer's country, cheapest first, from the providers' official price lists (each row has source_url and verified_on) converted to the buyer's currency by the Czech National Bank rate (fx_date). Categories: ai-chat (ChatGPT, Claude, Gemini, Copilot, Perplexity, Grok, Mistral Vibe, GitHub Copilot, Cursor, Jasper, DeepL… subscriptions), ai-api (price per 1M input and output tokens of the main models: OpenAI, Anthropic, Google, Mistral, xAI, DeepSeek, AI21, Amazon Nova), ai-creative (Midjourney, Runway, Kling, Leonardo, Canva, Firefly, ElevenLabs, Suno… per month, per picture or second of video when stated), streaming, music, vpn, cloud, office (Microsoft 365, Google Workspace, Zoho, Notion, Slack, Zoom… personal, family and business per user; business prices usually exclude VAT), creative (Adobe Creative Cloud, Canva, Figma, CapCut, DaVinci Resolve Studio… monthly, yearly or a one-time purchase: such a row has oneTimeLocal instead of a monthly price), passwords (1Password, Bitwarden, Dashlane). `usage` turns the list into a cost of that use: for ai-api messages_per_month (+ input_tokens and output_tokens per message, default 1 500 and 600) (+ cache_share 0–1 and batch) gives usage_cost a month, usage_breakdown (input, cached input, output; whether the long-prompt band or the batch discount applied) and break_even_messages (below it the API is cheaper than the provider's cheapest paid chat plan); for ai-creative images_per_month and video_seconds_per_month. A null price means the official page did not show one; it is never guessed. Each row carries data_location from the provider's own privacy policy (controller, storedIn country codes, inChina, authoritiesClause, quote, url, checked), null when we have not read it. Where the same plan is also sold inside the app (inAppPrices: the App Store's price for the buyer's country, with VAT, verifiedOn and sourceUrl), inApp compares a month on the web (the price list's price, plus the country's VAT when the list excludes it: web.vatAdded) with a month in the app, both in the buyer's currency: cheaper (web | app | same) and difference a month; inAppYearly does the same for yearly billing. Say both prices and which is cheaper; a plan without inApp has no store price read (never assume the app costs the same). Every row carries price, the one amount to show (the same as fordeal.ai shows): price.monthly and price.yearly (12 × monthly; yearlyWhenYearly = 12 × the month paid yearly) in the buyer currency with the buyer country VAT added where the price list excludes it (price.vat: included | by_law | added | excluded | unknown, price.vatRate), price.billing, price.channel (web) and price.rateDate; rows are ranked by price.monthly. promo (an open promotion) has monthlyLocal as converted and monthlyLocalGross on the same VAT basis as price: show the gross one, then price.monthly after it, both with the VAT word of price.vat. kind says who can buy the plan: regular (anyone), student (verified students or educators), business (companies and teams) or promo (only under the offer terms); never present a non-regular plan as the generic cheapest without saying who is eligible.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "category"
      ],
      "properties": {
        "tier": {
          "enum": [
            "free",
            "basic",
            "standard",
            "pro",
            "premium",
            "max"
          ],
          "type": "string",
          "description": "Only plans of this tier: free | basic | pro | max (AI subscriptions and picture/video tools), basic | standard | premium (streaming, music, VPN, cloud). Compare plans only within one tier."
        },
        "batch": {
          "enum": [
            "true",
            "false"
          ],
          "type": "string",
          "description": "Flat form of usage.batch (true / false)."
        },
        "usage": {
          "type": "object",
          "properties": {
            "batch": {
              "type": "boolean",
              "description": "Batch processing (answers within hours) at the provider's batch discount, where it offers one."
            },
            "cache_share": {
              "type": "number",
              "maximum": 1,
              "minimum": 0,
              "description": "Share of the input read from the provider's cache (0–1), billed at the cached-input price. Default 0."
            },
            "input_tokens": {
              "type": "integer",
              "maximum": 2000000,
              "minimum": 1,
              "description": "Input tokens of one message (prompt + context). Default 1 500."
            },
            "output_tokens": {
              "type": "integer",
              "maximum": 200000,
              "minimum": 1,
              "description": "Output tokens of one answer. Default 600."
            },
            "images_per_month": {
              "type": "integer",
              "maximum": 1000000,
              "minimum": 0
            },
            "messages_per_month": {
              "type": "integer",
              "maximum": 10000000,
              "minimum": 0
            },
            "video_seconds_per_month": {
              "type": "integer",
              "maximum": 1000000,
              "minimum": 0
            }
          },
          "description": "How the buyer uses the service; omit for the plain price list."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "purpose": {
          "enum": [
            "writing",
            "coding",
            "images",
            "voice",
            "video"
          ],
          "type": "string",
          "description": "ai-chat: what the buyer needs it for. coding = plans whose page states an agent or coding tool, images / voice / video = plans whose page states that feature, writing = every plan. A feature the page does not state is 'not stated', not 'no'."
        },
        "category": {
          "enum": [
            "ai-chat",
            "ai-api",
            "ai-creative",
            "streaming",
            "music",
            "vpn",
            "cloud",
            "office",
            "creative",
            "passwords"
          ],
          "type": "string",
          "description": "ai-chat | ai-api | ai-creative | streaming | music | vpn | cloud | office | creative | passwords"
        },
        "currency": {
          "type": "string",
          "maxLength": 3,
          "minLength": 3,
          "description": "Override the currency (e.g. EUR for a Czech buyer)."
        },
        "cache_share": {
          "type": "number",
          "maximum": 1,
          "minimum": 0,
          "description": "Flat form of usage.cache_share."
        },
        "input_tokens": {
          "type": "integer",
          "maximum": 2000000,
          "minimum": 1,
          "description": "Flat form of usage.input_tokens."
        },
        "output_tokens": {
          "type": "integer",
          "maximum": 200000,
          "minimum": 1,
          "description": "Flat form of usage.output_tokens."
        },
        "images_per_month": {
          "type": "integer",
          "maximum": 1000000,
          "minimum": 0,
          "description": "Flat form of usage.images_per_month."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "The buyer's country; decides the currency and the local prices (CZ prices for CZ). Default: the first compared country."
        },
        "messages_per_month": {
          "type": "integer",
          "maximum": 10000000,
          "minimum": 0,
          "description": "Flat form of usage.messages_per_month (REST query strings)."
        },
        "video_seconds_per_month": {
          "type": "integer",
          "maximum": 1000000,
          "minimum": 0,
          "description": "Flat form of usage.video_seconds_per_month."
        }
      }
    }
    arguments 153 lines
  • digital_price_history unknown never probed

    Every recorded change of a digital plan's price, newest first: plan_id, verified_on (the day it changed), from and to (price and currency), source (person = confirmed against the official page in our review; catalog = the stored price list changed between two daily snapshots) and source_url. Recording started on tracking_since; nothing before it is known and nothing is back-filled, so an empty list means no change since tracking_since. An unchanged price renewed by the daily check is no change. Filter by plan (the id from /digital/plans).

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "plan": {
          "type": "string",
          "maxLength": 120,
          "minLength": 2,
          "description": "One plan id from /digital/plans."
        },
        "limit": {
          "type": "integer",
          "maximum": 500,
          "minimum": 1,
          "description": "At most this many changes (default 100)."
        }
      }
    }
    arguments 18 lines
  • compare_energy_from_bill unknown never probed

    An indicative calculation (verified: false, with estimate_note like compare_energy). Pass the values from the household's electricity or gas bill (as read by POST /api/v1/digital/energy/bill, by yourself from the document, or typed by a person) and get the same ranked answer as compare_energy: yearly totals of every priced offer for that distributor area, rate and breaker, with the saving against the bill's own prices (saving_basis: own_prices) or against the monthly advance. Consumption of a billed period other than a year is scaled to 365 days by period_days. Confirm the values with the person before calling; nothing is stored.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "commodity",
        "distributor",
        "vt_mwh"
      ],
      "properties": {
        "rate": {
          "type": "string",
          "maxLength": 5,
          "description": "Electricity distribution rate, e.g. D25d."
        },
        "limit": {
          "type": "integer",
          "maximum": 100,
          "minimum": 1
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of estimate_note: cs | sk | en (default en)."
        },
        "nt_mwh": {
          "type": "number",
          "maximum": 1000,
          "minimum": 0,
          "description": "Low-tariff consumption in MWh in the billed period."
        },
        "vt_mwh": {
          "type": "number",
          "maximum": 1000,
          "minimum": 0,
          "description": "Consumption in MWh in the billed period: high tariff or all (gas: all)."
        },
        "breaker": {
          "type": "string",
          "maxLength": 8,
          "description": "Main breaker, e.g. 3x25."
        },
        "commodity": {
          "enum": [
            "electricity",
            "gas"
          ],
          "type": "string",
          "description": "electricity | gas"
        },
        "fee_month": {
          "type": "number",
          "maximum": 100000,
          "minimum": 0,
          "description": "Supplier's monthly fee without VAT."
        },
        "distributor": {
          "type": "string",
          "maxLength": 40,
          "description": "cez-distribuce | egd | pre-distribuce | gasnet | gas-distribution | ppd"
        },
        "period_days": {
          "type": "integer",
          "maximum": 800,
          "minimum": 1,
          "description": "Days of the billed period (default 365)."
        },
        "nt_price_mwh": {
          "type": "number",
          "maximum": 100000,
          "minimum": 0,
          "description": "Supplier's low-tariff price per MWh without VAT."
        },
        "vt_price_mwh": {
          "type": "number",
          "maximum": 100000,
          "minimum": 0,
          "description": "Supplier's commodity price per MWh without VAT."
        },
        "monthly_advance": {
          "type": "number",
          "maximum": 1000000,
          "minimum": 0,
          "description": "Monthly advance with VAT (used when the prices are missing)."
        }
      }
    }
    arguments 87 lines
  • energy_unit_prices unknown never probed

    An indicative calculation, not yet checked by an independent expert (verified: false); show estimate_note with the result. Price of one kWh with VAT for households of a country (Czechia for now), per distributor area, computed only from the energy regulator's tables and the suppliers' official price lists we read: regulated_kwh (variable regulated part: distribution of the rate, system services, renewables support, tax; the same with every supplier), supplier_kwh (commodity price: min, median, max over the priced offers), marginal_kwh (regulated + supplier: the cost of one more kWh, what an appliance costs to run) and all_in_kwh (the yearly total for `mwh` with every fixed fee spread over its kWh). Electricity for one rate (default D02d) and 2.5 MWh a year by default; gas for 9 MWh a year by default. Spot and formula prices are never counted. Use estimate_appliance_energy for an appliance's yearly cost.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "mwh": {
          "type": "number",
          "maximum": 63,
          "minimum": 0.1,
          "description": "Yearly electricity consumption for all_in_kwh, default 2.5."
        },
        "rate": {
          "type": "string",
          "maxLength": 5,
          "description": "Electricity distribution rate, default D02d."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of estimate_note: cs | sk | en (default en)."
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "CZ (default)"
        },
        "gas_mwh": {
          "type": "number",
          "maximum": 63,
          "minimum": 0.1,
          "description": "Yearly gas consumption for all_in_kwh, default 9."
        }
      }
    }
    arguments 35 lines
  • energy_price_history unknown never probed

    Development of household electricity and gas prices per kWh (Czechia), as published by Eurostat (semi-annual, all taxes and levies included, the most common consumption band), with the dataset link and the day it was fetched; never interpolated. Our own price-list readings start on own_history_since and are not yet a series. Use energy_unit_prices for today's price from the current price lists.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "CZ (default)"
        },
        "commodity": {
          "enum": [
            "electricity",
            "gas"
          ],
          "type": "string"
        }
      }
    }
    arguments 19 lines
  • energy_suppliers unknown never probed

    Facts from the suppliers' official price lists (verified: false: the yearly calculation built on them is not yet checked by an independent expert; estimate_note gives the sentence and the day of the price lists). Every household electricity and gas supplier of a country we know of (Czechia: 46), or one supplier with `id`: its official price-list page, whether we priced it (status priced | gap with the reason), its products with the prices of the official price lists (electricity: commodity price per MWh by rate and the monthly fee; gas: price and fee by consumption band; all without VAT, with source_url, valid_from and verified_on), whether each price is fixed and until when, and the bill guide (bill_guide: the customer portal and the steps to find and download the bill, from the supplier's own help page). Former suppliers (e.g. Bohemia Energy) are listed with what happened to their customers. No contract can be signed here and no link earns a commission.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "id": {
          "type": "string",
          "maxLength": 60,
          "description": "Supplier id from the list, e.g. cez-prodej."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of the bill guide steps: cs | sk | en (default en)."
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "CZ (default)"
        }
      }
    }
    arguments 23 lines
  • estimate_appliance_energy unknown never probed

    An estimate (verified: false, estimate_note with the day of the prices). kind fridge: label_kwh_year from the EU energy label (kWh/annum). kind washer: kwh_per_100_cycles from the EU energy label and washes_per_week (default 4). kind heating: area_m2 and heat_need_kwh_m2 (specific heat need for heating from the building's energy performance certificate; references: passive house 20, low-energy house 50 kWh/m² a year by ČSN 73 0540-2), source direct | heat_pump | gas_boiler with scop (heat pump, default 3) or efficiency (gas boiler, default 0.9). Answers kWh a year and the yearly and monthly cost at the price of one more kWh (median marginal price in the distributor area from energy_unit_prices, or price_per_kwh if given); `defaults` names every value that was assumed.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "kind"
      ],
      "properties": {
        "kind": {
          "enum": [
            "fridge",
            "washer",
            "heating"
          ],
          "type": "string"
        },
        "scop": {
          "type": "number"
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of estimate_note: cs | sk | en (default en)."
        },
        "source": {
          "enum": [
            "direct",
            "heat_pump",
            "gas_boiler"
          ],
          "type": "string"
        },
        "area_m2": {
          "type": "number"
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "CZ (default)"
        },
        "efficiency": {
          "type": "number"
        },
        "distributor": {
          "type": "string",
          "maxLength": 40,
          "description": "Distributor area for the price (default: the first area with priced offers)."
        },
        "price_per_kwh": {
          "type": "number",
          "maximum": 100,
          "minimum": 0,
          "description": "Own price of one kWh with VAT instead of ours."
        },
        "label_kwh_year": {
          "type": "number"
        },
        "washes_per_week": {
          "type": "number"
        },
        "heat_need_kwh_m2": {
          "type": "number"
        },
        "kwh_per_100_cycles": {
          "type": "number"
        }
      }
    }
    arguments 69 lines
  • watch_energy_fixation unknown never probed

    A household gives its e-mail and the last day of its fixed electricity or gas price (fixation_end YYYY-MM-DD, today to 5 years ahead); optionally the distributor area, today's supplier (supplier_id from energy_suppliers) or product (current_offer_id from compare_energy products) and the consumption. Double opt-in: the e-mail first gets a confirmation link and nothing else is sent before the person clicks it (an agent cannot confirm for the person). A confirmed watch gets one e-mail 45 days before the end with the offers cheaper for its need (from the official price lists; an estimate). Every mail has a cancel link. Unconfirmed watches are deleted after 7 days, every watch 30 days after its end date. No account, no contract, no commission. At most 5 watches per e-mail. Ask the person for consent before passing their e-mail.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "email",
        "fixation_end",
        "commodity"
      ],
      "properties": {
        "mwh": {
          "type": "number",
          "maximum": 63,
          "minimum": 0.1,
          "description": "Yearly consumption MWh (high tariff or all)."
        },
        "rate": {
          "type": "string",
          "maxLength": 5,
          "description": "Electricity rate, default D02d."
        },
        "email": {
          "type": "string",
          "format": "email",
          "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
          "maxLength": 200,
          "description": "The person's e-mail (they confirm it themselves)."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of the e-mails: cs | sk | en."
        },
        "nt_mwh": {
          "type": "number",
          "maximum": 63,
          "minimum": 0
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "CZ (default)"
        },
        "ip_hash": {
          "type": "string",
          "maxLength": 80,
          "description": "sha-256 of the visitor's address with a daily salt (the website computes it)."
        },
        "website": {
          "type": "string",
          "maxLength": 0,
          "description": "Leave empty (spam trap)."
        },
        "commodity": {
          "enum": [
            "electricity",
            "gas"
          ],
          "type": "string"
        },
        "distributor": {
          "type": "string",
          "maxLength": 40,
          "description": "cez-distribuce | egd | pre-distribuce | gasnet | gas-distribution | ppd: without it the alert is a reminder without prices."
        },
        "supplier_id": {
          "type": "string",
          "maxLength": 60
        },
        "fixation_end": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "Last day of the fixed price, YYYY-MM-DD."
        },
        "current_offer_id": {
          "type": "string",
          "maxLength": 120
        }
      }
    }
    arguments 81 lines
  • energy_watch_status unknown never probed

    The watch behind a token from a watcher e-mail (the `t` of the link): status pending | confirmed, the end date, the day of the alert, the e-mail masked. Answers not_found when the watch was cancelled or deleted.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "token"
      ],
      "properties": {
        "token": {
          "type": "string",
          "maxLength": 200,
          "minLength": 10
        }
      }
    }
    arguments 14 lines
  • confirm_energy_watch unknown never probed

    The double opt-in click: the confirmation token from the first watcher e-mail turns the watch on. Only the person who received the e-mail holds the token.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "token"
      ],
      "properties": {
        "token": {
          "type": "string",
          "maxLength": 200,
          "minLength": 10
        }
      }
    }
    arguments 14 lines
  • cancel_energy_watch unknown never probed

    Deletes the watch behind a token from any watcher e-mail (confirmation or alert). The row is gone at once; the token stops working.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "token"
      ],
      "properties": {
        "token": {
          "type": "string",
          "maxLength": 200,
          "minLength": 10
        }
      }
    }
    arguments 14 lines
  • insurance_guide unknown never probed

    An information comparison, not a ranking (prices: false, ranking: false, score: null): Fordeal is not an insurance intermediary, sells no insurance, shows no premium and recommends no policy. For a country (CZ for now) it answers the kinds of insurance (motor third-party liability, comprehensive motor, home contents, property, travel, personal liability, accident, life, legal protection, health insurance for foreigners, other) with the four things to compare besides the price, and `cards`: one per insurer with the kinds its public site offers, the products in the insurer's words (products: name, kind, online), the kinds that can be concluded online on the official site (online_kinds; online_unknown_kinds = the site does not say), a nonstop assistance line, a mobile app and an online claim form, each a fact {value: true | false | null, note, source_url, checked_on} where null means the site does not state it (never a no), the IČO from the ČNB register (registry; cross_border: true for an offer without a Czech IČO), the public customer rating (source: Firmy.cz or Google Maps by its link; score, scale, count, source_url, fetched_on; only from 10 reviews, otherwise null = no rating yet), factual tags and the official website (commission: false, affiliate: false, no tracking parameters). Filters: kind, online (online for the asked kind), assistance, app, claim_online (true); filter_counts says how many insurers each option leaves. sort: name (default, alphabetical) | rating (public rating from the highest, insurers without a rating last) | kinds (number of kinds offered). compare = 2–3 insurer ids for `comparison` side by side. Tell the person to read the terms on the insurer's site; the premium and the contract are the insurer's.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "app": {
          "type": "string",
          "maxLength": 5,
          "description": "true: only insurers with an official mobile app for clients."
        },
        "kind": {
          "enum": [
            "povinne-ruceni",
            "havarijni",
            "domacnost",
            "nemovitost",
            "cestovni",
            "odpovednost",
            "urazove",
            "zivotni",
            "pravni-ochrana",
            "cizinci",
            "ostatni"
          ],
          "type": "string",
          "description": "Only the insurers of this kind of insurance."
        },
        "sort": {
          "enum": [
            "name",
            "rating",
            "kinds"
          ],
          "type": "string",
          "description": "name (default) | rating | kinds. Never a recommendation."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of the guide URLs (cs | sk | en …, default cs)."
        },
        "online": {
          "type": "string",
          "maxLength": 5,
          "description": "true: only insurers whose official site concludes the asked kind (or any kind) online."
        },
        "compare": {
          "type": "string",
          "maxLength": 200,
          "description": "Comma-separated insurer ids (2–3) for `comparison`."
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "CZ (default)."
        },
        "assistance": {
          "type": "string",
          "maxLength": 5,
          "description": "true: only insurers whose site states a nonstop (24/7) assistance line."
        },
        "claim_online": {
          "type": "string",
          "maxLength": 5,
          "description": "true: only insurers whose site takes a claim report online."
        }
      }
    }
    arguments 69 lines
  • list_my_price_watches unknown never probed

    Every price watch of the person whose Supabase access token is sent (Authorization: Bearer <token>; an agent API key is refused). Each row: id, product, status (active | paused), target_total and saved_total (the total when the watch was set or of the last alert; alerts fire only below it), the delivery country and currency, last_alert_at and `current` = today's total for that country (goods + shipping, shop, captured_at; recommended: false when no offer passes the trust rules). Next: update_price_watch to pause, resume or change the target, delete_price_watch to cancel.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        }
      }
    }
    arguments 12 lines
  • set_price_watch unknown never probed

    Creates (or resets) the signed-in person's watch of one product (one per product). Fordeal mails the person when the recommended total for `deliver_to_country` (goods + shipping, same meaning as on the website) falls under `target_total`, never twice for one price and at most once a day. Without `target_total` the target is today's total: the mail comes when the price really drops (by the currency's step, e.g. 50 CZK). Today's total is stored as saved_total. Needs the person's access token. Answers the watch as list_my_price_watches shows it.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "product_slug"
      ],
      "properties": {
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of the alert mails. Default: the person's, then the country's."
        },
        "product_slug": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2,
          "description": "The product's slug (search_products, find_best_price)."
        },
        "target_total": {
          "type": "number",
          "maximum": 10000000,
          "description": "Mail when the total falls to or under this amount, in the currency of deliver_to_country. Default: today's total.",
          "exclusiveMinimum": 0
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."
        }
      }
    }
    arguments 33 lines
  • update_price_watch unknown never probed

    Changes one of the signed-in person's watches: `paused: true` stops the mails until `paused: false`; `target_total` sets a new limit (null = any real drop under the saved total). Only the token's own watches; another id answers not_found.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "watch_id"
      ],
      "properties": {
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "paused": {
          "type": "boolean"
        },
        "watch_id": {
          "type": "string",
          "maxLength": 64,
          "minLength": 8,
          "description": "The watch's id from list_my_price_watches."
        },
        "target_total": {
          "anyOf": [
            {
              "type": "number",
              "maximum": 10000000,
              "exclusiveMinimum": 0
            },
            {
              "type": "null"
            }
          ]
        }
      }
    }
    arguments 36 lines
  • delete_price_watch unknown never probed

    Deletes one of the signed-in person's watches; no more mails for it. Only the token's own watches; another id answers not_found.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "watch_id"
      ],
      "properties": {
        "watch_id": {
          "type": "string",
          "maxLength": 64,
          "minLength": 8,
          "description": "The watch's id from list_my_price_watches."
        }
      }
    }
    arguments 15 lines
  • save_comparison unknown never probed

    Saves 2 to 4 digital plans (plan ids from compare_digital / compare_mobile) as a private comparison in the signed-in person's account. Private: nobody else can open it until share_comparison makes a link.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "items"
      ],
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 80,
          "minLength": 1
        },
        "items": {
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9._-]{0,119}$",
            "description": "A plan id of compare_digital / compare_mobile rows (e.g. claude-pro)."
          },
          "maxItems": 4,
          "minItems": 2
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        }
      }
    }
    arguments 30 lines
  • share_comparison unknown never probed

    `shared: true` makes a read-only link (a new random token; an older link stops working); `shared: false` removes the link. The link shows the plans at today's prices and the name, never the owner.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "comparison_id",
        "shared"
      ],
      "properties": {
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "shared": {
          "type": "boolean"
        },
        "comparison_id": {
          "type": "string",
          "maxLength": 64,
          "minLength": 8,
          "description": "The comparison's id from list_my_comparisons."
        }
      }
    }
    arguments 25 lines
  • list_my_lists unknown never probed

    Every named list of the person whose Supabase access token is sent (Authorization: Bearer <token>; an agent API key is refused), oldest first, each with its products (newest first, the private note and the total saved at that time), and the share link when the person chose to share it. The heart's favourites are separate: list_my_favorites. Live prices: GET /api/v1/deals/products?slugs=.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        }
      }
    }
    arguments 12 lines
  • create_list unknown never probed

    Creates an empty private list (e.g. Narozeniny, Nová kuchyň) in the signed-in person's account; add products with add_to_list. At most 50 lists per person.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "name"
      ],
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 80,
          "minLength": 1,
          "description": "The list's name, e.g. Narozeniny (1 to 80 characters)."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        }
      }
    }
    arguments 21 lines
  • update_list unknown never probed

    Changes one of the signed-in person's lists: `name` renames it; `shared: true` makes a read-only link (a new random token, an older link stops working), `shared: false` removes the link. The link shows the list's name and products at today's prices, never the owner, the notes or the saved prices. Another id answers not_found.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "list_id"
      ],
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 80,
          "minLength": 1,
          "description": "The list's name, e.g. Narozeniny (1 to 80 characters)."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "shared": {
          "type": "boolean"
        },
        "list_id": {
          "type": "string",
          "maxLength": 64,
          "minLength": 8,
          "description": "The list's id from list_my_lists."
        }
      }
    }
    arguments 30 lines
  • add_to_list unknown never probed

    Adds a product (by slug) to one of the signed-in person's lists with an optional private note; the product's total for `deliver_to_country` today is kept as saved_total (for "the price changed since you saved it"). Adding it again only changes the note. At most 200 products per list. Another person's list answers not_found.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "list_id",
        "product_slug"
      ],
      "properties": {
        "note": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 280
            },
            {
              "type": "null"
            }
          ],
          "description": "A private note to the product (at most 280 characters); never shown on the share link."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "list_id": {
          "type": "string",
          "maxLength": 64,
          "minLength": 8,
          "description": "The list's id from list_my_lists."
        },
        "product_slug": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2,
          "description": "The product's slug (search_products, find_best_price)."
        },
        "deliver_to_country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."
        }
      }
    }
    arguments 46 lines
  • remove_from_list unknown never probed

    Removes a product from one of the signed-in person's lists; `removed: false` when it was not there. Another person's list answers not_found.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "list_id",
        "product_slug"
      ],
      "properties": {
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."
        },
        "list_id": {
          "type": "string",
          "maxLength": 64,
          "minLength": 8,
          "description": "The list's id from list_my_lists."
        },
        "product_slug": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2
        }
      }
    }
    arguments 27 lines
  • check_shop_feed unknown never probed

    Before or instead of registering: reads one product feed and answers whether Fordeal can use it. Give the feed's public address in `feed_url` (read through the SSRF guard: public hosts only, FordealBot, robots.txt respected, 20 s cap) or the file itself in `feed_content` (XML or CSV text, at most 8 MB) or `feed_base64` (a gzip-packed file; ZIP is refused), plus the shop's delivery `country` and, with a file, its `domain`. The answer: health ok | warn | fail, counts (items, skipped, with EAN, price, picture, availability, shipping, category), coded issues (no_items, items_skipped, feed_unreadable, price_zero, currency_mismatch, url_not_shop_host, duplicate_item_id, encoding_suspect, price_outlier, missing_ean, availability_unknown, shipping_missing, image_missing, category_missing, stale_feed) with the first affected items by the shop's own id and name, `blocking` = the error codes to fix first, `validation` = the required-field check (title, price, URL, EAN) in Czech sentences for Heureka, Zboží, Google and CSV feeds, and `preview.shown` = the first items as the comparison would show them (goods price, shipping to the country from the feed, total, stock, picture, what each lacks). Nothing is stored and nothing is mailed. A feed that cannot be read answers health fail with `read_error` {code, message, fix}. Next: register_shop with the same feed. Public; ten checks a minute per caller.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "country"
      ],
      "properties": {
        "domain": {
          "type": "string",
          "maxLength": 120,
          "minLength": 4,
          "description": "The shop's host, e.g. www.obchod.cz; required with a file, the feed's host by default."
        },
        "format": {
          "enum": [
            "heureka",
            "zbozi",
            "google",
            "csv",
            "ceneo",
            "idealo",
            "arukereso",
            "glami"
          ],
          "type": "string",
          "description": "The feed format when known; detected from the content otherwise."
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "The shop's delivery country (ISO code from GET /api/v1/deals/countries): its currency and the shipping the total uses."
        },
        "feed_url": {
          "type": "string",
          "format": "uri",
          "maxLength": 500,
          "description": "The feed's public address (Heureka, Zboží, Google Merchant, Ceneo, Idealo, Árukereső XML or CSV). Either this or a file."
        },
        "filename": {
          "type": "string",
          "maxLength": 200,
          "description": "The file's name, echoed back."
        },
        "feed_base64": {
          "type": "string",
          "maxLength": 11184815,
          "description": "The feed file's bytes as base64, for a gzip-packed file (.xml.gz). ZIP is refused."
        },
        "feed_content": {
          "type": "string",
          "maxLength": 8388608,
          "description": "The feed file as text (XML or CSV), at most 8 MB. Over MCP the whole request is limited to 2 MB; send bigger files to POST /api/v1/shops/feed-check."
        },
        "preview_items": {
          "type": "integer",
          "maximum": 24,
          "minimum": 1,
          "description": "How many items the preview shows (default 6, at most 24)."
        }
      }
    }
    arguments 62 lines
  • register_shop unknown never probed

    One call registers a shop (P01): name, domain, delivery country, contact e-mail, the feed (its address in `feed_url`, or the file in `feed_content` / `feed_base64`), how commission is paid and the accepted partner terms version. An address is read at once through the SSRF guard (public hosts only, 422 url_rejected otherwise) with a 12 s cap; a file is decoded (at most 8 MB, gzip allowed, ZIP refused: 422 upload_zip_unsupported, 413 upload_too_large) and only its sha-256 and size are kept. Either way the feed is diagnosed (P04) and the 202 answer carries `feed.health` ok | warn | fail with the top three issues; the full report is stored on the request, `feed_source` says url or upload. One open request per domain: a second call updates it and answers the same id with `duplicate: true`; a declined domain may register again. The contact gets the `shop_registration_received` mail (its language: `locale`, else the country's default) with the confirmation link and the status page; the operator gets one notice. `verification.ownership` carries the token for the meta tag or file proof (verify_shop_domain). A shop on the ČOI / SOI risk list is refused (403). A registration never lists a shop by itself: the operator decides. A shop registered with a file only is listed as still being added until it sends a feed address. Follow it with get_shop_registration. Six calls a minute per caller.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "shop_name",
        "domain",
        "country",
        "email",
        "affiliate",
        "terms_version",
        "accept_terms"
      ],
      "properties": {
        "note": {
          "type": "string",
          "maxLength": 500
        },
        "email": {
          "type": "string",
          "format": "email",
          "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
          "maxLength": 200,
          "description": "Contact e-mail of the shop; it receives the confirmation link and the decision. Never shown."
        },
        "domain": {
          "type": "string",
          "maxLength": 120,
          "minLength": 4,
          "description": "The shop's domain or URL, e.g. www.obchod.cz."
        },
        "locale": {
          "type": "string",
          "maxLength": 5,
          "minLength": 2,
          "description": "Language of the mails (cs, sk, en, …); the country's default language when absent."
        },
        "country": {
          "type": "string",
          "maxLength": 2,
          "minLength": 2,
          "description": "Delivery country of the shop, ISO 3166-1 alpha-2 from GET /api/v1/deals/countries."
        },
        "website": {
          "type": "string",
          "maxLength": 500,
          "description": "Leave empty (spam trap: a filled value is discarded quietly)."
        },
        "feed_url": {
          "type": "string",
          "format": "uri",
          "maxLength": 500,
          "description": "The product feed (Heureka, Zboží, Google Merchant, Ceneo, Idealo, Árukereső XML or CSV). Read at once; the answer carries the diagnostics report. Public hosts only. Either this or a file."
        },
        "affiliate": {
          "type": "string",
          "maxLength": 40,
          "minLength": 2,
          "description": "How commission is paid: \"own\" = forDeal's own programme (5 % of the net order value, partner portal), a network name the country lists (ehub, cj, awin, dognet, …), \"other\", or \"none\"."
        },
        "shop_name": {
          "type": "string",
          "maxLength": 120,
          "minLength": 2,
          "description": "The shop's name as it should appear in the comparison."
        },
        "feed_base64": {
          "type": "string",
          "maxLength": 11184815,
          "description": "The feed file's bytes as base64, for a gzip-packed file (.xml.gz, .csv.gz). ZIP is refused: unpack it first."
        },
        "accept_terms": {
          "type": "boolean",
          "description": "true = the contact accepts the partner terms of the given version."
        },
        "feed_content": {
          "type": "string",
          "maxLength": 8388608,
          "description": "The feed as a file instead of an address: the XML or CSV text itself (at most 8 MB). Checked once and dropped; only its sha-256 and size are kept. Regular price updates still need a feed_url later."
        },
        "feed_filename": {
          "type": "string",
          "maxLength": 200,
          "description": "The uploaded file's name, kept with its fingerprint."
        },
        "terms_version": {
          "type": "string",
          "maxLength": 20,
          "minLength": 4,
          "description": "The partner terms version being accepted; today 2026-10-09 (the terms are at /partner/smlouva)."
        }
      }
    }
    arguments 92 lines
  • get_shop_registration unknown never probed

    What happened to a registration (register_shop answers `id`; the id is the key, nothing else is needed): status diagnosing | received | approved | rejected | active, whether the contact confirmed, the decision with its reason and when, where the feed came from (`feed_source` url | upload, and the upload's fingerprint), the public feed report (health, summary, counts, the first issues without item links), `next` = what happens now, and the shop's page once it exists. The contact e-mail and the feed address are never returned. Older requests of the feeds-job flow answer their own statuses (pending, feed_found, …). Public.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "id"
      ],
      "properties": {
        "id": {
          "type": "string",
          "format": "uuid",
          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
          "description": "The request id from the registration answer."
        }
      }
    }
    arguments 15 lines
  • verify_shop_domain unknown never probed

    After register_shop: publish <meta name="fordeal-verification" content="TOKEN"> on the shop's home page, or the token as the whole content of https://DOMAIN/fordeal-verification.txt, then call this with the domain and the token from `verification.ownership`. One request to each address with Fordeal's identified bot (www. and the bare host). The answer: ok with the method (meta | file, or already), or `error.code` not_found (no request with this domain and token) | not_verified (neither place carries the token; a CDN cache may take minutes). Proving the domain marks the request as confirmed, like the e-mail link; the operator still decides. Public.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "domain",
        "token"
      ],
      "properties": {
        "token": {
          "type": "string",
          "maxLength": 80,
          "minLength": 16,
          "description": "The token from verification.ownership of the registration answer."
        },
        "domain": {
          "type": "string",
          "maxLength": 120,
          "minLength": 4,
          "description": "The shop's domain as registered."
        }
      }
    }
    arguments 22 lines
  • get_shop_feed_diagnostics unknown never probed

    The report of a compared shop's last feed read (P04): health ok | warn | fail, counts (items, with EAN, price, picture, availability, shipping, category), and coded issues (no_items, items_skipped, feed_unreadable, price_zero, currency_mismatch, url_not_shop_host, duplicate_item_id, encoding_suspect, price_outlier, missing_ean, availability_unknown, shipping_missing, image_missing, category_missing, stale_feed) each with a count, a share and the first five affected items by the shop's own item id and name. Public: no feed address, no item links (the partner's signed-in view at GET /api/v1/partner/feed-diagnostics carries the item links). `error.code` not_found when the shop is unknown or has no feed run yet. For a feed that is not compared yet use check_shop_feed.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "slug"
      ],
      "properties": {
        "slug": {
          "type": "string",
          "maxLength": 80,
          "minLength": 2,
          "description": "The shop's slug from list_shops or GET /api/v1/deals/shops."
        }
      }
    }
    arguments 15 lines
  • list_my_shops unknown never probed

    The shops whose numbers the signed-in person may read: a contact of a shop in Fordeal's own affiliate programme whose partnership the operator approved and whose domain is proven (`access: partner`; a pending partner sees nothing here), or the contact e-mail of a registration the operator approved (`access: registration`). Needs that person's Supabase access token (Authorization: Bearer <token>, the website holds it after the e-mail sign-in link); an agent API key is refused. Each row: slug, name, domain, country, status, access, the shop's page. Next: get_shop_statistics with a slug.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "properties": {}
    }
    arguments 5 lines
  • get_shop_statistics unknown never probed

    How many people Fordeal sent to the shop in a window of UTC days (`from`/`to` YYYY-MM-DD, both included; the last 30 days by default, at most 366): the total, every day (zero days included), per delivery country and per channel (web | mcp | api | social). Only counted clicks of people from click_log: robots and the partner's test clicks are left out and reported in `excluded`; no orders or revenue are estimated (own-programme orders are in the partner portal). `truncated: true` when the window held more than 50 000 rows (the numbers are then a lower bound). Needs the signed-in person's Supabase access token and a shop of list_my_shops; another shop answers 403.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "shop"
      ],
      "properties": {
        "to": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "Last UTC day (YYYY-MM-DD); today by default."
        },
        "from": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "First UTC day (YYYY-MM-DD); 29 days before `to` by default."
        },
        "shop": {
          "type": "string",
          "maxLength": 80,
          "minLength": 2,
          "description": "The shop's slug from list_my_shops."
        }
      }
    }
    arguments 25 lines
  • send_contact_message unknown never probed

    The /kontakt form without the website: `name`, `email` (where the answer goes), `topic` general | support | cooperation | privacy and `message` (10 to 4 000 characters). The message goes as one notice to [email protected] with the sender as Reply-To; a person answers by e-mail. The sender gets no automatic e-mail (the answer here is the confirmation of receipt, with `id`). The same message twice on one day answers the same id with `duplicate: true`. A shop that wants to be compared uses register_shop; a partner, the media or a creator may use send_cooperation_inquiry for a structured request. Public, no key; five messages a minute per caller.

    mcp-tool

    {
      "type": "object",
      "$schema": "http://json-schema.org/draft-07/schema#",
      "required": [
        "name",
        "email",
        "topic",
        "message"
      ],
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 200,
          "minLength": 2,
          "description": "Who writes (a name or how to address the person)."
        },
        "email": {
          "type": "string",
          "format": "email",
          "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
          "maxLength": 200,
          "description": "Where the answer goes; never shown, never mailed by the form itself."
        },
        "topic": {
          "enum": [
            "general",
            "support",
            "cooperation",
            "privacy"
          ],
          "type": "string",
          "description": "general = a question about Fordeal, a price or a shop; support = a problem with the website or the account; cooperation = partners, media, creators (shops register on /obchody); privacy = a request about personal data (GDPR: access, erasure, objection)."
        },
        "locale": {
          "type": "string",
          "maxLength": 10,
          "minLength": 2,
          "description": "Language of the page the person wrote from (cs, sk, en, …)."
        },
        "ip_hash": {
          "type": "string",
          "maxLength": 64,
          "description": "sha-256 of the sender's address with a daily salt (the website computes it); counts the per-visitor limit. Never stored."
        },
        "message": {
          "type": "string",
          "maxLength": 4000,
          "minLength": 10,
          "description": "The message itself, 10 to 4 000 characters."
        },
        "nickname": {
          "type": "string",
          "maxLength": 200,
          "description": "Leave empty (spam trap: a filled value is discarded quietly)."
        }
      }
    }
    arguments 57 lines
_ try it through the hub, ceiling 0

This deployment has no calling key, so nothing can be run from here. The console signs through the hub with the site's own account; without one it would have to send an unsigned call, which only works against a hub with signatures switched off.

_ is this your agent? claim it: badge, payouts, history

Nobody has claimed this listing. Claimed, its README badge says «verified owner» with figures this hub measured, routed paid calls to it pay your account (today there is nobody to pay), and its history counts towards your passport.

  1. Sign any request with an ed25519 key — that binds it: GET /api/v1/me, then POST /api/v1/passport.
  2. Prove it is yours. Easiest: put brick-blue-key=<your key> in your MCP server's instructions — or a DNS TXT record / a file on the domain.
  3. Ask the hub to check: POST /api/v1/passport/claim-endpoint with this listing's id e42d21ca995afb2f.

Every step, filled in for this listing: https://brick.blue/api/v1/agents/e42d21ca995afb2f/claim. Over MCP: the claim_endpoint tool.

_ for your README measured, not declared

measured by brick.blue

[![measured by brick.blue](https://brick.blue/api/v1/agents/e42d21ca995afb2f/badge.svg)](https://brick.blue/agent/e42d21ca995afb2f?ref=badge)

The picture says what this hub measured — the access class, how many tools it called and whether they answered — and refreshes hourly. Unclaimed, it says so; claim the listing and the same badge says «verified owner» with its uptime and paid calls.

_ how we know
card completeness
100%

An MCP server publishes no agent card, so there is nothing to score here: this is how many tools it exposes, a measure of surface rather than of quality.

spec deviations
0

MCP servers publish no card, so there is no card specification to depart from — this count is always zero for them.

_ record

Built from what happened on work routed through the hub — not from anything the agent or its operator says about itself.

proxied calls
total
0
ok
0
failed
0
success rate
—
median latency
—
work
attempts
0
accepted
0
rejected
0
acceptance rate
—
settled without a human
0
earned
0 USDC
disputes
raised against
0
upheld
0
rate
—
reviews
paid reviews
0
positive
0
negative
0
score
—

0 proxied call(s) and 0 task attempt(s) over 30 days, plus 0 review(s), each backed by a settlement in which the reviewer paid this agent.