cookidoo-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cookidoo-mcp upload a new chocolate chip cookie recipe"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cookidoo-mcp
An MCP server that bridges LLM sessions (Claude, Gemini, or any MCP client) to Cookidoo custom recipes on a Thermomix (TM7 by default). Describe a recipe in a chat, and the server uploads it as a Cookidoo custom recipe with proper structured Thermomix settings (time, temperature, speed, reverse) so it looks and behaves like an official recipe on the device.
The server ships its own German authoring guide as an MCP prompt and resource, so the writing rules for Thermomix steps do not have to live in your prompts.
Disclaimer: Cookidoo/Vorwerk offers no official public API. This project relies on the reverse-engineered API of miaucl/cookidoo-api and may break whenever the Cookidoo backend changes. Use at your own risk.
Prior art this project builds on:
miaucl/cookidoo-api - the unofficial Cookidoo API library used for login and session handling
alexandrepa/mcp-cookidoo - first Cookidoo MCP server, source of the create/patch upload flow
Xdev22/cookidoo-mcp - discovered the structured TTS and INGREDIENT annotations that make custom recipes look like official ones
Features
upload_recipe- upload a recipe with structured ingredients and steps. The LLM supplies semantics only (text, time, temperature, speed, reverse); the server renders the German settings notation and computes all Cookidoo annotations itself. Optionalimage_url/image_base64parameters attach a photo in the same call.set_recipe_image- set or replace the photo of an existing custom recipe, from an https URL or base64 data.list_custom_recipes- list your custom recipes.get_custom_recipe- fetch one custom recipe by id.delete_custom_recipe- delete a custom recipe by id.get_recipe_details- fetch any Cookidoo recipe by id.get_shopping_list,add_items_to_shopping_list,add_recipe_to_shopping_list- read and fill the shopping list.get_meal_plan,add_recipe_to_meal_plan- read and fill the weekly planner.MCP prompt and resource with the full German Thermomix authoring guide, plus compact server instructions delivered to every client on connect.
Optional GitHub OAuth with a user allowlist and persistent client registrations for safe public exposure.
Recipe images
Custom recipes can carry a photo. Pass image_url or image_base64
(exactly one source; base64 works with or without a data URI prefix) to
upload_recipe, or call set_recipe_image for a recipe that already
exists. JPEG and PNG are supported, from 80x80 pixels (smaller images are
rejected by Cookidoo) up to 10 MB. URL images are downloaded by the server
itself (https only), and Cookidoo re-hosts every image on its own CDN.
Clients should downscale images to about 800px (JPEG, quality around 70)
before embedding them as base64. An image failure does not
abort the recipe upload; the result then contains an image_warning
instead.
Related MCP server: Thermomix-MCP
Requirements
Python 3.12 or newer
A Cookidoo account with an active subscription
Setup
uv sync
cp .env.example .envThen edit .env and fill in your Cookidoo credentials:
Variable | Meaning | Default |
| Cookidoo account email | required |
| Cookidoo account password | required |
| Country code |
|
| Language code |
|
| Device written to the recipe tools field |
|
Locale examples:
Country |
|
|
Germany |
|
|
Austria |
|
|
Running
uv run cookidoo-mcpThis starts the server with streamable HTTP transport on
http://127.0.0.1:8000/mcp. Host and port are configurable via MCP_HOST
and MCP_PORT.
For clients that spawn the server as a subprocess, use stdio transport instead:
MCP_TRANSPORT=stdio uv run cookidoo-mcpClient configuration
Claude Code
claude mcp add --transport http cookidoo http://localhost:8000/mcpClaude Desktop
Add the server to your claude_desktop_config.json:
{
"mcpServers": {
"cookidoo": {
"type": "http",
"url": "http://localhost:8000/mcp"
}
}
}Public exposure and OAuth
Connectors on claude.ai (web, mobile app, and the Claude Desktop connector dialog) are established from Anthropic servers, so LAN-only deployments are not reachable there. To use the server from those clients it must be exposed to the internet - and then it MUST be protected, otherwise anyone could use your Cookidoo account.
The server supports GitHub OAuth via FastMCP:
Register an OAuth app at https://github.com/settings/developers. Homepage: your
MCP_BASE_URL; callback URL:<MCP_BASE_URL>/auth/callback.Set
GITHUB_CLIENT_ID,GITHUB_CLIENT_SECRET,MCP_BASE_URL,ALLOWED_GITHUB_USERS(and ideallyMCP_JWT_SIGNING_KEYplusMCP_STATE_DIRfor persistent client registrations - without it a restart disconnects all authorized clients) in the.envfile and restart the container.Make the server publicly reachable (see below).
Add the connector with your public
https://.../mcpURL; Claude redirects you through the GitHub login once per client.
Only the GitHub accounts listed in ALLOWED_GITHUB_USERS are accepted;
every other login is rejected after authentication. Without the GitHub
variables the server runs unauthenticated as before - keep it LAN-only
in that case.
Recommended public exposure: Cloudflare Tunnel
The battle-tested setup (and the one this project runs in production) is a Cloudflare Tunnel in front of a localhost-only server container:
Put a domain on Cloudflare (free plan; only the nameservers change, the registration stays where it is), create a tunnel under Zero Trust -> Networks -> Tunnels, and map a public hostname such as
cookidoo.example.comtohttp://localhost:8443.Run the connector next to the server (same host):
docker run -d --name cloudflared --network host \ --restart unless-stopped \ -e TUNNEL_TOKEN=<your tunnel token> \ cloudflare/cloudflared:latest tunnel runBind the server container to localhost only (the deploy script does this), drop the
MCP_SSL_*variables (Cloudflare terminates TLS with auto-renewing certificates) and setMCP_BASE_URLand the GitHub app URLs to the tunnel hostname.
This needs no router port forwarding and works behind DS-Lite or CGNAT, because the tunnel connects outbound and Cloudflare provides a dual-stack edge - important since the claude.ai connector infrastructure connects over IPv4 only, so an IPv6-only port release is never reached.
Known pitfall: Tailscale Funnel does NOT work as the public endpoint for claude.ai connectors. The funnel edge intermittently aborts TLS handshakes, and the multi-request OAuth flow of the connector broker gives up on the first failure, surfacing as "Couldn't reach the MCP server" with zero requests in your logs - even though curl and Claude Code work fine through the same funnel.
Testing
uv run pytestUnit and integration tests run offline against mocked HTTP. The end-to-end
tests in tests/test_e2e.py talk to the live Cookidoo API and are skipped
unless real credentials are present in .env.
Docker
Prebuilt image (recommended)
Every push to main builds a multi-arch image (amd64/arm64) via GitHub
Actions and publishes it as
ghcr.io/jsaedtler/cookidoo-mcp-docker:latest. On the server you only
need the credentials file and one script:
sudo mkdir -p /docker/cookidoo-mcp
sudo cp .env.example /docker/cookidoo-mcp/.env # fill in your credentials
./deploy/update-cookidoo-mcp.shdeploy/update-cookidoo-mcp.sh stops and removes the old container,
pulls the latest image and starts it again with --restart=unless-stopped.
Re-run it any time to update. Adjust the ENV_FILE, SSL_DIR,
STATE_DIR and PORT variables at the top of the script to your setup.
HTTPS without a tunnel
When you do not use the Cloudflare Tunnel (for example LAN-only use with
Claude Desktop, which requires an https URL), the server can terminate
TLS itself: set MCP_SSL_CERTFILE and MCP_SSL_KEYFILE and mount a
certificate directory into the container (the deploy script does this
via SSL_DIR). Any certificate you already have works, for example a
Let's Encrypt certificate from another service on the same host. The
hostname in the MCP URL must match the certificate. After a certificate
renewal restart the container (docker restart cookidoo-mcp) so it
picks up the new files.
Build locally
cp .env.example .env # fill in your Cookidoo credentials
docker compose up -d --buildThe server then listens on http://<host>:8000/mcp (Streamable HTTP) for
clients in your network. To change the port, adjust both sides of the
ports mapping in docker-compose.yml.
Notes:
Credentials are injected at runtime via
env_file; the.envfile is never baked into the image (see.dockerignore).The container binds
::(dual-stack). If the Docker daemon runs withip6tables: true, published ports are DNATed to the container's IPv6 address, so a v4-only bind would time out for all IPv6 clients even though the port looks open on IPv4.The image runs as a non-root user and builds on both amd64 and arm64.
Typical deployment on a server: clone the repository, create
.env, rundocker compose up -d --build. Therestart: unless-stoppedpolicy brings the container back after reboots.
Available Tools
11 toolsadd_items_to_shopping_listA
Setzt freie Artikel (z. B. "Milch") auf die Einkaufsliste.
Inputs: items (required). Returns: result
add_recipe_to_meal_planA
Plant ein Rezept fuer einen Tag (YYYY-MM-DD) im Wochenplan ein.
Fuer eigene Custom-Rezepte is_custom=true setzen.
Inputs: day (required), recipe_id (required), is_custom. Returns: object
add_recipe_to_shopping_listA
Setzt die Zutaten eines Rezepts auf die Einkaufsliste.
Fuer eigene Custom-Rezepte is_custom=true setzen.
Inputs: recipe_id (required), is_custom. Returns: result
delete_custom_recipeB
Loescht ein eigenes Custom-Rezept endgueltig.
Inputs: recipe_id (required). Returns: result
get_custom_recipeB
Liest ein eigenes Custom-Rezept mit Zutaten, Schritten und Annotationen.
Inputs: recipe_id (required). Returns: object
get_meal_planA
Liest den Wochenplan der Kalenderwoche, die den Tag (YYYY-MM-DD) enthaelt.
Inputs: day (required). Returns: result
get_recipe_detailsC
Liest die Details eines offiziellen Cookidoo-Rezepts.
Inputs: recipe_id (required). Returns: object
get_shopping_listA
Liest die Einkaufsliste: Rezepte, Zutaten und zusaetzliche Artikel.
Inputs: no named parameters. Returns: object
list_custom_recipesA
Listet alle eigenen Custom-Rezepte mit id, Name, Gesamtzeit und URL.
Inputs: no named parameters. Returns: result
set_recipe_imageA
Setzt oder ersetzt das Foto eines eigenen Custom-Rezepts.
Genau eine Bildquelle angeben:
image_url: https-URL eines JPEG- oder PNG-Bilds (maximal 10 MB); der Server laedt das Bild selbst herunter.
image_base64: Bilddaten als Base64, optional mit "data:image/...;base64,"-Praefix (z. B. Foto aus einem PDF). Das Bild vor der Einbettung auf ca. 800 px Kantenlaenge verkleinern und als JPEG mit Qualitaet ca. 70 speichern, damit die Anfrage klein bleibt.
Das Bild muss mindestens 80x80 Pixel gross sein, sonst lehnt Cookidoo es ab - beim Verkleinern also nicht unter diese Grenze gehen.
Inputs: recipe_id (required), image_url, image_base64. Returns: object
upload_recipeA
Laedt ein Custom-Rezept fuer den Thermomix nach Cookidoo hoch.
Regeln fuer den Aufbau (vollstaendige Anleitung: Resource cookidoo://rezept-anleitung):
Geraete-Einstellungen (Zeit, Temperatur, Stufe, Linkslauf) NIEMALS in den Schritt-Text schreiben. Nutze pro Schritt die strukturierten Felder time_seconds, temperature (37-120 oder "varoma"), speed (0.5-10 in halben Stufen, "turbo", "ruehrstufe") und reverse; der Server erzeugt die Notation und die Cookidoo-Annotationen selbst.
Schritt-Text im Imperativ, beginnt mit einem Verb, eine Aktion pro Schritt. Das Gefaess heisst immer "Mixtopf", niemals "Thermomix".
Zutatenmengen NIEMALS im Schritt-Text wiederholen; Artikel verwenden ("das Mehl zugeben", nicht "200 g Mehl zugeben"). Mengen stehen nur in der Zutatenliste mit getrennten Feldern quantity, unit und name.
Optional kann ein Rezeptfoto mitgegeben werden: image_url (https-URL, JPEG oder PNG) ODER image_base64 (Bild vorher auf ca. 800 px Kantenlaenge verkleinern, JPEG mit Qualitaet ca. 70; mindestens 80x80 Pixel, sonst lehnt Cookidoo es ab). Schlaegt nur das Bild fehl, wird das Rezept trotzdem angelegt und die Antwort enthaelt image_warning.
Das fertige Rezept zuerst dem Benutzer vollstaendig anzeigen und erst nach dessen ausdruecklicher Freigabe hochladen.
Inputs: name (required), steps (required), ingredients (required), hints, +5 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 11 tools
Each tool targets a distinct resource and action: custom recipe CRUD (upload/list/get/delete/set image), official recipe read, shopping list read/add, and meal plan read/add. Even similar tools like add_items_to_shopping_list and add_recipe_to_shopping_list are clearly differentiated by their target (free items vs. recipe ingredients).
All tool names follow a consistent verb_noun pattern (upload_recipe, list_custom_recipes, get_shopping_list, add_recipe_to_meal_plan). Verbs are consistent (list, get, add, set, delete) and nouns clearly indicate the resource. No mixed naming conventions.
With 11 tools, the server is well-scoped for its purpose. Each tool covers a core aspect of Cookidoo integration—custom recipes, official recipe details, shopping list, and meal plan—without unnecessary duplication or bloat.
The set has notable gaps: custom recipes can be created and read but not updated (except image), shopping list items and meal plan entries can be added but not removed, and there is no search or list for official recipes. These missing operations will cause agents to fail when users need to modify or remove data.
Maintenance
Related MCP Connectors
Recipe search, ingredient matching, nutrition filters and a private cookbook for any AI agent.
Your family recipe box inside ChatGPT and Grok. Save, scale, plan menus and share recipes.
Search, save, organize, cook, and share recipes with any AI assistant.
Save, import and edit recipes as interactive cards in ChatGPT and Claude, synced to your iPhone.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceLets Claude read recipes from your Cookidoo account and create TM7-optimized custom recipes with guided-cooking annotations, quality scoring, and automatic rollback on upload failure.MIT
- AlicenseAqualityDmaintenanceConverts recipes from any source (web, YouTube, Instagram, etc.) into Thermomix format with guided cooking steps and uploads them to Cookidoo.4MIT
- AlicenseAqualityDmaintenanceEnables interaction with the Thermomix Cookidoo platform, including authentication, recipe management, meal planning, and shopping list access through natural language.1663 PyPI2Apache 2.0
- AlicenseAqualityCmaintenanceEnables AI assistants to search, read, author, edit, favorite, and privately or publicly publish recipes on the Lidl cooking platform, including converting Paprika/Thermomix instructions into Smart device programs with automatic weighing steps.22Apache 2.0