Reposta MCP

A remote MCP server that answers questions about fuel station prices in Spain, in natural language — Spanish-first, with an opt-in English mode.

A remote MCP (Model Context Protocol) server that lets any MCP-compatible AI assistant (Claude, ChatGPT, etc.) answer questions about fuel station prices in Spain, based on a location the user describes in plain natural language — in any language or phrasing, since the connected LLM (not this server) is what interprets what the person says.

Tool names, descriptions, and all user-facing text are Spanish-first (this server targets the Spanish public), with an opt-in English mode via the language parameter.

Only stations open to the general public are ever shown — restricted-access stations (fleets, co-ops, agricultural use) are excluded, and so is any fuel type not meant for general-public refueling.

Scope: Spain only. There is no coverage for other countries. If a location can't be resolved to Spain, every tool returns a clear message explaining that, instead of silently returning nothing.

Location is always required. No tool assumes or geolocates the user by IP. If the assistant doesn't know where the user is, it's expected to ask before calling these tools.

Privacy policy, support, and terms of use — served live alongside the connector.


What this MCP can do

Six tools are exposed. All of them are read-only (readOnlyHint: true) and safe to call freely. Every tool below returns a ready-made formattedText field meant to be shown to the user verbatim — the tool descriptions instruct the client model not to reformat or summarize it on its own.

Interactive map. Every tool's result also includes a map field with everything needed to draw an interactive map of the answer: a marker for the search point (labeled "Punto de búsqueda" / "Search point" — never "your location", since Reposta never accesses GPS or the user's real location) and one marker per station in the response, all auto-framed together. Tapping a station marker shows its name, address, price(s), schedule, and navigation links. Clients that support it (like ChatGPT) render this map alongside formattedText; clients that don't simply ignore the map field and the text answer works exactly the same.

In chat, the map appears as a compact card sized so the written answer stays visible right below it — never a tall panel you have to scroll past. An Ampliar / Expand button on the card opens the full-size map when you want to explore it, and takes it back to the card when you're done.

1. gasolineras_cerca — stations near a location

The main tool: lists nearby gas stations with full pricing, sorted by price or distance. Every match in the search area is returned. If you want a specific number of them instead, use gasolineras_top_n.

Input

Param Type Default Notes
location string — (required) Natural language: municipality, neighborhood, zone ("downtown Madrid", "north of Valencia"), address, postal code, a road reference ("AP-7 a la altura de Valencia"), or the two ends of a stretch you're driving ("entre Mojácar y Níjar por la autovía").
fuel_type string (none — shows all fuels) Natural language: "diesel", "gasoline", "gasoline 95", "gasoline 98", "premium diesel".
station_name string (none) Name of a specific gas station to filter by, e.g. "Repsol", "BP", "Moeve", "Plenoil". Case- and accent-insensitive.
radius_km number 2 Search radius around the location, up to 5 km. If location is the exact name of a municipality, the radius is ignored and every station in it is returned instead, with no cap at all.
sort_by "price" | "price_desc" | "distance" (auto) Leave unset in almost every case: the server defaults to "distance" when location is a precise point (a street address, or a named place like a hotel) since the exact distance is known there, and to "price" for every other location kind, where no real distance is known. Set it explicitly to override that default — "price" for "cheapest", "price_desc" for "most expensive", "distance" for "closest" — an explicit request always wins over the automatic default. Either way, an open station always ranks before a closed/unknown one — price/distance only break ties within each group.
open_now boolean false Filter to stations currently open right now. When false (the default), every matching station is shown regardless of whether it's open or closed.
low_cost_only boolean false Filter to low-cost brands (Ballenoil, Petroprix, Plenoil...).
max_results number (none — no limit) Cap the list to the first N stations after sorting. This is a result-count filter, entirely independent of radius_km (a search-area filter), with no cap of its own — the search area is what bounds how many stations can ever be returned. If you're asking for a specific number of stations, gasolineras_top_n is the tool for it: there the count is required, so it can't be left out by accident.
language "es" | "en" "es" Language of formattedText and every human-facing field (fuel names, messages).

Response template

{
  "available": true,
  "formattedText": "⛽ Diésel A en Madrid – Chamberí, Madrid — ...",  // show verbatim
  "location": { "queried": "downtown Madrid", "resolved": "Madrid, Spain", "lat": 40.42, "lon": -3.70 },
  "municipality": { "name": "Madrid", "province": "MADRID" },
  "filteredFuel": "Diésel A",              // or null if no fuel_type was given; localized per `language`
  "radiusKm": 2,
  "sortBy": "price",
  "date": "24/07/2026 10:00:00",           // dataset's last update time
  "summary": {
    "totalInMunicipality": 244,            // all public stations in the municipality
    "totalInRadius": 12,                   // how many fall within the radius
    "returned": 12,                        // how many are actually in `stations` (may be less if max_results was set)
    "totalWithFuel": 11,                   // of those, how many sell filteredFuel (only if fuel_type given)
    "zoneAverageForFilteredFuel": 1.775,    // or null if no fuel_type was given
    "averagesByFuel": [                    // average + min price of EVERY fuel found in the zone
      { "fuel": "Diésel A", "averagePrice": 1.775, "minPrice": 1.669, "stationCount": 11 }
    ]
  },
  "stations": [
    {
      "name": "BALLENOIL",
      "address": "CALLE EXAMPLE, 1",
      "postalCode": "28004",
      "schedule": "L-D: 24H",
      "isLowCost": true,
      "open": true,
      "distanceKm": 1.39,
      "prices": [ { "fuel": "Diésel A", "price": 1.669 } ],
      "referencePrice": 1.669,              // present only when fuel_type was given
      "diffFromAverage": -0.106,
      "indicator": "🟢",                    // 🟢 cheap / 🟡 average / 🔴 expensive
      "estimatedSavings": 5.3,              // € saved on a ~50L fill-up vs. the zone average
      "rank": 1,
      "links": {
        "googleMaps": "https://www.google.com/maps/search/?api=1&query=40.43,-3.70",
        "appleMaps": "https://maps.apple.com/?q=40.43,-3.70",
        "waze": "https://waze.com/ul?ll=40.43,-3.70&navigate=yes"
      }
    }
  ],
  "map": {                                // data for the interactive map (supporting clients only)
    "language": "es",
    "searchPoint": { "lat": 40.42, "lon": -3.70 },   // shown as "Punto de búsqueda" / "Search point"
    "stations": [ { "name": "...", "address": "...", "schedule": "...", "lat": 40.43, "lon": -3.70, "open": true, "prices": [ { "fuel": "...", "price": 1.669 } ], "links": { "...": "..." } } ]
  },
  "notice": "..."   // present only when something needs explaining (e.g. filters left nothing)
}

If the location isn't in Spain or can't be resolved: { "available": false, "message": "..." }.

2. gasolineras_top_n — exactly the number of stations you asked for

Use this when you ask for a specific number of stations: "the 5 cheapest gasoline 95 stations near Hotel Mediodía, Madrid", "las 3 más cercanas", "find me 5 stations". It runs the same search as gasolineras_cerca and returns exactly that many (fewer only if the area holds fewer).

It takes the same input as gasolineras_cerca, except max_results is replaced by count — a required number. That's the whole point of this tool: because the count is required rather than optional, the assistant can't quietly leave it out and hand you the full list instead of the five you asked for.

Param Type Default Notes
count number — (required) How many stations to return, i.e. the number you asked for. Applied after sorting, so "the 5 cheapest" returns the 5 cheapest in the area.

Every other parameter (location, fuel_type, station_name, radius_km, sort_by, open_now, low_cost_only, language) behaves exactly as in gasolineras_cerca, so you can combine a count with any filter: the 3 cheapest diesel stations open right now, the 5 closest Repsol stations within 5 km, and so on.

3. gasolineras_24h — stations open 24 hours a day

Same as gasolineras_cerca, but only returns stations whose posted schedule is 24h/every day — that's a property of the schedule itself, not "happens to be open right now". Same input as gasolineras_cerca, minus open_now (redundant: a 24h station is always open).

4. gasolineras_low_cost — low-cost stations

Same as gasolineras_cerca, but only returns low-cost brands. Same input as gasolineras_cerca, minus low_cost_only (implied by the tool itself).

5. precio_medio_zona — statistics without the long list

For when only the aggregate numbers matter, not a station-by-station dump.

Input: location (required), fuel_type (required), radius_km (optional — see defaults note below), language (optional, default "es").

Response template

{
  "available": true,
  "formattedText": "⛽ Gasolina 98 en Madrid – norte de Madrid — ...",  // show verbatim
  "scope": "radius",              // "radius" or "municipality" — see note below
  "radiusKm": 2,                  // present only if scope = "radius"
  "location": { "queried": "north of Madrid", "resolved": "...", "lat": 40.44, "lon": -3.70 },
  "municipality": { "name": "Madrid", "province": "MADRID" },
  "fuel": "Gasolina 98",
  "date": "24/07/2026 10:00:00",
  "stationCount": 7,
  "averagePrice": 1.854,
  "minPrice": 1.739,
  "maxPrice": 1.914,
  "cheapest": [                   // top 3 cheapest stations
    { "name": "Q8", "address": "...", "schedule": "...", "price": 1.739, "lat": 40.44, "lon": -3.70, "open": true, "distanceKm": 0.9, "links": { "...": "..." } }
  ],
  "map": {                        // data for the interactive map (supporting clients only), built from "cheapest"
    "language": "es",
    "searchPoint": { "lat": 40.44, "lon": -3.70 },
    "stations": [ { "name": "...", "address": "...", "schedule": "...", "lat": 40.44, "lon": -3.70, "open": true, "prices": [ { "fuel": "Gasolina 98", "price": 1.739 } ], "links": { "...": "..." } } ]
  }
}

6. precio_medio_municipio — average and cheapest price

A lighter version of precio_medio_zona focused on just the number a user usually wants.

Input: same as precio_medio_zona: location, fuel_type, radius_km (optional), language.

Response template

{
  "available": true,
  "formattedText": "⛽ Gasolina 95 en Madrid\nPrecio medio: ...",  // show verbatim
  "scope": "municipality",
  "location": { "queried": "Madrid", "resolved": "...", "lat": 40.42, "lon": -3.70 },
  "municipality": { "name": "Madrid", "province": "MADRID" },
  "fuel": "Gasolina 95",
  "date": "24/07/2026 10:00:00",
  "stationCount": 229,
  "averagePrice": 1.701,
  "lowestPrice": 1.519,
  "cheapestStation": { "name": "BALLENOIL", "address": "...", "schedule": "...", "price": 1.519, "lat": 40.43, "lon": -3.71, "open": true, "links": { "...": "..." } },
  "map": {                        // data for the interactive map (supporting clients only)
    "language": "es",
    "searchPoint": { "lat": 40.42, "lon": -3.70 },
    "stations": [ { "name": "BALLENOIL", "address": "...", "schedule": "...", "lat": 40.43, "lon": -3.71, "open": true, "prices": [ { "fuel": "Gasolina 95", "price": 1.519 } ], "links": { "...": "..." } } ]
  }
}

How radius_km defaults work in precio_medio_zona and precio_medio_municipio (and in gasolineras_cerca for the exact-municipality case): if location is the exact name of a municipality ("Madrid"), the whole municipality is used (scope: "municipality"). If it's anything more specific — a neighborhood, street, landmark, cardinal zone ("north of Madrid"), or postal code — a 2 km radius is applied automatically (scope: "radius"), with no need to pass radius_km explicitly.

Municipality search is not a public tool. All five tools above resolve the municipality internally from free-text location — there's no separate "find a municipality by name" tool exposed, since end users never ask for that directly.

location works in Spanish or English. Places in Spain are recorded under their Spanish (or regional) name, so an English phrasing of a Spanish place — "University of Almería", "Port of Barcelona", "Almeria hospital" — is translated internally and resolved to the same point its Spanish name gives. English names for cities and provinces ("Seville", "Cordova", "Saragossa") work directly. There's no need to ask the user to restate a location in Spanish.


Available fuel types

Requests accept natural-language fuel names in Spanish or English (e.g. "diésel", "gasoil", "gasolina 95", "unleaded 98"). Displayed fuel names follow the language parameter:

Diesel B (subsidized/agricultural fuel), LPG/Autogas, CNG, LNG, and AdBlue are deliberately never shown or requestable — they aren't meant for general-public refueling (Diesel B) or fall outside this connector's scope, and never appear as an option, in results, or in the tools' questions to the user.

If a fuel type isn't recognized, the tool returns a clear error listing valid options instead of failing silently.


Behavior you should know about


Connect

Reposta is a remote MCP server, available directly from the Claude and ChatGPT app directories — nothing to install or run yourself.

MCP endpoint: https://reposta.jorgemrht.dev/mcp