What inspired me. Cooking apps are single-player: they talk at you with recipes you'll never use. Chat agents fixed the conversation but not the problem — an agent that only answers can't do anything. The WebMCP moment is that the page itself becomes the tool surface, so I built the app I wanted: a teammate that cooks with you on one live board. You type what's in your fridge — "tomatoes, soy sauce, basil" — and the agent doesn't reply in a bubble, it acts: recomposes the board, drops in a card it invented, re-sorts, re-themes. Every action mutates the real DOM in front of both of you. That shared, visible state is the whole idea — visible execution is what keeps trust and control with the human.
How I built it. One zero-dependency index.html + a node serve.mjs dev server, deployed on GitHub Pages. On load the page registers 7 tools through the native WebMCP API (document.modelContext.registerTool) with JSON-schema inputSchema, readOnlyHint annotations and async execute callbacks that return clean JSON. Ingredient input normalises through an alias map and Unicode NFD stripping, so "poivron", "œufs", "sauce soja" and "baguette" all land on canonical ids. A stdio MCP server (mcp-server.mjs) re-exposes the same 7-tool surface, so any MCP host can drive the live UI too. I verified with a headless visual check and a full MCP JSON-RPC end-to-end test before pushing.
The card's match score is just coverage of what a recipe needs:
s c o r e ( 𝑟
)
∣ { 𝑖 ∈ n e e d s ( 𝑟 ) : 𝑖 ∈ 𝑃 ∪ 𝑆 } ∣ ∣ n e e d s ( 𝑟 ) ∣ score(r)= ∣needs(r)∣ ∣{i∈needs(r):i∈P∪S}∣
where 𝑃 P is your canonical pantry and 𝑆 S the staples (oil, salt, sugar, water, butter, vinegar) assumed always on hand — they never block a match.
Challenges I faced. The first version faked WebMCP: it overwrote document.modelContext with a plain-object shim — in a WebMCP-capable browser that destroys the native API. I rewrote it to feature-detect, register natively, and degrade honestly into a labelled demo mode. Matching messy human input took real engineering: quantifiers ("2 eggs", "half an onion") get stripped, plurals folded, and the match never depends on typos I could normalise away. And agents break things: add_recipe crashed on partial args (needs.map of undefined), so every tool now validates its inputs and returns {ok:false, error} instead of throwing, while get_board/get_pantry give the agent truthful grounding before it acts.
What I learned. WebMCP flips tool design into UI design: the page is the API, so good agent UX means building a surface that is honest to read, safe to mutate, and legible when it changes. And the best pattern for human-AI trust isn't explaining what you did — it's letting the human watch you do it.
Log in or sign up for Devpost to join the conversation.