Skip to main content
Glama
README.md
# wolt-mcp

A thin [Model Context Protocol](https://modelcontextprotocol.io/) server that exposes Wolt's public consumer endpoints to AI agents. Point it anywhere Wolt operates — the default coordinates are Tallinn, Estonia, but you can override per-call or via env vars.

Two tools, no magic:

- **`list_nearby`** — venues near a lat/lon, filtered by substring, rating, open/closed status.
- **`get_menu`** — full menu for a venue by slug, with prices, 30-day lows, and category structure.

It's read-only on purpose. Wolt's ordering API is gated behind merchant credentials; this server intentionally doesn't try to place orders.

## Who this is for

You want an AI assistant (Claude Code, Cursor, Continue, Zed, or your own Agent SDK app) that can:

- Discover restaurants by cuisine, rating, or open status in your city.
- Read full menus with live prices into its context window.
- Watch favorite venues for deals — discount categories like `ERIPAKKUMISED` (Estonian), `SPECIAL OFFERS`, or `KUUPAKKUMINE` (monthly offer), plus `lowest_price` (the 30-day low used for EU compliance display).
- Draft weekly meal plans by composing items across a curated shortlist of venues.

## Geographic coverage

Wolt's `consumer-api.wolt.com` is global; this server has no country hardcoding. Change `WOLT_DEFAULT_LAT` / `WOLT_DEFAULT_LON` (or pass `lat`/`lon` per call) to work anywhere Wolt delivers — Finland, Germany, Czechia, Estonia, Israel, Greece, Japan, and more. Verified live against **Tallinn (59.4370, 24.7536)**; other regions should work with the same endpoints.

## Install

```bash
git clone https://github.com/fogside/wolt-mcp
cd wolt-mcp
python3 -m venv .venv
.venv/bin/pip install -e .
```

Then register it with any MCP-capable client. For **Claude Code**, drop this at the project root:

```json
{
  "mcpServers": {
    "wolt": {
      "command": "./.venv/bin/wolt-mcp",
      "args": [],
      "env": {
        "WOLT_DEFAULT_LAT": "59.4370",
        "WOLT_DEFAULT_LON": "24.7536",
        "WOLT_LANGUAGE": "en"
      }
    }
  }
}
```

For **Claude Desktop**, add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or the equivalent on Linux/Windows:

```json
{
  "mcpServers": {
    "wolt": {
      "command": "/absolute/path/to/wolt-mcp/.venv/bin/wolt-mcp",
      "env": { "WOLT_DEFAULT_LAT": "59.4370", "WOLT_DEFAULT_LON": "24.7536" }
    }
  }
}
```

Any other MCP client that supports stdio transport works the same way — run `wolt-mcp` as the command.

## Tools

### `list_nearby`

| Param | Type | Default | Notes |
|---|---|---|---|
| `lat` | float | `$WOLT_DEFAULT_LAT` | |
| `lon` | float | `$WOLT_DEFAULT_LON` | |
| `radius` | int (m) | `3000` | 200–20000 |
| `query` | str? | `None` | Substring match against name + tags |
| `only_open` | bool | `False` | |
| `min_rating` | float? | `None` | 0–10 scale |
| `max_results` | int | `30` | |
| `language` | str | `$WOLT_LANGUAGE` or `en` | |

Returns a list of dicts: `name`, `slug`, `id`, `online`, `rating`, `rating_volume`, `eta_minutes`, `price_range`, `tags`, `short_description`, `address`.

### `get_menu`

| Param | Type | Default | Notes |
|---|---|---|---|
| `slug` | str | — | From `list_nearby`, e.g. `vapiano-foorum` |
| `language` | str | `en` | |
| `include_disabled` | bool | `False` | |

Returns `{ slug, assortment_id, primary_language, selected_language, available_languages, categories: [{ id, name, slug, description, items: [...] }], uncategorised_items, item_count }`. Each item has `id`, `name`, `description`, `price`, `original_price`, `lowest_price`, `enabled`, `tags`.

**Prices are integers in minor units.** `2390` = €23.90. Currency is not on items — infer from venue country.

## Environment variables

| Var | Default | Purpose |
|---|---|---|
| `WOLT_DEFAULT_LAT` | `59.4370` | Tallinn center |
| `WOLT_DEFAULT_LON` | `24.7536` | |
| `WOLT_LANGUAGE` | `en` | Sent as `Accept-Language` |
| `WOLT_MCP_LOG` | `WARNING` | Python logging level |

## Example conversations

> "Find the top five sushi places near me that are open right now." → `list_nearby(query="sushi", only_open=True, min_rating=9, max_results=5)`
>
> "Pull Vapiano Foorum's menu and tell me what's vegetarian." → `get_menu(slug="vapiano-foorum")` then the LLM filters by description.
>
> "Compare prices for pad thai between these three Thai venues." → one `list_nearby` + three `get_menu` calls.
>
> "Summarise current deals at my favorite café." → `get_menu` — surface items in categories named like `ERIPAKKUMISED` / `SPECIAL OFFERS` / `KUUPAKKUMINE`, or with `⭐` in the name.

## Detecting deals — an important gotcha

Wolt venues in practice use **category membership** as their deal signal much more often than `original_price`. A typical Estonian cafe will have a category named `ERIPAKKUMISED` ("special offers") or `KUUPAKKUMINE` ("monthly offer") containing the discounted items, while `original_price` on those items stays `null`.

When prompting your agent, don't rely on a price-diff — ask it to inspect category names and item names (`⭐` prefixes are common) as the first-class signal. `lowest_price` is useful for longer-range price-tracking: it's the 30-day low that Wolt surfaces for EU price-transparency compliance.

## Non-goals and limitations

- **No ordering, cart, or checkout.** Wolt's consumer cart/order flow requires authenticated user sessions + isn't in this MCP's scope. For commerce, use Wolt's merchant API (partner credentials required).
- **No user-account actions.** Can't read your order history or favorites.
- **Language.** The `assortment` endpoint often returns the venue's primary language (e.g. Estonian) even when `en` is requested — most venues don't publish auto-translated content. You'll see the actual selected language in the response's `selected_language` field.
- **Rate limits.** Wolt returns 429s under aggressive use. For personal use this doesn't matter; for anything heavier, add client-side pacing.

## Terms of service

This project hits Wolt's public, unauthenticated consumer endpoints — the same ones wolt.com's web app calls. Automated access at scale is contrary to Wolt's Terms of Service. Use this for personal agent assistance, experimentation, or research. Don't build a scraper at scale with it.

## Credits and sources of inspiration

- [**jonzarecki/wolt-sdk**](https://github.com/jonzarecki/wolt-sdk) — the first published Wolt MCP. Inspired this project, though the published implementation was Israel-focused and had server↔client method mismatches at the time of this writing, which pushed us to rebuild rather than fork. MIT-licensed.
- [**OfiliPatrick/wolt-restaurant-api**](https://github.com/OfiliPatrick/wolt-restaurant-api) — early reverse-engineering of the consumer endpoints.
- [Tomer Chaim's writeup](https://medium.com/analytics-vidhya/exploring-the-api-of-a-website-8579b04df28f) and [OzTamir's gist](https://gist.github.com/OzTamir/7ed2b49b8628d88c086d65b0d1730c36) — how to discover undocumented web-app endpoints through DevTools.
- Built on [**FastMCP**](https://gofastmcp.com) (v3.x) by the `jlowin/fastmcp` project.
- The broader [Model Context Protocol](https://modelcontextprotocol.io/) spec from Anthropic.

## Development

```bash
.venv/bin/pip install -e ".[dev]"  # once dev extras are defined
.venv/bin/wolt-mcp                 # runs the server on stdio — connect a client
```

Contributions welcome — especially venue-specific deal-detection heuristics for cities outside Estonia, or a `venue_dynamic(slug)` tool if you can find a working endpoint.

## License

[MIT](LICENSE).

TDQS

A3.9/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have completely distinct purposes: list_nearby finds venues, get_menu retrieves menu details for a specific venue. No overlap.

Naming Consistency4/5

Both tools follow a verb_noun pattern ('get_menu', 'list_nearby'), though 'list_nearby' uses an adjective which is a minor deviation.

Tool Count3/5

Only 2 tools is on the low end for a food delivery service, but it may be acceptable for a simple discovery-focused server. However, it feels thin for broader use cases.

Completeness2/5

The server covers basic venue discovery and menu retrieval, but lacks essential operations like searching items, user authentication, order management, or venue details beyond menus.

Maintenance

ActivityInactive
ResponsivenessNo issues