Releases: mgummich/mcp-mealie
Releases · mgummich/mcp-mealie
Release list
v0.3.1
Fixed
- Deleting a food or unit that is still on a recipe or shopping list now
answers with an error naming the way out. Mealie deletes the row directly,
so a reference from anywhere still pointing at it comes back as a foreign
key violation, and nothing in this server can repoint those rows. The raw
"Mealie returned 409: ForeignKeyViolation" said nothing about that; the
error now points atmergefor the resources that support it.docs/HOWTO.md
also now notes thatlibrary_statscounts recipe usage only, so a food it
reports as unused may still be sitting on somebody's shopping list. - The
update_recipedocstring named the wrong field for the slug to use
after a rename. "The result carries the new slug plusrenamed_from— use
that slug" pointed atrenamed_from, its nearest antecedent, which is the
old slug and a 404 from then on. It now says to useslug, the live one.
v0.3.0
Added
delete_recipefalls back toPOST /api/recipes/bulk-actions/deletewhen
the row-level delete answers 5xx, which is what a recipe whose rows Mealie's
ORM cannot cascade does. The result says when the fallback ran. A 404 still
fails as before, so a typo is never answered by a second attempt.MealieError, aToolErrorsubclass carrying the HTTP status, so a tool can
branch on the status rather than on message text.- A spec describing the server as built —
docs/superpowers/specs/2026-08-10-mealie-mcp-current-state.md. Every tool
with its endpoint, the caches, the write semantics, and which parts of
Mealie's API this deliberately does not expose. The 2026-08-09 design
document is marked superseded; it was a plan, and the code had moved.
Fixed
- Taxonomy objects are trimmed to the keys a write accepts before they go into
a recipe payload. Foods, units, tags, categories, and tools come off a read
carryingcreatedAt,updatedAt, andhouseholdsWithIngredientFood, which
a write has no business echoing back — Mealie 3.22 tolerates them, but they
have been reported as 500s elsewhere and Mealie hydrates the row from its own
id regardless. The same trim applies to the existing tags a merge in
update_recipereads back. - An ingredient line Mealie's parser could not resolve no longer keeps the
parsed quantity. The whole source line becomes the note, so the amount was
stored twice and rendered as "500 500 g flour". - A 5xx now reports FastAPI's
detailwhen the body carries one, instead of
the raw first 200 characters of JSON. - The howto said
manage_taxonomy(action="list")pages at 200. It pages at 50,
so anyone sizing a sweep off that number was out by a factor of four. - The install note told readers to keep the
@v0.2.0pin while every command
around it usedv0.2.1.
v0.2.1
Changed
- Releases are cut as GitHub Releases with the wheel and sdist attached,
instead of being published to PyPI. Installs read the tag directly, so the
tag is the distribution; the publish step needed a PyPI account that does
not exist and failed on 0.2.0 without uploading anything.docs/RELEASING.md
records what putting it on an index would take. - The release workflow reads its notes from the matching
CHANGELOG.md
section and fails when there is none, rather than publishing an empty
release. Its three jobs collapse into one — they existed to hand artifacts
between runners for the upload that is now gone.
Fixed
- The install tag in
README.mdanddocs/HOWTO.mdis pinned to
__version__by a test. Both files carry it since installs come from git,
and a release that bumped the version without touching them left a command
that looks current but installs the previous server.
v0.2.0
Added
bulk_tag_recipes(slugs, tags, categories)— adds tags and categories to
many recipes through Mealie's bulk-action endpoints, creating names that do
not exist yet. Adds only; removal stays withupdate_recipe.upload_recipe_image(slug, path)— sends a local image file as a recipe's
image, including theextensionform field Mealie's multipart handler
requires.set_recipe_imagestill covers images already on the web.library_stats(resource)— usage rollup for tags, categories, tools, foods,
or units in one call: every item with its recipe count, unused ones included.
Mealie has no endpoint for this, so it sweeps the recipe list server-side
instead of costing one search per name.find_duplicate_recipes()— groups recipes whose names match once case and
punctuation are ignored.check_recipe_links()— probes source URLs from outside Mealie (never
sending the API token to a third party) and lists recipes with no image.update_cookbook(cookbook_id, ...)— rename or re-filter a cookbook in
place, instead of delete-and-recreate losing the id.create_cookbookandupdate_cookbookaccepttags,categories,tools,
andrequire_all, building thequeryFilterStringserver-side with Mealie's
stored name casing.query_filterremains for filters names can't express.manage_taxonomyacceptsitems=[...]to batch create, update, merge, or
delete in a single call, reporting per-item failures rather than stopping at
the first bad id.search_recipesacceptsfields— the same projectionget_recipehas,
minus ingredients, instructions, and notes, which Mealie's search payload
does not carry.set_recipe_image(slug, url)— set or repair a recipe's image from an
image URL.manage_taxonomygainsupdateandmergeactions.updatepatches onto
the current row, so food descriptions, plural names, aliases, label
assignments, unit abbreviations, and organizer renames are all reachable.
mergeuses Mealie's own/api/foods/mergeand/api/units/merge, which
repoint every recipe that used the duplicate.manage_taxonomysupports thelabelsresource (/api/groups/labels), so
food labels can be created, renamed, and assigned.update_recipeacceptsnotes,tools,rating, andreplace_tools.get_recipereturnstoolsin the default view.
Removed
- The bundled skill (
skills/). Its workflows moved to
mealie-skill, which already
covers the same instance and now drives this server directly. Two skills for
one server meant two descriptions in every prompt and two copies of the same
guidance to keep in sync.
Changed
- Tool results are sent once, as JSON text. MCP returns a tool's value both as
a text block and asstructuredContent, and both cross the wire; the
duplicate is pure token cost for a client that reads the text. Output
schemas — which said no more than "an object", and are what oblige the
server to send the structured copy — go with it. A 300-tag
library_statswent from roughly 12k tokens on the wire to 5k. library_statstakestop(default 50): used and unused items each get
that many rows, and the reply reports how many there are in total. Every row
carries a UUID, and neither the tail of the used list nor a 193-item unused
list is what anybody reads — on a real instance the tags rollup went from
20k to 8k characters.manage_taxonomylistreturns 50 rows a page rather than 200. A food
carries description, plural name, label, and aliases, so a full page was a
12k-token reply; it is now 3k, and the pagination note already says how to
ask for the rest.- The foods and units rollups fetch each recipe body once per process instead
of once per call. Mealie has no ingredient-usage endpoint, so those two
reports sweep the whole library; asking for foods and then units paid for
the same 262 requests twice. Any write drops the cache. Measured on a
262-recipe instance: 12.3s cold, 2.5s warm. search_recipescapslimitat 100 rows a page. Mealie will return the
whole library in one reply if asked, and the reply is the expensive part;
the pagination note already says how to ask for the rest.- Requests are logged at DEBUG as method, path, and status — set
MEALIE_LOG_LEVEL=DEBUGto see them. The token is never logged.
Fixed
manage_taxonomylistsilently truncated at 200 rows. It now takes a
pageargument and reports the total plus the next page to request.update_recipereportedrecipe 'x' not foundafter successfully renaming
one. Mealie derives the slug from the name, so the read-back used a slug
that no longer existed. The update response is now read from the PATCH
itself and carries the new slug, plusrenamed_fromso the caller can see
the slug moved rather than infer it.import_recipe_from_urlreturned a recipe reading "Could not detect
ingredients" as though the import had worked. Pages that render their recipe
in the browser now come back with a note saying the scrape found nothing.- A 500 from Mealie was always reported as "the server is unhealthy",
discarding the response body. Whatever Mealie sent back is now included. - A malformed item in a
manage_taxonomybatch failed the whole call. Only
ToolErrorwas caught, so adatavalue that was not an object raised
TypeErrorpast the per-item handler and stranded the other writes. Such an
item is now reported inerrorslike any other bad one. create_recipeandimport_recipe_from_urlsent a follow-up request to
/api/recipes/Nonewhen Mealie's create response carried no slug, surfacing
as a confusing 404. They now say the recipe exists but cannot be read back.create_recipeandupdate_reciperaised an internal error when Mealie's
ingredient parser returned fewer results than lines sent. That mismatch is
now a plain tool error, and nothing is written.- The recipe-body cache is bounded. A whole-library sweep pinned every fetched
recipe for the life of the process; pastMAX_CACHED_DETAILSentries the
cache is dropped instead of grown. - Parsing ingredients no longer drops that cache.
POST /api/parser/ingredients
writes nothing, but counted as a write, so everycreate_recipemade the
next foods or units rollup sweep the library again. - Taxonomy snapshots are paged instead of read as one 1000-row request. Past
that many foods, a name that already existed looked missing, and
resolve_taxonomycreated a duplicate of it;library_statsreported the
same items as unnamed. Both now walk every page. manage_taxonomyno longer documentscreate,update,merge, and
deletewhen the server is read-only, where all four are refused.scripts/smoke.pyprintednullfor every tool and crashed on--write.
It readresult.data, which is empty since results stopped being sent
twice; it now decodes the JSON text block like the tests do.