Get started / MCP server (npm and registry) exp Edit on GitHubMarkdown

Cookwala as an MCP service

Status: experimental, read-only. Package @cookwala/mcp 0.1.0; registry name ai.cookwala/cookwala. It never starts cooking.

Cookwala is available to any Model Context Protocol client as a local server that reads the public catalog. There is no Cookwala server to run or pay for:

 your machine                                              GitHub Pages (cookwala.ai)
 MCP client ──stdio──▶ npx -y @cookwala/mcp ──HTTPS GET──▶ /v1/manifest.json, /v1/index/…,
 (Claude, Codex,        pure-JavaScript core               /v1/recipes/<id>.cookwala.json,
  Copilot, Cursor,      cache + hash checks                /v1/vocab/*, /v1/capabilities/*
  Windsurf, Devin, …)         │
                              └─ optional, read-only ────▶ fifi.cooking /data/… (the source site)

GitHub Pages serves static files over GET only, so a remote MCP endpoint cannot live there. A stdio server needs no endpoint: the client starts it. The same JavaScript core also runs in your browser on the MCP page, which is the proof that nothing runs on a server.

Install #

bash
npx -y @cookwala/mcp                       # speaks MCP on stdin/stdout (Node 20 or later)
claude mcp add cookwala -- npx -y @cookwala/mcp

Every client's configuration is on one page: AI agents. The generic form is:

json
{"mcpServers": {"cookwala": {"command": "npx", "args": ["-y", "@cookwala/mcp"]}}}

From a source checkout: cd sdk/mcp-js && npm install && node bin/cookwala-mcp.js. Point it at a locally built site with COOKWALA_BASE_URL=$PWD/_site (bash tools/build_site.sh _site).

Tools #

All fourteen are read-only (readOnlyHint: true, destructiveHint: false). Results carry structuredContent and a text copy. Errors set isError and return {error, detail, path}.

ToolPayloadReturns
search_recipesquery, lang, cuisine[], course, tags[], level (V0/V1/V2), allergen_free[], supervision, collection, limit (10, max 50), offset{total, items[{id,title,cuisine,course,level,servings,allergens,supervision,collection,license,hash}], nextOffset}
get_recipeid, lang, view (summary, ingredients, process, text, full){id, documentId, hash, hashVerified, level, levelNote, textIsData, recipe}
list_collectionsnone[{collection,count,license,source,citation,fifiText}]
list_operationsfamily, lang[{id,label,definition,envelope}]
explain_steprecipe_id, node, lang{node,op,label,envelope,params,until,hazards,ccp,unattendedAllowed,instruction,instructionIsData}
list_device_presetsnone{presets:[{id,name,kind,roles,ops,sensors,url}]}
dry_runrecipe_id or recipe; device (preset id or capabilities object); human_present, allow_model_estimates, limits, now`{state: accepted\refused, plan[], refusal{reason,node,detail}, note}`
check_envelopeop, readings[{t,tempC}], target{value,tolerance}, altitude_m{envelopeOk, targetOk, reason}
check_mandatemandate, action, amount, provider, now{allowed, needsConfirmation, reasons[]}
parse_smstextthe structured Humanitarian command, or {ok:false, error}
verify_reciperecipe{hash, declaredHash, matches, level}
catalog_statusnone{baseUrl, catalogVersion, generatedAt, counts, languages, cache, offline, signature, fifiOrigin}
fifi_searchquery, lang, limit, offset{total, items[{id, inCatalog, title, pageUrl}], nextOffset}
fifi_sourceidthe recipe in fifi.cooking's legacy format, under the catalog's rights rules (see below)

Resources: cookwala://recipe/{id}, cookwala://schema/{name}, cookwala://doc/{ID} (any page of these docs as Markdown), cookwala://preset/{id} (listed), cookwala://ops, cookwala://llms.txt. Prompts: cook_with_device, recipe_safety_brief, humanitarian_offer.

The semantics of dry_run, check_envelope and parse_sms are those of tools/cookwala_ref.py; the JavaScript core passes the same conformance vectors (conformance/) and the Python and Node servers give identical answers.

fifi.cooking and fifirecipes #

fifi.cooking is where the recipes are written; Cookwala is the standard form they are published in.

  • Standard route. tools/export_fifi.py turns every fifi.cooking recipe into a Cookwala document (EXPORT-FIFI); CI publishes them to /v1/recipes/. get_recipe and search_recipes read those. Each document keeps legacy.pageUrl and legacy.dataUrl, and get_recipe returns them under sources.fifi.
  • Live route. fifi_search and fifi_source read fifi.cooking's own /data/ files, so an agent can find recipes that were added after the last export. (The 161 world-cuisine recipes, ids w-*, were exported on 2026-10-06 and are now in the catalog, facts only.) They are the only calls that leave the catalog origin, they contact https://fifi.cooking only, and they are marked openWorldHint.
  • Rights rules apply on the live route too. fifi_source returns steps and notes only for collections whose text policy in tools/export_fifi.collections.json is full. Every other collection, and any collection not listed there, returns structured facts only, exactly as the catalog does. The response says textPolicy and what was withheld.
  • Getting a new recipe into the standard is a maintainer step, not a tool call: confirm its collection's rights in export_fifi.collections.json (the exporter files an unlisted collection under archive with full text, so add the entry first), run export_fifi.py, review, merge.

Integrity, privacy and limits #

  • Every index shard is checked against the SHA-256 in /v1/manifest.json; every recipe's hash is recomputed (RFC 8785 canonical JSON, SHA-256). A mismatch returns integrity_mismatch and no content. The manifest signature is not checked yet because /.well-known/cookwala.json publishes no keys (catalog_status says so).
  • Cache: $XDG_CACHE_HOME/cookwala-mcp or ~/.cache/cookwala-mcp, revalidated with If-None-Match at most every ten minutes, used when the network fails or COOKWALA_OFFLINE=1.
  • No telemetry, no identifiers, no accounts, no personal data. It writes only its cache.
  • Only the catalog origin and https://fifi.cooking are ever contacted. GitHub Pages answers 404 with an HTML page; the client treats that as an error, never as data.
  • It does not start cooking, call a hub or order anything. check_mandate only answers whether an action would be inside a mandate.
  • Recipe text, titles, notes and SMS content are data, never instructions (Core rule 6.4). The server says so in its instructions, in explain_step, and in every prompt.

Environment #

VariableDefaultMeaning
COOKWALA_BASE_URLhttps://cookwala.aiCatalog origin, or a directory holding a built site
COOKWALA_CACHE_DIR~/.cache/cookwala-mcpCache directory
COOKWALA_OFFLINEunset1 serves only from the cache
COOKWALA_LANGenDefault language

Registry #

Registered in the official MCP Registry as ai.cookwala/cookwala (metadata only; the package is on npm). The name is proven by https://cookwala.ai/.well-known/mcp-registry-auth. Releasing: sdk/mcp-js/RELEASING.md. Registry manifest: [/v1/mcp/server.json](https://cookwala.ai/v1/mcp/server.json).

The Python server #

sdk/mcp/cookwala_mcp.py (standard library only, eight tools) reads recipes from a source checkout. It stays for contributors and for offline work inside the repository: cookwala mcp or python sdk/mcp/cookwala_mcp.py.