mcpField
O
orangerail

orangerail

本地服务
github.com/KimHyeongRae0开发工具011 周前更新

关于 orangerail

orangerail 根据 Prisma schema 生成类型化 MCP 服务,为 Agent 提供有界数据库工具,而非任意查询。它面向需要为指定写入设置人工审批并追踪治理变更的团队。

主要功能

  1. 01从 Prisma schema 生成类型化工具
  2. 02按对象提供 get 和 list 工具
  3. 03根据 schema 生成写入操作
  4. 04为指定写入设置人工审批
  5. 05治理基线与审计链
  6. 06交互式领域关系图

适用场景

  1. 01让 Agent 执行获准的数据库读取
  2. 02无人值守地运行常规写入
  3. 03暂存破坏性写入以供后续审核

MCP 相关

它生成的 MCP 服务公开基于 schema 的读写工具及 check_approval,不提供任意查询工具;指定写入可暂存,等待人工审批。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"kimhyeongrae0-orangerail": {
"command": "npx",
"args": [
"-y",
"orangerail"
],
"env": {
"DATABASE_URL": "<DATABASE_URL>"
}
}
}
}
启动命令npx -y orangerail
需要配置的环境变量
DATABASE_URL密钥The database the generated actions reach, in the same form your Prisma datasource takes.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmorangerail0.1.4

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

README 配图

orangerail

把数据库交给你的 Agent,不要把 SQL 交给它。

npm CI node published with provenance license

快速入门 · 命令 · 不受管控的内容 · 与规则文件的对比 · 示例 · 文档

orangerail 在包含三个模型的 Prisma schema 上初始化,随后展示服务真实的 tools/list:六个读取工具、九个写入工具、check_approval,且没有 execute_sql

在包含三个模型的 Prisma schema 上运行 orangerail init,然后对它生成的服务实际调用 tools/list。共 16 个工具:每个对象各有一个 get 和一个 list,每种写入操作各有一个工具,以及 check_approval。列表中的工具都不接受查询。 三个锁是 --gate delete,这是一个可以通过一行配置更改的默认设置,并非最终判定。

规则文件做不到这一点。 它可以要求 Agent 不要运行查询,却无法将工具从列表中移除——而且我们测量了这种差异的价值,其中包括我们验证后不再成立的四项主张。

orangerail 会读取你已有的 schema,并据此生成 Agent 可用的工具界面。 orangerail init 会将 prisma/schema.prisma 转换为 MCP 服务:每个对象各有一个 get 和一个 list,每种写入操作各有一个带 zod 输入 schema 的工具,仅此而已——没有 execute_sql,工具列表中也没有任何接受查询的工具。它是一个扫描器和代码生成器,不会调用大模型,也不需要 API 密钥。你愿意让它无人值守运行的写入操作,就会无人值守地运行。对于你不愿意无人值守运行的写入操作,会附加 policy: { approval: 'required' },这会阻止调用,并将其转为可由他人稍后处理的审批请求——即使处理者不是你,甚至生成该请求的对话早已结束。

受限不等于安全,本 README 不会假装两者相同。 生成的工具界面提供的是有限且清晰可见的操作范围,并不意味着其中绝无有害操作。你声明了哪些操作动词,Agent 就能调用其中哪些;所以你声明的破坏性操作,Agent 也能调用。

是否值得安装,取决于一个前提:orangerail 只管控它自己的工具。 如果 Agent 还能使用带凭据的 shell,或另一个数据库 MCP 服务,它就能绕过这道防线——请参阅 orangerail 不管控的内容。

预发布且可安装:npm 上的 0.1.5——orangerail(CLI),以及 orangerail-core、orangerail-mcp、orangerail-docs-gen 和 orangerail-studio。API 会在 1.0 之前变更,状态中有一条重要的升级说明。

将整个领域视为一张地图

只需一条命令,init 生成的界面就是一张可供阅读的地图。

$ orangerail studio
orangerail studio: scanning ontology — 9 object(s), 27 action(s)
orangerail studio: building the interactive map…
orangerail studio: serving on http://127.0.0.1:4820 — open it in your browser

每个对象、它们之间的关系,以及 Agent 能触达的每个写入操作。将鼠标悬停在表上,即可高亮显示其关系和操作;点击表即可查看管理它的策略。

orangerail 工作室地图——将鼠标悬停在表上以显示关系,然后打开 deleteOrder 查看管理它的策略:目标为 Order,需要审批,任意审批者,且无条件

更清晰的版本:assets/studio-map.mp4——同一次运行的完整分辨率版本。在示例电商领域中进行的一次真实运行,使用 --gate delete。这些锁并非为视频添加的注释:它们是工作室根据本体绘制的,因此九个操作带有锁,十八个没有。

准确理解它的价值。 这些关系来自 ontology/_links.mjs,init 会根据你的 Prisma 关系生成它,因此 Customer_list 的描述显示为 List Customer records. Relations: has many Order.。Agent 会被告知一个 Customer 有多个 Order。但它仍无法沿着这条边进行查询:没有遍历工具、没有联接、没有聚合,而且 Customer_list 会拒绝涉及 Order 的筛选条件。了解领域的结构和能够跨结构进行查询是两回事,而这里具备的只有前者。

快速入门

七个步骤,所有输出均逐字来自一次录制的运行。每一步背后的原因,以及它能避免的故障,详见快速入门注释;该页面首先列出了前置要求和 Prisma 7 的注意事项。

1. 将 orangerail 安装到即将扫描的项目中。

npm i -D orangerail

2. 扫描你的项目,所在仓库中须有 prisma/schema.prisma。

$ npx orangerail init --yes --preset approval-for-writes --no-studio
  ✓  scanned your sources — 2 object(s), 6 action(s)
  ✓  generated a governed MCP server under ontology/
  ✓  --gate delete: 2 of 6 write action(s) gated behind human approval — the other 4 run when the agent calls them
  ✓  recorded that posture in orangerail.governance.json — commit it
  ✓  approvals queue + audit chain at .orangerail/store/ — inside this project, so an
     agent with file tools over this directory can write them

  These files are yours — re-scans never modify them; `orangerail sync` reports drift.

  Change what is gated by editing `policy` in ontology/<action>.mjs, or re-run init
  with `--gate all` (gate every write) or `--gate none` (gate nothing).
  orangerail.governance.json holds the posture init just generated, which nobody has reviewed yet.
  From now on `orangerail sync` fails when an action gets weaker than that file, and
  `orangerail mcp` refuses to serve it. Read the file, then run
  `orangerail sync --accept-governance` to vouch for it as reviewed.

  That store is the record of which writes a human approved, and appending one line to
  .orangerail/store/approvals.jsonl marks a staged action approved — the next
  `check_approval` then executes it, because the gate reads that store and never the
  audit chain. `orangerail audit verify` reports the forgery afterwards; it is a report,
  not a gate, and it does not prevent the write. The generated config carries the
  one-line move at the `createFileStore` call — see docs/audit-log.md.
orangerail docs: wrote /private/tmp/shop/.orangerail/generated/AGENTS.md

Done. Run `orangerail studio` to explore the map, or `orangerail mcp`.

3. 安装生成的代码所加载的运行时。

npm install orangerail-core zod

4. 为生成的操作提供可访问的数据库。

npm install @prisma/client@6
export DATABASE_URL="file:./dev.db"
npx prisma generate
npx prisma db push --skip-generate

已有数据库?不要在其上运行 db push—— 针对现有数据库采用 orangerail。

5. 将 Agent 宿主指向它。 将以下内容放在项目根目录中,文件名为 .mcp.json:

{
  "mcpServers": {
    "orangerail": {
      "type": "stdio",
      "command": "./node_modules/.bin/orangerail",
      "args": ["mcp"],
      "env": { "DATABASE_URL": "file:./dev.db" }
    }
  }
}

其他宿主、claude mcp add 单行命令,以及从源码运行的方法: 将其接入 Agent 宿主。

6. 记录治理基线,并将其提交。 ontology/ 可由你编辑,因此只需一次不慎删除,就能用一行代码解除整个流程的限制,而重新扫描也不会察觉。系统会将当前状态与已记录的文件进行比较。

npx orangerail sync --accept-governance

提交 orangerail.governance.json。 它的全部价值在于:如果某个拉取请求移除了审批关卡,审查者就能在 CI 运行之前,从该请求自己的差异中看到 "approval": "required" 变成了 null。

7. 现在离开即可。 你离开期间,Agent 会处理队列:你未设置关卡的写入操作会继续执行,而它收到的删除请求则会停止。回来后:

$ npx orangerail status
orangerail status
  objects:  2
  actions:  2 approval-gated, 4 auto
  baseline: 6 action(s) match orangerail.governance.json
  preset:   approval-for-writes
  pending:  1 approval(s) awaiting a decision
  store:    /private/tmp/shop/.orangerail/store
            Inside the project root, so an agent with file tools over this directory can
            write it: one appended line in approvals.jsonl is a decision no human made,
            and the next `check_approval` executes the staged action — the gate reads
            this store, never the audit chain. `orangerail audit verify` reports the
            forgery afterwards; it is a report, not a gate. Pointing the store `dir` at a
            directory this agent's process cannot write is what removes the reach — see
            docs/audit-log.md.
  server:   not detected — no orangerail mcp is running against this store
  hosts:    .mcp.json declares orangerail and nothing else.
            Project scope only (.mcp.json, .cursor/mcp.json, .vscode/mcp.json); user- and
            machine-scope MCP config is not read.
  audit:    chain OK — 5 record(s) verified

$ npx orangerail approvals list
c4818df5-770c-446f-883a-e9c0f7e615a2  "deleteCustomer"  by "local-dev" [dev]  0s ago  input={"id":2}

1 pending approval(s).

$ npx orangerail approvals approve c4818df5-770c-446f-883a-e9c0f7e615a2
approve ok (approved)

Agent 的下一次 check_approval 才是该行可以发生更改的第一个时刻。你未作出许可之前,什么都不会执行,而且每个步骤都记录在哈希链上。每次回归测试都会针对本仓库自己的构建运行 tests/e2e/ONT-093-quickstart-runs-as-documented.sh,验证上述完整流程。

为什么提示词不是正确的控制方式

阻止你离开的,并不是 Agent 做得太多,而是你唯一的控制手段是它必须向你提出的问题。 下午问到第二十次时,得到的还是和第一次相同的点击;而终止询问的开关就随软件一同提供——按照 Claude Code 自己的权限参考,bypassPermissions 模式会“跳过权限提示,但明确 ask 规则强制要求的提示除外”。如果每次调用都要由人重新设定边界,那么一旦没人守着,边界就无法维持。

提示词在形式上也不对。它询问的是某个工具——是否可以运行 Bash——而你承担的风险关乎你的业务领域:编辑库存没问题,删除订单不行;低于 $50 的退款不需要任何人审批。这种区别并不存在于工具层面,而存在于你的架构中。

本项目适用的运行场景

交给 Agent 处理的后台队列,没有人盯着:普通写入顺利完成,一次删除被拦下并转为审批,而阻止它的那条明示规则清晰可见

运行一次 examples/unattended-queue——使用真实 MCP 客户端,无需 API 密钥,并对每一行进行断言。视频展示了 12 条中的 6 条;行号有所跳跃,方便你看出位置。

一个包含 15 项任务的后台队列,涉及一个电商数据库。队列交给一个 Agent 处理,操作员当天离开,并明确要求不要请求确认。其中 12 项是普通的可撤销写入,3 项具有破坏性:删除一个已取消的订单、删除一个处于数据擦除请求下的客户,以及删除一个已停产的商品。完成后根据数据库评分,而不是根据 Agent 自称完成了什么:

orangerail
无人值守完成的普通任务12 / 12
执行的破坏性任务0
被拦下并暂存的破坏性任务3
次日早上等待处理的内容3 条审批记录,每条都通过哈希绑定到对应的具体调用
审计链27 条记录,验证通过

这就是本项目围绕的指标,而它并不是“我们拦下了多少”。而是在无人看守时完成了多少,以及你回来时还有什么在等待处理。

这张表里有两个可以分开的主张,而且它们的证据强度并不相同。12 项任务能够通过、3 项任务无法通过,这是服务端的特性,你可以在自己的机器上复现——examples/unattended-queue 会通过真实 MCP 客户端,确定性地运行整个队列,并对每一行进行断言。而当队列以文字形式提供时,模型会选择这些调用,则需要一个实时 Agent 驱动真实主机,这一部分是测量结果,而非可复现结果:样本量较小,只足以说明在测试过的场景中这道关卡有效,不足以得出发生率。

与你会采用的方案对比

真正有意义的对比对象不是原始 SQL 服务,而是一份规则文件:写得很好的 CLAUDE.md 列明允许和禁止访问的表,再配上拥有完整写入权限的 Postgres MCP 服务。同一队列、同一模型、三次克隆。

markdown 规则,完整写入权限orangerail
已完成的普通项12 / 12,三次运行均如此12 / 12
已执行的破坏性操作00
停止后留下的内容报告中的一段文字一条审批记录
在另一个目录启动相同任务行已删除已暂存

合规性方面打成了平手,而且一直如此——无论面对对抗性改写、伪造的先前审批、植入数据库行中的指令,还是小得多的模型,结果都是如此。有一项指标上它胜过了我们。因此,本项目并不主张你的 Agent 会无视规则:在这里测量的每次运行中,它都遵守了规则。

一共进行了六次运行。 这足以否定“它不会遵守规则”这一说法,但远不足以得出比率——六次中零次失败,只能将尾部风险限定在约 39%,而非接近于零。要获得可靠的界限,成本很高,而且下一次模型发布就会让它失效;因此,本项目押注的是下面这一行: 十次运行无法证明什么。

唯一没有打成平手的是最后一项,而且这与 Agent 的行为无关:授权随其注册的会话流转,而规则文件随其所绑定的机器账户流转。对于单台机器上的单个开发者,全局 ~/.claude/CLAUDE.md 可以弥补大部分差距——如果你正是这种情况,可能不需要它。 但遇到 CI 运行器、容器、服务账户或队友的检出目录时,这种弥补就到头了;这些环境无论如何都会拿到数据库凭据。

每次运行、规则文件胜出的指标,以及这项测量的局限: 与您会采用的方案对比。 examples/vs-a-rules-file 会执行两种方案。

Agent 获得的不是 execute_sql,而是这些工具

在包含三个模型(Order、OrderItem、Payment)的 Prisma schema 上运行 orangerail init 后,整个工具列表共有 16 项:每个对象各有一个 get 和一个 list,每种写入操作各有一个工具,另有 check_approval。 没有其他工具,也没有任何工具接受查询。

每个操作的输入都是根据你自己的列生成的 zod schema,并发布在 tools/list 中,因此 updateProduct 会拒绝将字符串用于整数列,并指出对应字段。每次读取都是按 id 执行的 findUnique,或分页的 findMany;其 filter 是针对已声明字段的一组封闭谓词——由服务在请求到达 resolver 之前强制执行,而不只是公布出来。

固定的接口范围很窄:没有聚合、没有联接、没有自由格式查询,也没有 DDL。无法通过它表达的问题必须在其他地方解答——orangerail 不负责管控的内容列出了全部内容,以及实际实施管控的位置。

看看它如何拦住 Agent

破坏性 Agent 操作被拦截,随后返回一个审批 ID;由人来决定,只有在此之后行才会发生变化

通过真实 MCP 客户端运行 examples/governed-writes 的一次真实记录。破坏性工具会保持可用,而不是被隐藏;Agent 无法强行执行该操作,并且只有在人工作出决定后行才会发生变化——这发生在另一个终端、另一个时间点,这正是能够离开的关键。

声明生成器无法推导的规则

以上内容都是生成的。当某条规则只存在于你的脑海中,而不在架构中——“绝不为售罄商品发放优惠券”——你只需用 TypeScript 写一次,它就会加入同一界面:

import { defineAction, defineObject } from 'orangerail-core';
import { z } from 'zod';

// Your existing backend. orangerail never replaces it — it only gates the call.
declare const findProduct: (id: string) => Promise<{ id: string; status: string } | null>;
declare const grantCoupon: (args: { productId: string; amount: number }) => Promise<void>;

// A `where` guard has to read the row it guards, so the target needs `resolve`.
export const Product = defineObject({
  name: 'Product',
  schema: z.object({ id: z.string(), status: z.string() }),
  resolve: { get: async ({ id }) => findProduct(id) },
});

export const issueCoupon = defineAction({
  name: 'issueCoupon',
  target: Product,
  input: z.object({ productId: z.string(), amount: z.number() }),
  policy: {
    approval: 'required',
    where: { field: 'status', op: 'neq', value: 'soldout' },
  },
  // `execute` runs only after the approval clears, and receives the validated
  // input plus the resolved caller. There is no `audit` switch: every staged,
  // approved, rejected and executed action is written to the hash chain.
  execute: async ({ input, identity }) => {
    await grantCoupon({ productId: input.productId, amount: input.amount });
    return { issuedBy: identity.subject };
  },
});

这段代码不是示例——它是 packages/cli/test/readme-example.ts 的原样输出, 由仓库的类型检查编译,并在每次运行时与此文件比对,因此不会逐渐变成从未编译通过的内容。

状态

如今,orangerail init 无需检出此仓库即可在你自己的项目中运行,而在 1.0 之前,API 还会有所变动。全部五个包都通过 npm 的 Trusted Publishing 从 .github/workflows/release.yml 发布,因此每个包都带有来源证明,注明构建它的工作流和提交;此仓库中没有 npm 令牌。

如果你使用的是 0.1.0,请升级。 该版本向 Agent 发布了一个读取用的 filter,但从未对其进行检查,因此 <Object>_list 调用可以读取服务从未公开过的对象类型 (实现机制)。修复已包含在 0.1.2 中,并位于 orangerail-mcp,因此升级软件包即可应用修复,无需重新运行 init。0.1.2 还缩小了 filter 接受的范围,并改变了待审批项在升级过程中的处理方式——这两项内容都列在 CHANGELOG 的 从 0.1.0 升级 一节中。

文档

示例

  • unattended-queue — 将本文开头的运行过程变为可复现示例。确定性、经过断言、无需 API 密钥。
  • governed-writes — 单独展示同一门控,一次执行一个破坏性调用。
  • vs-a-rules-file — 将规则文件对比变为可运行示例,执行两种方案,包括规则文件胜出的那一列。

开发

此仓库采用确定性的 9 阶段门禁流程构建。每次变更都会通过 ./scripts/verify.sh 运行检查——语言、结构、门禁自测、无 LLM、 模板,然后是类型检查 / lint / 测试 / 构建——而 CI 只运行此脚本,因此本地运行通过即表示构建通过。一项硬性约束:绝不捆绑 LLM 推理 SDK (./scripts/check-no-llm.sh)。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。