plate-cost
Enables interactive recipe costing and menu-item pricing with deterministic math, including waste and margin calculations, and distinguishes whether figures came from the calculator or the model.
README
plate-cost
An MCP App that costs recipes and prices menu items — an interactive calculator the model opens instead of doing the arithmetic itself.
Ask Claude "help me price my nasi goreng" and you get a working spreadsheet: ingredient rows, purchase prices, waste percentages, portion yield, a margin slider. Change a number, everything recalculates. Press Use these numbers and the model continues the conversation with figures you entered rather than figures it invented.
Built on MCP Apps (ext-apps).

Running in the basic-host reference host from ext-apps — not Claude. The model
proposed the recipe, the widget loaded it, and "Use these numbers" sent the corrected
figures back into the conversation.
Why this is an app and not a tool
Costing is exploration, not a question. You do not know the answer you want until you have moved the portion size and watched the margin move. Chat is a bad interface for that, and a model doing the arithmetic in its head is worse — LLMs are unreliable at multi-step numeric work and completely reliable at sounding certain about it.
So the split is: the widget captures inputs, the server does the maths, the model does the talking.
The interesting part: knowing where the numbers came from
MCP Apps has an open gap — ext-apps#746:
a tools/call from a widget and one the model decided to make are indistinguishable
at the server. For most tools that does not matter. For a costing tool it decides
whether you are doing arithmetic or laundering a guess.
mcp-app-attest closes it — extracted
from this repo, which is its first consumer. The server mints a short-lived token each time it
serves the app resource and substitutes it into the document; the widget echoes it
back in _meta on every call. The model never sees the resource body, so it cannot
produce the token. Calls are answered either way — the response says which it got:
{ "perPortion": 3300, "inputsFrom": "model" }
and when the numbers came from the model, the text reply says so:
Note: these figures came from the model, not from the calculator. Confirm the purchase prices with the user before relying on them.
Verified end to end against the reference host, not just in unit tests:
[provenance] inputsFrom=model reason=missing meta=null
[provenance] inputsFrom=app meta={..."io.platecost/app-attestation":"XfqGVAiP…"}
What this is not. Not authorisation, and not proof a human typed anything. It distinguishes code paths, not identities. If a host copies the resource text into model context, the model can read the token — nothing here prevents that, it is the host's contract to keep. A compromised widget can send whatever it likes. Treat it as the difference between "typed into my form" and "produced by a language model", which is exactly what #746 asks for.
It has since been extracted into mcp-app-attest,
which switched to signed tokens rather than stored ones — see the "what didn't work"
note below for why.
Two things the domain gets wrong
Both are in src/costing.ts, both have tests.
Waste means buying more, not using more. Cost is used / (1 - wastePct), not
used * (1 + wastePct). At 50% waste you buy double, not one and a half times. The
naive version understates every trimmed ingredient you own.
Margin and markup are different numbers. Margin is (price - cost) / price;
markup is (price - cost) / cost. A 60% markup is a 37.5% margin, and a 60% margin
needs a 150% markup. priceForMargin takes margin — that is what "we want 65%"
means in a kitchen — and returns both, so the gap is visible rather than assumed.
Also handled: unit conversion within mass and volume families, with a refusal across
them (kg → l needs a density you have not given), per-ingredient cost share, and
overhead applied per portion rather than per batch.
Try it
npm install
npm run build # bundles the widget to a single inlined HTML
npm test # 21 tests
npm run dev # widget standalone in a browser, no host
Point an MCP client at server.ts. Outside a host the attestation placeholder is
never substituted, so calls are labelled model — which is the honest answer.
What didn't work
- A stateless HTTP transport. The first version built a fresh server per request,
which is fine for stateless tools and silently breaks this one: the attestation was
minted by a server instance that no longer existed when the widget called back, so
every widget call was rejected as
unknown. The in-memory tests could not see it — they share one instance. Only running against a real host exposed it. - Blaming the SDK. Before finding the above, the obvious suspect was
_metabeing stripped in transit. It is not: the reference host forwards it intact through the sandbox proxy. Worth knowing, because the whole mechanism depends on hosts doing so and the spec does not require it.
Status
v0. Two tools (cost-recipe, price-portion), one widget, 21 tests.
Not built: persistence between conversations, multi-recipe comparison, and anything
touching the namespacing problem in
#753 /
#745 — callServerTool
uses bare tool names, so this will break behind an aggregator. That is the next thing
worth solving and it is not solved here.
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 模型以安全和受控的方式获取实时的网络信息。