wolt-mcp
by fogside
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