Skip to main content
Glama

MacroMCP

一个 MCP 服务器,将 LLM 变成一位拥有真实记忆的营养助手。

你像跟人说话一样跟它交流:"7 盎司鸡肉和一杯米饭。" 它会问它需要问的问题,确认,提交,然后把数字读回来。之后 你问 "我这周蛋白质摄入怎么样",它从数据库回答,而不是靠猜。


问题所在

营养追踪应用通常以两种方式之一失败。

手动记录类(MyFitnessPal 之流)准确但令人疲惫。搜索 数据库,从六个几乎相同的条目中挑选,设置份量,每个 食材都要重复一遍。这种摩擦既是产品的主要特色,也是用户放弃的主要原因。

LLM 聊天包装类毫无摩擦,但悄悄出错。你说"鸡肉和 米饭",模型编造出看似合理的数字,没有持久化,没有 来源追溯,也没有任何可核查的东西。一周后问它你吃了什么,它毫无头绪。

MacroMCP 是中间路线:对话式录入,由模型负责理解, 数据库负责强制约束和算术运算,中间还有一步结构化的确认环节。


核心张力

严谨性与摩擦直接对立。 每一个澄清问题都提高了数据质量, 同时让你明天记录的可能性略微降低。大部分设计工作 是在不付出对话轮次代价的情况下买到准确性。

第二个组织原则:

强制约束属于服务器,而不是系统提示词。 一条说"绝不猜测 数量"的提示词能坚持一阵子,然后在长对话的第 40 轮悄悄失效。 而一个返回拒绝结果并附上具体问题列表的提交函数不可能失效。 提示词负责语气和提问措辞;数据库负责什么可以被表示。


工作原理

录入:解析 → 分类 → 解析 → 确认 → 提交 → 读回

解析 将一段话语转化为结构化的草稿。它的工作是转写 和分段,而不是推断。"鸡肉和米饭"产生两个条目,大多数字段 为空,而这正是正确的输出。

两个不变量,都在提交时强制执行:

  • 跨度覆盖。 每个条目都指向你所说内容的一个字符范围。 包含食物但未产生条目的文本会被报告,因此遗漏的条目 会被机械地捕获,而不是三个月后在每周汇总中才被注意到。

  • 无无锚条目。 没有跨度的条目就是幻觉,会被 拒绝。这正是阻止模型"好心"添加你从未提过的食用油的方式。

分类种类标记每个缺口,这样助手就能提出有针对性的 问题,而不是泛泛地问"多少?"。这个分类体系是 最有趣的部分:

缺口

示例

为什么重要

模糊容器

"一碗"、 "一杯"

那是量杯还是你橱柜里的杯子?

歧义维度

"8 盎司"

牛奶用液量,鸡肉用重量。由食物决定。

烹饪状态

"米饭"

干米 vs 熟米相差约 3 倍。最大的单一错误来源。

烹饪用油

"煎的"

经常被遗漏,经常是 100–200 千卡

变体

"鸡肉"、 "牛奶"

鸡胸肉 vs 鸡腿肉是 2 倍的脂肪差异

复合食物

"一个三明治"

分解它,否则就是猜测

数量范围

"两个鸡蛋和香肠"

"2" 是否适用于两者?

重要性门槛 是防止这变成一场盘问的关键。每个 缺口都携带其最可能解释之间的热量差异。低于阈值, 就取最佳解读,标记为估算值,不花费对话轮次。黑咖啡的 容器 vs 量杯差异是噪音;对米饭来说那是 200 千卡。

解析 产生克数和宏量营养素密度。确认 在一个块中显示 整个计划,并在一个对话轮次中提出所有未解决的问题——串行提问 正是导致追踪应用被弃用的原因。

提交 是闸门。它拒绝未解析的条目、无锚条目、遗漏的 跨度、未解决的重要缺口,以及未通过一致性检查的宏量营养素。

读回 返回已提交的条目,包含克数、逐条目宏量营养素、 餐次总计和当日总计。助手报告的是服务器计算的数字,所以 如果草稿在长对话中发生了偏移,这里就会显现出来。

存储:四个层级

meals               the eating event.  "chicken and rice", dinner, Aug 19
  meal_logs         one submission.    eaten_at + logged_at
    log_items       one named thing.   "cheeseburger", fraction 1/2
      item_ingredients                 bun 60g, patty 113g, cheese 19g

每个层级存在的原因:

  • meals 因为一次进食事件有名称,并且可以被多次记录。 "我忘了酱料"附加到该餐次上,而不是创建第二顿晚餐。 这也是餐次被拥有的层级——见下文"多用户"。

  • meal_logs 因为忘记某件事是正常的,也因为你进食的时间你告诉系统的时间是值得分开保存的不同事实。

  • log_items 因为份量比例就在这里。 "半个汉堡和 所有薯条"如果比例放在 log 上就无法表示。复合食物 也有名称,所以读回时显示"芝士汉堡,263 千卡",而不是 三行需要你重新拼装的数据。

  • item_ingredients 因为芝士汉堡就是面包、肉饼和奶酪。每个 条目都有配料,包括简单的——"一杯米饭"是一个有一个配料的 条目——这花费一个包装行,但换来一条统一的汇总路径, 任何地方都不需要多态。

meals 以下的所有内容都是只追加的。更正就是 取代旧行的新行。meals.name 是整个日志中唯一可变的字段。

查询

模型从不做算术。 每个总计、平均值和趋势都在 SQL 中计算, 并以结构化 JSON 返回。LLM 对 40 个数字求和会偶尔出错,而且是 静默地出错,这完全违背了拥有数据库的意义。

汇总按 配料 → 条目 → 日志 → 餐次 → 日 的顺序进行,全程不舍入, 只在显示时舍入一次。组件明显无法加总到总数 比任何单个错误条目更快地摧毁信任。


多用户

MacroMCP 最初是单用户的,现在为小群体构建——一个 家庭或几个朋友共享一个自托管实例,而不是公开的 多租户产品。

每餐都由一个用户拥有。 meals.user_id 是事实来源; 其下的一切(meal_logslog_itemsitem_ingredients)通过 向上关联到它来限定范围,而不是携带自己的副本。每个提交路径 函数——commit_logrename_mealsupersede_logfind_attachable_meals——都将调用用户的 id 作为显式 参数,并在做任何事之前检查所有权,就像 staging_id 由服务器铸造而不是信任模型一样。

多用户带来的好处: 两个人可以共享一个实例,而不会让他们的 日志、重复检测或趋势相互冲突。Sam 记录的和 Luke 五分钟前 记录的相同的鸡肉和米饭不是重复。Luke 的周二总计 不会被悄悄合并到 Sam 的里面。

它刻意不包含的内容: 身份验证。这个 schema 中没有 密码或令牌——user_id 按给定的值被信任,而解析 实际调用者是谁(API 密钥、登录会话、每人一个 MCP 服务器) 是 API 层的决定,不是数据库的决定。也没有 共享模型:用户之间完全隔离,而不是可以互相查看 日志的家庭成员。如果共享可见性最终变得重要, 那是在此之上的增量功能,而不是对它的重做。

关于哪些地方加了跨用户防护以及为什么,以及暂时跳过 行级安全背后的权衡,请参阅 docs/design-notes.md


v0 的赌注

没有参考数据库。 没有 USDA 数据导入,没有 Open Food Facts,没有条形码 路径,没有份量表。宏量营养素密度来自模型自身的知识或 来自你,并存储在配料上。

这是一个真正的赌注,所以这里列出双方的理由。

支持方: 现代模型知道鸡胸肉大约是 165 千卡/100 克,一杯 熟米饭大约是 158 克。查证这些数据需要延迟,而录入慢就意味着 不录入。它移除了整个数据导入管道。而且历史记录在 记录时被冻结——没有任何上游数据源能悄悄改变你过去日志 的内容。

反对方: 没有外部事物交叉核对这些数字。剩下的唯一自动化 检查是 Atwater 恒等式——千卡应 ≈ 4·蛋白质 + 4·碳水化合物 + 9·脂肪—— 它能捕获数字错位和不连贯的猜测,但无法捕获 自洽的错误答案。一个以 100 千卡/100 克和看似合理的宏量营养素 输入的贝果会成功提交;真正的贝果大约是 270。确认步骤 才是捕获它的地方,这就是为什么确认块显示宏量营养素 而不仅仅是克数。

两件事让这个赌注可以承受:

宏量营养素按每 100 克发送,绝不发送绝对值。 "鸡肉是每 100 克 165 千卡"是 回忆;"213 克鸡肉是 351 千卡"是算术。模型在 前者上可靠,在后者上不可靠。每 100 克也意味着服务器仍然执行 每一次乘法,所以条目比例继续正常工作。

每个配料都记录来源llm_knowledgellm_estimate、 或 user_statedv_daily_data_quality 报告一天中多少比例的热量 来自每种来源。80% 由模型猜测的一天,与 80% 由标签读取的 一天,值得不同的信任,而这是唯一能告诉你 你拥有的是哪一种的东西。

注意:条形码查询在下面的延迟列表中,而且它位于 同一个赌注的下游,不是单独的一刀——没有 UPC→宏量营养素 查找表,因为根本没有参考数据库。构建一个 就能同时解除两者的延迟状态。


值得了解的设计决策

暂存状态存在于上下文窗口中。 没有草稿表,没有 Redis。 对话本身已经携带了进行中的状态。带写穿透的 Redis 是 计划中的下一步;提交闸门在它落地时不会改变,因为它已经 将负载作为参数接收,而不是读取表。

重复项按内容识别,而不是按时钟。 一个 (meal, timestamp) 键 会拒绝"哦,再加一根香蕉"——这是最常见的记录模式。 替代方案:对已解析的配料做哈希,在窗口内与 现有行的时间戳比较,限定在单个用户范围内。双重范围(同一餐 / 其他餐),都是软性的,因为一天内两杯相同的蛋白奶昔是真实存在的。

幂等性来自一个唯一列。 服务器铸造一个 staging_id;它在 所有用户之间是 UNIQUE 的。重试、代理循环的重复触发和并发调用 都会返回现有条目,而不是重复创建。

附加从不静默。 将"我忘了酱料"附加到错误的 餐次比创建一个多余的更糟糕,因为它破坏了一餐本来正确的 数据。服务器在调用者自己的餐次内提出候选; 即使只有一个匹配也需要确认。

名称从不重新生成。 添加你忘记的酱料后,"鸡肉和米饭"保持 "鸡肉和米饭",而不是变成"鸡肉、米饭和是拉差酱"。一个 在你脚下不断变化的名称,比一个略微不完整的更糟糕。

日期在凌晨 4 点而不是午夜翻转。 凌晨 1:30 的零食属于 你仍然醒着的那一天。log_date 在提交时物化,并从该餐的 第一条日志推导而来,所以一餐永远不会跨两天。

精确不是准确。 对目测份量做精确的有理数算术 仍然记录为 estimated。系统永远不会把一种洗成另一种。


v0 刻意不包含的内容

  • 条形码查找,以及它所依赖的参考食品数据库。不包含USDA/OFF数据导入,也没有UPC查找表——这与上述“无参考数据库”的削减相同,并非两个独立的遗漏。

  • 先前解析结果的复用(“和上次一样?”)——这是主要的摩擦点修复,缺少它意味着每次用餐都要支付完整的确认成本。

  • 批量跟踪(没有任何机制强制要求一个菜品的分数总和不超过1)。

  • 食谱模板

  • 微量营养素——当它们回归时,添加一个独立的、长格式的表格,而不是迁移回去,因为宏量营养素和微量营养素具有不同的形态和查询模式。

  • 身份验证和跨用户共享——参见上文“多用户”部分。user_id 作用域已存在;但验证 user_id 实际对应谁,以及用户之间共享查看彼此日志的任何概念,目前尚未实现。


技术栈

FastAPI + Postgres 16,小型多用户,自托管。通过MCP暴露,以便任何MCP客户端都能作为前端。

运行方式

MCP服务器(server/)是一个轻量适配器:它根据docs/intake-agent.md中的约定注册每个工具,在启动时解析此进程的user_id,并为每次调用调用匹配的SQL函数或视图。除此之外,它没有自己的逻辑——数据库仍然是所有不变量实际执行的地方。

一个服务器进程 = 一个用户(参见server/config.py)。这就是对docs/design-notes.md中“调用如何解析为user_id”问题的答案:对于MCP,每个人运行自己的服务器实例,就像Claude Desktop/Code为每个配置的工具启动一个子进程一样。

python3 -m venv .venv && source .venv/bin/activate
pip install -e .

createdb macromcp                       # first time only
psql -d macromcp -f db/schema.sql       # first time only
psql -d macromcp -c "INSERT INTO users (username, display_name) VALUES ('luke','Luke');"

cp .env.example .env   # edit MACROMCP_USERNAME to match the user you just created
export $(cat .env | xargs)
python -m server.server

将MCP客户端(Claude Desktop、Claude Code、OpenAI Realtime函数调用桥)指向python -m server.server,并设置该环境,docs/intake-agent.md中的每个工具都将生效。

docs/intake-agent.md中描述的GPT Realtime迷你语音前端尚未连接——此服务器只需要某个MCP或函数调用客户端作为前端,即可实现端到端的实用性。

文件

  • db/schema.sql — 完整的DDL,多用户提交门,汇总视图。在PG16上干净加载。

  • db/tests.sql — 18个不变量测试(13个核心,5个跨用户隔离检查),全部通过。

  • docs/design-notes.md — 完整的设计原理,多用户权衡,尖锐的边缘情况。

  • docs/intake-agent.md — 对话式前端(GPT Realtime迷你)的系统提示和工具/函数调用约定,与fn_commit_log的负载逐字段匹配。

  • docs/erd/ — 模式图(仍显示单用户形态;尚未为多用户重新生成)。

  • server/ — 实现工具约定的MCP服务器(db.py Postgres访问,models.py 负载验证,tools.py 业务逻辑,server.py 工具注册)。

  • 先前的单用户设计历史:git log db/schema.sql

-
license - not tested
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lukew0824/MacroMCPv2'

If you have feedback or need assistance with the MCP directory API, please join our Discord server