cookidoo-mcp
by josepenam
README.md
# cookidoo-mcp
This is what happens when you love your wife, love AI, but she loves her Thermomix even more. π
An [MCP](https://modelcontextprotocol.io) server that lets an AI assistant **browse, compare, plan, and shop** from [Cookidoo](https://cookidoo.international) β and **save arbitrarily tweaked custom recipes** back to your account ("load this recipe, apply my manual tweaks, save it").
It ships with a companion **usage skill** that teaches the assistant *how* to use the tools well (tweak methodology, Thermomix step formatting, safety rails). The skill is discoverable at runtime through a `get_skill` tool, so even MCP clients without filesystem-skill support can pull the methodology on demand.
> **Unofficial project.** Not affiliated with, endorsed by, or connected to Vorwerk, Thermomix, or Cookidoo. It talks to an unofficial/undocumented API that may change or break at any time. Use at your own risk and only within Cookidoo's Terms of Service (personal use β no scraping at scale). You need an active Cookidoo subscription.
---
## What it can do
| Area | Tools |
|---|---|
| **Discovery** | `search_recipes`, `get_recipe_details` |
| **Custom recipes** | `add_custom_recipe_from` (copy at a serving size), **`create_custom_recipe` (create from scratch β the "save my tweaks" path)**, `get_custom_recipe`, `remove_custom_recipe`, `update_custom_recipe` |
| **Tweak workflow** | `draft_tweak_from_recipe` β edit in conversation β `create_custom_recipe` |
| **Meal planning** | `get_calendar_week`, `add_recipes_to_calendar`, `remove_recipe_from_calendar`, `add_custom_recipes_to_calendar`, `remove_custom_recipe_from_calendar` |
| **Shopping list** | recipe / ingredient / additional-item management, check-off, `clear_shopping_list` |
| **Collections** | managed + custom collection CRUD |
| **Account** | `get_user_info`, `get_active_subscription` |
| **Suggestions** | `suggest_recipes_from_ingredients` |
| **Skill** | `get_skill` β serves the usage methodology at runtime |
The single biggest capability over prior art is **`create_custom_recipe`**: it builds a fully custom recipe (name, ingredients, steps, servings, times, hints) via the undocumented `created-recipes` endpoint. This is what makes "load a recipe, apply my manual tweaks, save the result" possible.
### Known limitations (v1)
- **No guided-cooking automation.** Uploaded custom recipes are readable on the Thermomix but do **not** drive the machine (per-step temperature/speed/time annotations are not reliably reverse-engineered). Write steps machine-adjacent (`3 min / 100Β°C / speed 2`) so they're easy to follow on-device.
- **No cooking steps from the library.** `get_recipe_details` returns ingredients, timing, nutrition, etc., but the Cookidoo API does not expose guided-cooking steps for library recipes, so a draft made from a library recipe starts with an empty step list for you to fill in.
- Custom recipes are always **PRIVATE**.
- No in-place edit is guaranteed in v1: the safe flow is create-new (+ optionally delete the old one). `update_custom_recipe` is provided as a best-effort PATCH but shares the reverse-engineered schema risk.
- No recipe images; no multi-account support.
---
## Requirements
- Python **β₯ 3.13**
- [`uv`](https://docs.astral.sh/uv/)
- An active Cookidoo subscription
## Configuration
All configuration is via environment variables (or a local `.env`; **environment wins** over `.env`). Copy the example:
```bash
cp .env.example .env
# then edit COOKIDOO_EMAIL / COOKIDOO_PASSWORD
```
| Variable | Required | Default | Meaning |
|---|---|---|---|
| `COOKIDOO_EMAIL` | β
| β | Cookidoo account email |
| `COOKIDOO_PASSWORD` | β
| β | Cookidoo account password |
| `COOKIDOO_COUNTRY_CODE` | | `ch` | Cookidoo TLD (`cookidoo.<cc>`) |
| `COOKIDOO_LANGUAGE` | | `de-CH` | Content locale (`fr-FR`, `en-GB`, `it-IT`, `es-ES`, β¦) |
| `COOKIDOO_URL` | | derived | Overrides the derived `https://cookidoo.<cc>/foundation/<lang>` |
> **Credentials are stored in plaintext locally** (in `.env` or your client config). They are sent only to the configured Cookidoo host. `.env` is gitignored. Never commit real credentials.
## Run it
```bash
# install deps into a project venv
uv sync
# dev loop with the MCP Inspector
uv run mcp dev src/cookidoo_mcp/server.py
# run the server directly (stdio transport)
uv run cookidoo-mcp
```
## Client integration
This is a **local stdio** server: it runs as a process on your machine. Which of
the following applies depends on the client. In all cases the server reads
credentials from your `.env`, so no secrets go into client configs.
| Client / surface | Works with a local server? | How |
|---|---|---|
| Claude Code (CLI, and the Code/Cowork sessions in Claude Desktop) | β
| `claude mcp add` |
| Claude Desktop chat β classic builds | β
| `claude_desktop_config.json` |
| Claude Desktop chat β newer "Extensions" builds | β
| install the `.mcpb` extension |
| Cursor / other stdio MCP clients | β
| `mcpServers` config entry |
| ChatGPT, and Claude on mobile | β (local) | needs a **remote** server β see [Remote / mobile / ChatGPT](#remote--mobile--chatgpt) |
### Claude Code (CLI or the Code/Cowork sessions in Claude Desktop)
Register it once at user scope (available in every session):
```bash
claude mcp add --scope user cookidoo -- \
"$(command -v uv)" run --directory /absolute/path/to/cookidoo-mcp cookidoo-mcp
```
Verify with `claude mcp list` (should show `cookidoo β¦ β Connected`). MCP tools
load when a session starts, so open a **new** session to see them.
### Claude Desktop chat β classic builds (config file)
Edit `claude_desktop_config.json`
(macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`) while
Claude Desktop is **fully quit**, then relaunch:
```json
{
"mcpServers": {
"cookidoo": {
"command": "/absolute/path/to/uv",
"args": ["run", "--directory", "/absolute/path/to/cookidoo-mcp", "cookidoo-mcp"]
}
}
}
```
Use the **absolute** path to `uv` (find it with `command -v uv`) β Claude Desktop
launches with a minimal `PATH` and often can't find a bare `uv`.
> Note: newer Claude Desktop builds (the "Cowork" / Extensions UI) **rewrite this
> file and drop custom `mcpServers`**. If your added server disappears after a
> restart, you're on a newer build β use the extension below instead.
### Claude Desktop chat β newer "Extensions" builds (`.mcpb`)
Newer builds load servers as **Extensions**. Build and install the bundle:
```bash
sh extension/build.sh # writes ~/Downloads/cookidoo.mcpb
```
The launcher (`extension/launch.sh`) finds `uv` on `PATH` and expects the repo at
`~/Documents/GitHub/cookidoo-mcp`; if yours lives elsewhere, either edit that file
or export `COOKIDOO_MCP_DIR=/path/to/cookidoo-mcp` before launching Claude, then
rebuild.
Install it:
1. Double-click `~/Downloads/cookidoo.mcpb` in Finder β **Install** in Claude, **or**
Claude β **Settings β Extensions β Advanced β Install Extensionβ¦** and pick the file.
2. If blocked as "unverified", enable local/unverified extensions in
Settings β Extensions (Advanced), then install.
3. `cookidoo` now appears in the **Connectors** menu (like the built-in
extensions) β toggle it **on**. First use logs in via your `.env`.
### Cursor / other stdio clients
Use the same `mcpServers` JSON as the classic-build example above.
### Remote / mobile / ChatGPT
**ChatGPT and the Claude mobile apps cannot run a local process on your machine**,
and ChatGPT does not support `.mcpb` extensions at all β both only talk to a
**remote** MCP server reachable over HTTPS. Making that work means:
1. Run the server with HTTP transport instead of stdio.
2. Add an authentication layer (a bearer token / OAuth) β a hosted server exposes
your Cookidoo account, so it must not be open to the internet.
3. Expose it over HTTPS (a `cloudflared`/`ngrok` tunnel for testing, or a small
always-on host).
4. Add it as a **custom connector** by URL: claude.ai β Settings β Connectors
(then it syncs to the Claude mobile app), or ChatGPT β Settings β Connectors /
developer mode (paid plans).
This is not wired up in v1 β it's the natural next step if you want mobile/ChatGPT.
---
Any client can call `get_skill("index")` first to discover the recommended workflows; clients with filesystem-skill support can instead load `skills/cookidoo-usage/SKILL.md` directly. Same content, two delivery paths.
---
## Example: "load a recipe, apply my tweaks, save it"
A representative transcript of the canonical flow (see `get_skill("recipe-tweaking")`):
> **User:** Load recipe r59322, make it for 6 people, swap the butter for olive oil, and save it.
>
> **Assistant:** *(calls `draft_tweak_from_recipe("r59322", target_servings=6)`)* Here's the scaled draft (4 β 6 servings). I applied your tweaks:
> - `200 g butter` β **`75 g olive oil`** *(swap + reduced, fat swaps aren't 1:1)*
> - `300 g flour` β `450 g flour` *(scaled)*
> - "salt to taste" β left unchanged (unscaled)
>
> Note: the library doesn't expose the original steps, so I've drafted them from your instructions. **Review and confirm before I save.**
>
> **User:** Looks good, save it.
>
> **Assistant:** *(calls `create_custom_recipe(...)` after confirmation)* Saved β
β `https://cookidoo.ch/created-recipes/de-CH/<id>`
> Reminder: it's readable on your Thermomix but does not include guided-cooking automation.
The rule the skill enforces: **never call `create_custom_recipe` without showing the final draft and getting an explicit yes.**
---
## Development
```bash
uv sync --extra dev
uv run ruff check .
uv run ruff format --check .
uv run pytest -q # pure-python unit tests, no network
```
Manual end-to-end verification against your own account: see [`tests/smoke.md`](tests/smoke.md).
### Security & privacy
- TLS verification is **always on**. The one workaround is clearing `VERIFY_X509_STRICT` (Vorwerk's certificate is missing the key-usage extension that Python 3.13+ enforces strictly); hostname and chain verification remain enabled. PRs that disable TLS verification are rejected on principle.
- Credentials only via env/`.env`; never logged (only the login email is logged, once, at INFO).
- No telemetry. The server talks only to the configured Cookidoo host.
- Destructive tools (`remove_*`, `clear_shopping_list`) declare their irreversibility in their docstrings so MCP clients surface it in approval prompts. The skill mandates explicit confirmation before `create_custom_recipe`, every `remove_*`, and `clear_shopping_list`.
## Acknowledgements
Builds on the prior art of [`otisthescribe/cookidoo-mcp`](https://github.com/otisthescribe/cookidoo-mcp) (structure, correct TLS handling, read/plan/shop tools), [`alexandrepa/mcp-cookidoo`](https://github.com/alexandrepa/mcp-cookidoo) (the `created-recipes` two-step create/PATCH, reimplemented here **without** disabling TLS), and the [`miaucl/cookidoo-api`](https://github.com/miaucl/cookidoo-api) library (auth, session, endpoint constants, typed models).
## License
[MIT](LICENSE)
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues