mcpField
M
MCP Write Gate

MCP Write Gate

本地服务
github.com/goran-revops安全05 周前更新

关于 MCP Write Gate

MCP Write Gate 是位于 AI Agent 与真实 MCP 服务之间的本地写入控制层,面向连接 CRM、邮件和协作系统的 GTM 与运营团队。它让读取请求通过,并按列表、只读模式和审批规则拦截写入,同时保管密钥并记录调用。

主要功能

  1. 01按目标列表检查写入
  2. 02支持强制只读模式
  3. 03未命中名单时可要求审批
  4. 04配置联系频率上限
  5. 05保护 API 密钥并记录调用

适用场景

  1. 01限制 Agent 修改 CRM 客户记录
  2. 02阻止向客户或未联系对象发送邮件
  3. 03测试规则而不实际发送请求

MCP 相关

MCP 客户端连接此服务而非后端 MCP 服务;它转发获准的读取和写入工具调用,并拒绝不符合规则的请求。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"goran-revops-mcp-write-gate": {
"command": "uvx",
"args": [
"mcp-write-gate"
]
}
}
}
启动命令uvx mcp-write-gate

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

安装包
pypimcp-write-gate0.2.0

工具

还没有获取到工具列表

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

详细介绍

mcp-write-gate

mcp-write-gate 位于 AI Agent 与其通过 MCP 使用的工具之间,例如电子邮件、CRM、Smartlead 或 Slack。Agent 可以自由读取,但每次写入都会在发送前经过检查;任何面向客户、正在进行的交易或你列表中其他对象的操作,都会在到达工具之前被拒绝。

我为 GTM 和运营团队构建了它:这些团队会将 Claude Code 之类的 Agent 连接到真实系统,并希望制定一条 Agent 无法辩驳绕过的规则。最常见的设置是只读模式:你使用完整权限范围的 API 密钥连接 Smartlead、HubSpot 或 Salesforce,Agent 可以查看所有内容,但不能更改任何内容。

+---------------+               +------------------+                  +-------------------+
|   AI agent    |   tool call   |  mcp-write-gate  |  allowed calls   |  Real MCP server  |
| (Claude Code, | ------------> |                  | ---------------> | (HubSpot, Gmail,  |
|  Cursor, ...) | <------------ |                  | <--------------- |  Smartlead, ...)  |
+---------------+  the result,  +--------+---------+     results      +-------------------+
                   or why it             |
                   was refused           v
                          +-----------------------------+
                          |  read          ->  forward  |
                          |  write, safe   ->  forward  |
                          |  write, listed ->  refuse   |
                          |  write, unsure ->  hold     |
                          |  read-only     ->  refuse   |
                          |  every call    ->  log      |
                          +-----------------------------+

工作原理

Agent 连接到 mcp-write-gate,而不是实际服务,并看到相同的工具、相同的名称和输入。调用工具时,由网关决定如何处理。读取操作会直接通过。写入操作会根据你的列表进行检查;如果涉及客户、正在进行的交易或任何标记为“禁止联系”的对象,就会被拒绝,并告知 Agent 原因。任何内容都不会到达工具。默认情况下,写入不在任何列表中的对象会通过;你也可以选择让它等待人工批准。你还可以限制联系同一个人的频率,例如每周最多发送一封电子邮件;在只读服务上,无论密钥允许什么,所有写入都会被拒绝。

Agent 始终不会持有真实 API 密钥。密钥保存在网关自己的文件夹中,网关也会从服务返回的任何内容中移除密钥。每次调用,无论通过还是被拒绝,都会记录在日志中;如果有人之后编辑日志,你也能看出来。

快速开始

你需要 Python 3.10 或更高版本。

pip install mcp-write-gate
mcp-write-gate init
mcp-write-gate add mail -- npx -y your-mail-mcp-server

init 会在你的用户文件夹中创建网关文件夹,与项目隔开。文件夹中包含存放规则和服务的 gate.json、起始列表 lists/off-limits.csv、用于存放真实服务 API 密钥的 keys.env,以及日志。

add 会启动一次真实服务,读取其工具,并判断哪些工具用于读取、哪些用于写入。它会打印每项判断,以及供 Agent 使用的 MCP 配置块。检查这些判断,然后将该配置块粘贴到原来真实服务配置所在的位置。在 Claude Code 中只需运行一条命令:

claude mcp add mail -- mcp-write-gate serve mail --config "<gate folder>/gate.json"

远程服务通过 URL 添加,其密钥保存在 keys.env 中,并以 ${NAME} 的形式引用。使用 OAuth 的服务需要由人工登录一次,之后网关会自行刷新令牌:

mcp-write-gate add crm --url https://mcp.example.com/mcp --header 'Authorization: Bearer ${CRM_TOKEN}'
mcp-write-gate add crm --url https://mcp.example.com/mcp --oauth
mcp-write-gate login crm

在依赖某条规则之前,你可以先测试,而不会发送任何内容:

mcp-write-gate check mail send_email --args '{"to": ["[email protected]"]}'

只读模式

mcp-write-gate add smartlead --preset read-only --url 'https://mcp.smartlead.ai/sse?user_api_key=${SMARTLEAD_KEY}'
mcp-write-gate reads smartlead
mcp-write-gate confirm smartlead get_campaigns get_campaign_stats

在只读模式下,所有写入都会被拒绝,任何列表、模式或审批都无法改变这一点。只有在以下情况下,读取操作才会通过:服务将工具标记为只读,且工具名称看起来像读取操作;或者人工使用 mcp-write-gate confirm 确认了该工具。mcp-write-gate reads 会列出每项读取操作以及确认者。

网关不会对服务提供的信息照单全收。名为 delete_campaign、但被服务标记为只读的工具仍会被视为写入操作。如果服务在你确认后更改了某个工具,该工具会被拒绝,直到你再次确认。试图通过参数更改内容的读取操作也会被拒绝,例如 HTTP DELETE、执行写入的 SQL 语句或 GraphQL mutation。

因此,只要满足以下四项条件,将完整权限范围的密钥放在网关后面就是安全的:

  1. 网关是 Agent 访问该工具的唯一途径。
  2. Agent 无法读取网关文件夹,也无法以网关用户的身份运行代码,否则它可能找到密钥并直接调用 API。docs/security.md 介绍了三种防范方法,其中最强的是使用独立容器。
  3. 确认每项读取操作前都已检查。对于 call_api 或 run_query 这类通用工具,需要格外谨慎,因为供应商 API 可能会在 GET 请求中执行删除操作,看起来却像读取操作。
  4. 密钥仍应采用供应商提供的最小权限范围。网关是第二道锁,所以第一道锁也要保留。

列表

列表是 lists/ 文件夹中的纯 CSV、TXT 或 JSON 文件,因此你可以从 CRM 导出,也可以手动维护。每个文件都会被读取,文件更改会在下一次调用时生效。

target,status,note
example.com,customer,paying account
[email protected],open_deal,in a live deal
[email protected],allow,partner contact inside a customer
#sales-internal,blocked,chat channel the agent must not post in
*/contracts/*,blocked,signed contracts stay untouched

域名规则涵盖其所有子域名;对于邮箱地址,使用 +标签 或 Gmail 点号写法的同一邮箱也适用。当两行都匹配时,更具体的一行优先,因此 [email protected],allow 可以位于某个客户的域名规则之下。门禁无法识别的状态会被视为拒绝,因此即使写错也不会放行。如果真实数据在 CRM 而非文件中,门禁可以针对未列入任何列表的对象运行查询命令,详见 docs/configuration.md。

使用真实服务测试

服务测试内容
Smartlead将全部 170 个工具分类为读取和写入。回复潜在客户、启动营销活动和转发电子邮件的操作均遭拒绝,且未发送;已确认读取操作可以通过,API 密钥也从未传到 Agent。
HubSpot读取操作通过并到达 HubSpot。创建记录和记录互动的操作均遭拒绝,且未发送。
Gmail将全部 23 个工具分类。草稿、标签、垃圾邮件和废纸篓操作均视为写入。
Salesforce将全部 74 个工具分类。部署、权限更改和 Apex 测试均属于写入,查询属于读取。
Notion将全部 24 个工具分类。创建、编辑、移动和删除页面均属于写入,获取页面属于读取。
MCP filesystem 和 everything servers将文件路径作为目标、资源、提示词、补全内容和长时间运行的调用进行测试。

我还使用 Claude Code 作为 Agent 进行了测试。不启用门禁时,Claude 会发送被要求发送的电子邮件。启用只读模式的门禁后,电子邮件未被发送,日志中也显示了拒绝记录。

它无法防护的情况

门禁会检查调用涉及的对象和目标,但不会检查消息内容,因此不会拦截邮件正文中提到某个客户的名字、却发给其他人的情况。它无法查看加密载荷、自定义二进制格式或类似 contact 123 这样的裸记录 ID 中隐藏的目标。对于 ID,你可以添加查询命令;对于其他情况,可以将相应工具设置为拒绝任何不在列表中的对象。它无法阻止以与门禁相同的 OS 用户身份运行代码的 Agent,因此 Dockerfile 会在独立容器中运行门禁。此外,它只能控制 Agent 向服务发送的内容,因此只应将你信任的服务置于其后。

了解更多

docs/configuration.md 介绍了 gate.json 中的所有设置:目标、预设、速率限制、查询命令、暂存调用和审批页面、通过 HTTP 提供服务,以及完整的命令列表。docs/security.md 说明了如何防止 Agent 接触门禁、机密信息的存放位置、日志如何显示篡改记录,以及攻击测试覆盖的内容。

运行测试

pip install -e ".[dev]"
pytest

测试会在门禁后启动一个真实的 MCP 服务,并通过官方 MCP 客户端与其通信,支持 stdio 和 HTTP。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

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

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