Files
Fizz f2d233b430 Initial commit: Mealie MCP server
Ports a working Hermes agent skill to an MCP server. The skill's value was not
its Mealie endpoints but ~25 operational rules found by running imports against
the live instance; those are now code with tests rather than prompt text.

The server owns deterministic mechanics — auth, the non-default User-Agent
Cloudflare requires, the `extension` field on cover uploads, PATCH instead of
the 500-ing bulk-action endpoints, decimal-comma normalization, and restoring
Swedish display text after parsing. Language and taste judgement stay with the
model, fed by the four reference notes shipped as MCP resources.

verify_recipe runs the finished-import definition as code so an agent cannot
report success on a recipe with an English ingredient line, a missing cover, or
ingredients still in the "Click Parse" state.

Home Assistant is optional and isolated; the Obsidian meal plan is out of scope.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 07:31:10 +02:00

66 lines
1.7 KiB
Markdown

# External Mealie hostname via Cloudflare
## Symptom
Authenticated API calls to `https://recept.famfallman.com` can fail with:
- HTTP `403 Forbidden`
- response body: `error code: 1010`
- `Server: cloudflare` header
This is not the same as a bad Mealie token (`401`).
## Reproduction
Python `urllib` with its default user-agent may trigger the block:
```python
import os, urllib.request
base = 'https://recept.famfallman.com'
token = os.environ['MEALIE_API_TOKEN']
req = urllib.request.Request(
f'{base}/api/users/self',
headers={'Authorization': f'Bearer {token}'},
)
urllib.request.urlopen(req, timeout=30)
```
Observed failure pattern:
- default `Python-urllib/...` user-agent -> `403`
- explicit `User-Agent: Hermes-Debug/1.0` -> `200`
- `curl` with explicit user-agent -> `200`
## Working patterns
### curl
```bash
BASE_URL="${MEALIE_BASE_URL:-https://recept.famfallman.com}"
AUTH=(-H "Authorization: Bearer $MEALIE_API_TOKEN")
UA=(-H "User-Agent: Hermes-Debug/1.0")
curl -s "$BASE_URL/api/users/self" "${AUTH[@]}" "${UA[@]}"
```
### Python
```python
headers={
'Authorization': f'Bearer {token}',
'User-Agent': 'Hermes-Debug/1.0',
}
```
## Interpretation
If the same token works on the LAN URL and the external host returns Cloudflare `403/1010`, suspect edge/WAF bot filtering before suspecting Mealie auth, DNS, or the token.
## Import-response quirk discovered in the same session
`POST /api/recipes/create/url` may return a JSON string slug like:
```json
"grillat-laxpaket-med-sparris"
```
Do not assume the import response is a full object. Follow with:
```bash
curl -s "$BASE_URL/api/recipes/<slug>" "${AUTH[@]}" "${UA[@]}"
```
to verify title, image, and parsed ingredients.