mealie-mcp
A read-only MCP server for Mealie that enables searching recipes, managing shopping lists, meal plans, and retrieving household/instance info via tools. Supports secure per-user authentication and multiple Mealie instances.
README
mealie-mcp
A Model Context Protocol server for Mealie, built with FastMCP and served over the Streamable HTTP transport. Ships as a Docker container.
It exposes tools only — no MCP resources or prompts. It is read-only by
default; write tools can be enabled with MEALIE_READONLY=false.
How auth works
There are two independent credentials:
| Credential | Header | Purpose |
|---|---|---|
| MCP endpoint token | Authorization: Bearer <token> |
A static secret (set via MCP_AUTH_TOKEN) that gates the server. Requests without a valid token are rejected with 401. |
| Mealie API token | X-Mealie-Token: <token> |
Supplied per request by each client. The server forwards it to Mealie as a bearer token, so one server can serve many Mealie users. |
Optionally, a client can target a different Mealie instance per request with the
X-Mealie-Url: https://other-mealie.example.com header (otherwise MEALIE_BASE_URL
is used).
Get a Mealie API token from your Mealie profile: Profile → Manage API Tokens.
Tools
Read tools (always available)
Recipes — search_recipes, get_recipe, get_recipe_suggestions
Reference data — list_categories, list_tags, list_tools, list_foods, list_units, list_cookbooks
Household — get_shopping_lists, get_shopping_list, get_meal_plan, get_todays_meals
Instance — get_current_user, get_app_info
Write tools (only when MEALIE_READONLY=false)
Recipes — create_recipe_from_url, create_recipe, update_recipe, delete_recipe, mark_recipe_made
Shopping — add_shopping_item, set_shopping_item_checked, add_recipe_to_shopping_list
Meal plans — create_mealplan_entry, delete_mealplan_entry
Write tools respect the per-request Mealie token's own permissions, so a read-only Mealie token can never mutate data even when write tools are enabled.
Run with Docker
cp .env.example .env
# edit .env: set MCP_AUTH_TOKEN (a long random secret) and MEALIE_BASE_URL
docker compose up --build -d
The MCP endpoint is then available at http://<host>:8000/mcp, with an
unauthenticated liveness probe at http://<host>:8000/healthz.
The endpoint token is the only thing standing between the internet and your Mealie instance. Put the server behind a reverse proxy with TLS, or on a private network, and use a long random
MCP_AUTH_TOKEN.
Run locally (without Docker)
pip install -r requirements.txt
export MCP_AUTH_TOKEN="a-long-random-secret"
export MEALIE_BASE_URL="https://mealie.example.com"
python main.py
Connecting a client
Point your MCP client at the Streamable HTTP endpoint and send both headers. Example with the FastMCP client:
from fastmcp import Client
from fastmcp.client.transports import StreamableHttpTransport
transport = StreamableHttpTransport(
url="http://localhost:8000/mcp",
headers={
"Authorization": "Bearer <your MCP_AUTH_TOKEN>",
"X-Mealie-Token": "<your Mealie API token>",
},
)
async with Client(transport) as client:
tools = await client.list_tools()
result = await client.call_tool("search_recipes", {"search": "soup"})
LibreChat
See examples/librechat.yaml for a ready-to-use
mcpServers entry. It maps the endpoint bearer token to a LibreChat environment
variable and each user's Mealie token to a per-user customUserVars field, so
every LibreChat user acts as their own Mealie account.
Set
requiresOAuth: falseon the server entry. This server uses a static Authorization Bearer gate, not OAuth. Without the flag, LibreChat's OAuth auto-detection probes the endpoint without your headers, gets a401, and misclassifies the server as OAuth-protected — so it never sends your token (you'll see401s followed by/.well-known/oauth-*404s). See Troubleshooting.
Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
MCP_AUTH_TOKEN |
yes | — | Comma-separated secret bearer token(s) for the MCP endpoint. |
MEALIE_BASE_URL |
no¹ | — | Default Mealie base URL (e.g. https://mealie.example.com). |
MEALIE_READONLY |
no | true |
Set false to also register write tools. |
MEALIE_TIMEOUT |
no | 30 |
Outbound request timeout in seconds. |
MEALIE_VERIFY_SSL |
no | true |
Set false for self-signed Mealie certs. |
MCP_HOST |
no | 0.0.0.0 |
Bind address. |
MCP_PORT |
no | 8000 |
Bind port. |
MCP_PATH |
no | /mcp |
Endpoint path. |
MCP_LOG_LEVEL |
no | info |
uvicorn log level. |
MCP_AUTH_DEBUG |
no | false |
Log a masked diagnostic for each request hitting the auth gate (to troubleshoot 401s). See Troubleshooting. |
¹ Required unless every client sends the X-Mealie-Url header.
Troubleshooting 401 Unauthorized
A 401 means the endpoint token (the Authorization: Bearer <token> gate,
not your Mealie token) was missing or didn't match MCP_AUTH_TOKEN. Many MCP
clients react to a 401 by probing for OAuth (GET /.well-known/oauth-*, which
this server returns 404 for, since it uses static tokens, not OAuth) — those
404s are a symptom of the 401, not a separate problem.
To see exactly what the gate receives, set MCP_AUTH_DEBUG=true and reconnect.
Each request to the gate is logged with a masked summary (the token itself
is never logged — only its length and a SHA-256 fingerprint):
auth-debug enabled: accepting 1 token(s) with fingerprints ['0c45a1f1']
auth-debug: POST /mcp authorization=scheme=Bearer token_len=10 fp=0c45a1f1 matches_configured=True -> 200
auth-debug: POST /mcp authorization=scheme=Bearer token_len=5 fp=02b60b3b matches_configured=False -> 401
auth-debug: POST /mcp authorization=absent (no Authorization header reached the server) -> 401
auth-debug: POST /mcp authorization=scheme=Bearer <empty token> -> 401
Read it as:
matches_configured=False— the client sent a token, but it doesn't equal anyMCP_AUTH_TOKENvalue. Check for typos, quoting, or trailing whitespace.absent— noAuthorizationheader reached the server. The client isn't sending it, or a reverse proxy/ingress stripped it before it arrived. With LibreChat this is usually OAuth auto-detection probing without your headers — setrequiresOAuth: falseon the server entry (see above).<empty token>— the client sentAuthorization: Bearerwith no value, typically an unset${...}variable in the client config.matches_configured=True -> 200— the gate is fine; the problem is elsewhere.
Docker Hub images
Released versions are published to Docker Hub at
georgx22/mealie-mcp
(multi-arch: linux/amd64, linux/arm64):
docker run -d -p 8000:8000 \
-e MCP_AUTH_TOKEN="a-long-random-secret" \
-e MEALIE_BASE_URL="https://mealie.example.com" \
georgx22/mealie-mcp:latest
CI/CD
Three GitHub Actions workflows are included (.github/workflows/):
ci.yml— runsruff,pyright, andpyteston every push/PR (Python 3.11–3.13).docker-publish.yml— builds and pushes the multi-arch image to Docker Hub when a GitHub Release is published (tagsX.Y.Z,X.Y,X, andlatest).claude.yml— runs Claude Code when someone mentions@claudein an issue, PR, or review comment.
Configure these repository secrets (Settings → Secrets and variables → Actions):
| Secret | Used by | How to get it |
|---|---|---|
DOCKERHUB_USERNAME |
docker-publish | Your Docker Hub username (with push access to georgx22/mealie-mcp). |
DOCKERHUB_TOKEN |
docker-publish | A Docker Hub access token (Account Settings → Security → New Access Token). |
CLAUDE_CODE_OAUTH_TOKEN |
claude | Run claude setup-token locally (Claude Pro/Max), paste the token. |
To cut a release (which triggers the image build):
gh release create v0.1.0 --generate-notes
Development
pip install -e ".[dev]"
ruff check . # lint
pyright # type check
pytest -q # tests
See CONTRIBUTING.md for details. Changes are tracked in CHANGELOG.md. Licensed under MIT.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。