Mealie MCP Server

A Model Context Protocol (MCP) server that connects AI assistants to your
Mealie recipe database through clients
such as Claude Desktop.
Contents
Features
- Recipes: Create, read, update, import, duplicate, and delete recipes.
- Search: Filter by text, categories, tags, and tools with AND/OR logic.
- Images and assets: Upload recipe images and files, or set images from URLs.
- Nutrition and display: Set per-serving nutrition and recipe visibility
settings such as
showAssets and showNutrition.
- Ingredients: Resolve free-text ingredients against Mealie's food and unit
vocabulary.
- Shopping lists: Manage lists and items, perform bulk operations, and add
recipe ingredients with quantity scaling.
- Organization: Manage categories, tags, foods, units, and recipe tools; find
unused categories and tags.
- Meal planning: View, create, update, and delete meal plan entries, create
multiple entries, and mark recipes as made today.
Quick Start
Prerequisites
- Python 3.12+
- A running Mealie instance and an API key from your account settings
- Package manager uv
Installation
Option 1: Using the MCP SDK CLI (Recommended)
Clone the repository, then install the server into Claude Desktop with the
mcp command supplied by the Python MCP SDK (no standalone fastmcp package
is needed):
git clone https://github.com/rldiao/mealie-mcp-server.git
cd mealie-mcp-server
uv sync --locked
uv run mcp install src/server.py --with-editable . \
--env-var MEALIE_BASE_URL=https://your-mealie-instance.com \
--env-var MEALIE_API_KEY=your-mealie-api-key
Option 2: Using uvx
Add this to your MCP client's configuration to run directly from GitHub without
cloning (in Claude Desktop, use claude_desktop_config.json):
{
"mcpServers": {
"mealie-mcp-server": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/rldiao/mealie-mcp-server",
"mealie-mcp-server"
],
"env": {
"MEALIE_BASE_URL": "https://your-mealie-instance.com",
"MEALIE_API_KEY": "your-mealie-api-key"
}
}
}
}
Restart Claude Desktop to load the server.
Configuration
Set environment variables in your MCP client configuration or shell. For a local
checkout, you can also copy .env.template to .env and fill in
your instance details. Never commit your API key.
Remote Access
The default stdio transport is for local clients. To serve HTTP clients, configure
your Mealie credentials as described above and run from the checkout:
export MCP_TRANSPORT=streamable-http
export MCP_HOST=127.0.0.1
export MCP_PORT=8765
uv run mealie-mcp-server
The server will expose its MCP endpoint at http://<host>:<port>/mcp.
Security: HTTP transports have no built-in authentication. Anyone who can
reach the endpoint can use the configured Mealie credentials through its tools.
Keep it on a trusted interface; for remote access, use a reverse proxy that
enforces authentication and HTTPS.
Docker
The Dockerfile runs the server as a persistent container.
Build
docker build -t mealie-mcp-server .
Standalone
docker run -d \
--name mealie-mcp \
-e MEALIE_BASE_URL=http://your-mealie-host:9000 \
-e MEALIE_API_KEY=your-mealie-api-key \
-e MCP_TRANSPORT=streamable-http \
-e MCP_HOST=0.0.0.0 \
-e MCP_PORT=8765 \
-p 127.0.0.1:8765:8765 \
mealie-mcp-server
The port is published only on the host's loopback interface. See
Remote Access before making it reachable remotely.
Docker Compose
Add this service to the Compose file that runs Mealie. The example assumes that
the Mealie service is named mealie and both services use a network named
mealie_net, defined in that Compose file. Set MEALIE_API_KEY in the shell or
Compose .env file.
services:
mealie-mcp:
build: .
container_name: mealie-mcp
restart: unless-stopped
environment:
MEALIE_BASE_URL: http://mealie:9000
MEALIE_API_KEY: ${MEALIE_API_KEY}
MCP_TRANSPORT: streamable-http
MCP_HOST: "0.0.0.0"
MCP_PORT: "8765"
expose:
- "8765"
networks:
- mealie_net
expose does not publish a host port. Connect a reverse proxy on the same network
for remote access, following the HTTP security guidance.
Usage Examples
"Search for chicken recipes"
"Create a new recipe for pasta carbonara"
"Mark the meatloaf recipe as made today"
"Create a shopping list for this week"
"Add all ingredients from the lasagna recipe to my shopping list"
"Plan chicken soup for lunch on Friday"
See Usage Examples for detailed workflows and troubleshooting.
get_recipes - List/search recipes with advanced filtering
get_recipe - Get complete recipe details, or a summary with concise=true
create_recipe - Create a recipe; only the name is required, with optional
ingredients, instructions, metadata, nutrition, and display settings
import_recipe_from_url - Import a recipe from a web page
update_recipe - Update content or metadata, including nutrition and display
settings; omitted fields are preserved, and empty lists clear content
duplicate_recipe - Clone a recipe
mark_recipe_last_made - Update last made timestamp
set_recipe_image_from_url - Set image from URL
upload_recipe_image_file - Upload image file
upload_recipe_asset_file - Upload document/asset
update_recipe_categories_and_tags - Replace or clear categories, tags, or both using IDs
delete_recipe - Delete recipe
get_shopping_lists - List all shopping lists
create_shopping_list - Create new list
get_shopping_list - Get list by ID
update_shopping_list - Rename a list while preserving other fields
delete_shopping_list - Delete list
add_recipe_to_shopping_list - Add recipe ingredients
remove_recipe_from_shopping_list - Remove recipe ingredients
get_shopping_list_items - List all items
get_shopping_list_item - Get item by ID
create_shopping_list_item - Create single item
create_shopping_list_items_bulk - Create multiple items
update_shopping_list_item - Update item (preserves fields)
update_shopping_list_items_bulk - Update multiple items
delete_shopping_list_item - Delete single item
delete_shopping_list_items_bulk - Delete multiple items
get_categories - List/search categories
get_empty_categories - Find unused categories
create_category - Create new category
get_category - Get by exactly one of category_id or category_slug
update_category - Update category
delete_category - Delete category
get_tags - List/search tags
get_empty_tags - Find unused tags
create_tag - Create new tag
get_tag - Get by exactly one of tag_id or tag_slug
update_tag - Update tag
delete_tag - Delete tag
get_foods - List/search foods (resolve IDs for structured ingredients)
create_food - Create a new food
get_food - Get by ID
update_food - Update food
delete_food - Delete food
get_units - List/search units
create_unit - Create a new unit
get_unit - Get by ID
update_unit - Update unit
delete_unit - Delete unit
get_tools - List/search recipe tools (includes householdsWithTool)
create_tool - Create a new tool
get_tool - Get by exactly one of tool_id or tool_slug
update_tool - Update tool
delete_tool - Delete tool
parse_ingredients - Resolve one or more ingredient lines in one request; always returns a list
get_all_mealplans - List meal plans
create_mealplan - Create meal plan entry
create_mealplan_bulk - Create multiple entries
update_mealplan - Update an entry while preserving omitted fields
delete_mealplan - Delete an entry
get_todays_mealplan - Get today's meals
Total: 61 tools
With MEALIE_ENABLE_AI_IMPORT=true, import_recipe_with_ai adds one optional
recipe operation: 62 total tools, including 13 recipe tools. It is absent
from discovery and cannot be called when disabled.
Redundant MCP names have been removed, not retained as aliases. Refresh your
client's tool list and update saved calls:
Existing create_recipe and update_recipe calls remain supported. Recipe
updates can now combine content and metadata, with omitted or null fields left
unchanged. Ingredient and instruction lists replace only the provided fields.
Nutrition remains a whole-object replacement, while settings are merged.
Distinct operations remain separate: single and bulk writes have different
response/failure contracts; paginated lists differ from individual lookups,
unused-organizer queries, and today's meal plans. Recipe URL import, image URL
scraping, and file uploads also perform different operations.
Optional AI recipe import
Set MEALIE_ENABLE_AI_IMPORT=true in your MCP client's environment, shell, or
local .env. Restart the server and refresh the client's tool list. This applies
to stdio, SSE, and Streamable HTTP. Offline SDK discovery remains configuration-
and network-free, listing only default tools; optional registration occurs at
runtime startup (or when passing an explicit enabled ServerConfig).
import_recipe_with_ai requires Mealie 3.23.0+ and a default AI provider
configured for the API user's group. It accepts any combination of:
content: plain text, raw HTML, or JSON; also used for corrections or notes.
url: an HTTP(S) recipe or video URL, fetched by Mealie and saved as the source.
image_paths: ordered image paths accessible to the MCP server's filesystem,
not a remote caller's computer. Multiple photos become one recipe; the first
becomes its cover image.
At least one nonblank source is required. Sources are combined, with pasted
content taking precedence when they disagree. Optional translate_language
requests translation. create_new_organizers defaults to false: matching
existing tags, categories, and kitchen tools may be assigned, but new ones are
created only when explicitly requested.
Before each import the server reads /api/groups/self to check aiEnabled and,
for photos, imageProviderEnabled. Missing/malformed capabilities or a failed
lookup produce an explicit error, not a silent disabled result. Video detection
and the audio-provider requirement are handled by Mealie. These checks establish
configuration, not provider connectivity, credentials, or available quota.
This tool immediately creates and saves a recipe. Source material is processed
by Mealie's configured AI providers and may incur charges. Review the returned
recipe for accuracy. The import has a 300-second read timeout; other API calls
retain their existing timeouts. No imports are automatically retried. After a
timeout or connection failure, check Mealie before retrying or switching tools:
creation may already have succeeded. If the follow-up fetch fails, the error
includes created_slug and stage; retrieve that recipe rather than importing again.
Choose the tool according to the task:
The opt-in controls only this new tool. It does not disable Mealie's own AI
fallback for URL scraping or other existing AI features. See
Mealie's AI import documentation
and usage examples.
Development
Setup
After cloning the repository, install development dependencies:
uv sync --locked --extra dev
For manual testing, configure your Mealie instance:
cp .env.template .env
# Edit .env with your Mealie instance details
Launch the MCP Inspector:
uv run mcp dev src/server.py
Run the offline checks; these do not require a Mealie instance or credentials:
uv run ruff check src tests
uv run pytest -q
Project Structure
Repository conventions are in AGENTS.md, with focused guidance for
source code and tests.
The automated suite uses fake HTTP responses and includes local HTTP-transport
checks. It does not replace compatibility testing against your deployed Mealie
version.
Important Notes
The calls below use Python-style notation to illustrate MCP tool arguments; they
are not standalone Python scripts.
When filtering recipes, you must use slugs or UUIDs, not display names:
Use get_tags() or get_categories() first to find the correct slugs:
get_recipes(tags=["quick-meals", "healthy"])
For example, pass quick-meals, not the display name Quick Meals.
Nutrition Is Replaced, Not Merged
Mealie replaces the whole nutrition object on write. update_recipe follows
suit, so pass every value you want to keep:
# Clears every nutrition value except fat.
update_recipe(slug="...", nutrition={"fatContent": "12"})
Parsing Ingredients in Bulk
Resolving ingredients by hand costs one to two get_foods / get_units calls
each. parse_ingredients does a whole recipe in one request and returns results
that can be handed straight to create_recipe:
parse_ingredients(ingredients=["1/4 cup chopped onion", "2 large eggs"])
# -> [{"input": "1/4 cup chopped onion", "confidence": 0.99, "quantity": 0.25,
# "unit": {"id": "...", "name": "cup"},
# "food": {"id": "...", "name": "onion"}, "note": "chopped"}, ...]
A null unit or food means your instance has no matching entry; create one
with create_food / create_unit, or leave the text in the note. Pass
verbose=True for Mealie's full response including per-field confidences.
Uploaded Assets and Nutrition Can Be Stored but Hidden
A recipe's settings object controls what the UI renders. showAssets and
showNutrition gate the assets and nutrition cards, so an asset uploaded with
upload_recipe_asset_file can be present in the API response and still be
invisible in the web UI. Flip the toggle with:
update_recipe(slug="...", settings={"showAssets": True})
Mealie seeds a new recipe's settings from the household preferences
(recipeShowAssets, recipeShowNutrition, ...), so the defaults differ per
instance. Check rather than assume.
Only the toggles you pass are changed. The tool reads the recipe's current
settings and sends the merged object, because Mealie does not reliably preserve
toggles omitted from a settings PATCH.
Field Preservation
When updating shopping list items, both single and bulk updates fetch the current
records and preserve omitted fields. You only need to specify the fields you
want to change:
# Only updates 'checked' field, preserves note, quantity, etc.
update_shopping_list_item(item_id="...", checked=True)
Bulk shopping inputs accept snake_case names such as shopping_list_id and
Mealie's camelCase names such as shoppingListId. Conflicting aliases and
duplicate IDs in a bulk update are rejected before writing.
Meal Plan Validation and Clearing
Meal dates must use YYYY-MM-DD, and entry types must be breakfast, lunch,
dinner, or side. Creation requires a recipe or a nonblank title. Bulk meal
plans are validated in full before any entries are created.
Omitted update fields remain unchanged. To remove an existing recipe link,
use update_mealplan(entry_id="...", clear_recipe=True, title="Leftovers").
Do not combine clear_recipe with a replacement recipe_id.
Recovering from Partially Completed Writes
Recipe creation/population and bulk meal-plan creation require multiple API
requests and are not atomic. If a later request fails, the tool error includes
recovery information identifying completed work. Inspect that information and
the current Mealie state rather than blindly retrying the entire operation.
A failed or timed-out request may have completed remotely.
Support and Contributing
License and Credits
Licensed under the MIT License.