mcpclerk
mcpclerk
一个用于 MCP 服务器的治理代理:它位于任何 MCP 服务器之前,强制执行按工具划分的允许列表,将写类工具挂起等待人工批准,应用按工具划分的配额,对看起来像秘密的参数进行脱敏,并记录每次调用的哈希链审计日志。
AI 代理在 MCP 服务器上可以调用它们暴露的任何工具,想调用多少次就调用多少次,使用任何参数,而且没有任何东西以任何人都能审计的形式记录它做了什么。在企业环境中,问题不是“代理能否完成工作”,而是它被允许做什么,谁批准了危险的部分,以及它实际做了什么?
mcpclerk 用代码回答这三个问题。它本身就是一个 MCP 服务器:代理连接到它,它连接到真实的服务器,并将它们的工具重新暴露为 upstream.tool。每次调用都经过一个管道:允许列表、配额、脱敏、批准、转发、记录。未列出的工具会被拒绝。写类工具会等待人类回答 y。拒绝以可读的错误形式返回。日志是仅追加的 JSON Lines,每个条目与前一个条目进行哈希链接,因此任何地方的编辑都会破坏链条。
演示包装了官方的文件系统服务器:读取通过,写入被挂起并批准,移动被拒绝,一分钟内的第四次搜索因配额被拒绝,日志验证通过。49 个测试针对假上游验证了每个控制,包括上游始终收到未脱敏的参数。

安装
pip install mcpclerk # Python 3.10+ (the MCP SDK requires it); pulls in mcp and pyyaml
mcpclerk --version从源码安装:git clone https://github.com/hishamalward/mcpclerk && cd mcpclerk && pip install -e ".[dev]" && pytest。
Related MCP server: mcp-policy-gateway
五分钟
编写一个策略。这是演示中的那个(
examples/policy.filesystem.yaml):version: 1 defaults: unlisted: deny # a tool not named here is an unreviewed tool approval_timeout_s: 120 # a call nobody answers in time is refused, and logged as such upstreams: fs: transport: stdio command: npx args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp/mcpclerk-demo-sandbox"] tools: "read_*": allow list_directory: allow search_files: { decision: allow, quota: { per_minute: 3 } } write_file: approve edit_file: approve create_directory: approve move_file: deny # the filesystem server has no delete; move is its destructive op查看上游提供了什么,以及你的策略如何处理它。服务器自身的注释会显示在你的决策旁边,这样你就能注意到你允许了一个破坏性工具:
$ mcpclerk tools --policy examples/policy.filesystem.yaml tool decision rule read_only destructive quota fs.read_file allow glob:read_* True None -/- fs.write_file approve exact False True -/- fs.move_file deny exact False True -/- fs.search_files allow exact True None -/3在你的代理查找 MCP 服务器的地方注册代理。对于 Claude Code,
examples/.mcp.json:{ "mcpServers": { "fs-governed": { "command": "mcpclerk", "args": ["serve", "--policy", "examples/policy.filesystem.yaml"] } } }在第二个终端中,等待批准:
mcpclerk approve。当代理调用fs.write_file时,你会看到调用(秘密已被遮蔽),并回答y或n。之后:
mcpclerk verify audit/mcpclerk.jsonl和mcpclerk report audit/mcpclerk.jsonl。
五个控制
控制 | 它做什么 | 它防止什么 | 它不能防止什么 | 由什么证明 |
允许列表 | 每个工具使用 | 代理使用未经任何人审查的工具。 | 策略本身中的错误决策。 |
|
批准 |
| 无监督的写入。 | 不阅读就批准的人类。 |
|
配额 | 每个工具使用 | 失控的循环;一个廉价工具因数量而变得昂贵。 | 将循环分布到多个工具,或跨代理重启( |
|
脱敏 | 键规则( | 秘密落入日志或批准者的屏幕。 | 形状不在列表上的秘密。通过 |
|
审计日志 | 每次调用一个 JSON Lines 条目,包含时间戳、上游、工具、脱敏参数、决策、批准者、结果、延迟,以及 | 事后静默编辑、删除或重新排序条目;截断已完成的运行( | 从创世块重写整个链的攻击者(这是链,不是签名;见下文)。截断中途被杀死的运行。 |
|
结果不会被记录,只记录它们的大小和内容类型。日志是决策的审计,不是数据的副本;存储结果会使其成为秘密泄漏的第二个地方。
调用如何移动
agent ──tools/call fs.write_file──▶ mcpclerk ──▶ [namespace] ──▶ [allowlist] ──▶ [quota] ──▶ [redact for log]
│ │ │
refused-unknown refused-denied refused-quota
│
┌── decision = approve ──▶ [hold: approvals/<id>.json] ──▶ y ─┐
│ │ n / timeout │
│ refused-by-human / refused-timeout │
└── decision = allow ────────────────────────────────────────┤
▼
[forward with ORIGINAL args] ──▶ upstream ──▶ result
│
[append log entry, hash-chained]每条路径,包括每次拒绝,都以日志条目结束。拒绝以正常工具结果返回给代理,带有 is_error: true 和一行原因:mcpclerk: refused-quota fs.search_files: 3/min exhausted; retry after 60s。
批准,详细说明
代理通常由代理的 MCP 客户端启动,MCP SDK 在新会话中启动 stdio 服务器,因此代理通常没有自己的终端。这就是为什么机制是文件队列,终端提示是它的客户端:
approvals/<id>.json为每个挂起的调用写入,包含脱敏参数、requested_at、expires_at和"approved": null。mcpclerk approve(在同一台机器的任何终端中)显示待处理的请求并写入你的答案。--once回答一个并退出;没有它,它会持续监视。手动编辑文件为
"approved": true也可以,这是无头作业或脚本所做的。如果代理碰巧有控制终端(你手动启动它),它也会在那里提示。两条路径竞争;第一个答案获胜。
在
approval_timeout_s内没有答案就是拒绝,记录为refused-timeout。对写入的沉默意味着不。serve --approve-session自动批准该进程的每个 approve 类调用。它在启动时打印警告,run-start条目记录它,每个受影响的条目说approved_by: session-flag,report会大声喊出来。它不能在策略文件中设置;这是启动进程的人每次调用的行为。
审计日志
{"kind":"call","ts":"2026-08-24T01:14:40.822Z","run_id":"20260824T011440Z-3e1c","id":"20260824T011440Z-0002",
"name":"fs.write_file","upstream":"fs","tool":"write_file","rule":"exact",
"args":{"content":"# notes\n[REDACTED:kv-secret]\n","path":"/tmp/mcpclerk-demo-sandbox/notes.md"},
"decision":"approved","approved_by":"file","held_ms":253.7,"outcome":"ok","is_error":false,
"latency_ms":7.7,"content_bytes":57,"content_types":["text"],
"seq":4,"prev_hash":"5c0e…","hash":"b41a…"}decision是allowed、approved、refused-denied、refused-unknown、refused-quota、refused-timeout、refused-by-human之一。latency_ms仅指上游时间;人类的思考时间是held_ms,因此report中的 p95 延迟指的是工具,而不是人。事件条目(
run-start带有策略的 SHA-256 和标志,discover带有暴露/隐藏计数,run-end带有条目计数)共享同一条链。verify以 0 退出并显示OK n entries, chain intact,或以 1 退出并显示FAIL at line N: <what>。试试:sed -i '' 's/allowed/approved/' examples/audit.demo.jsonl && mcpclerk verify examples/audit.demo.jsonl。
examples/audit.demo.jsonl 中的示例日志是演示运行的真实输出。按构造发布是安全的:脱敏测试证明了这一点,演示将假 API 密钥写入文件,正是为了让日志在原本会出现的地方显示 [REDACTED:kv-secret]。
CLI
mcpclerk serve --policy policy.yaml [--log audit/mcpclerk.jsonl] [--approvals approvals] [--approve-session] [--no-tty]
mcpclerk approve [--approvals approvals] [--once] [--wait 60]
mcpclerk tools --policy policy.yaml [--json]
mcpclerk verify audit/mcpclerk.jsonl
mcpclerk report audit/mcpclerk.jsonl [--json]退出代码:0 正常,1 验证失败或策略无效,2 用法错误。策略在启动时验证,任何问题(未知键、错误决策、未设置的 ${ENV_VAR}、没有 command 的 stdio 上游)都会在代理服务任何内容之前阻止它。
策略参考
version: 1
namespace_separator: "." # "__" for clients that reject dots in tool names
defaults:
unlisted: deny # allow | deny | approve
approval_timeout_s: 120
quota: { per_run: null, per_minute: null }
redaction:
extend: ['(?i)my[-_ ]?internal[-_ ]?token\s*[:=]\s*\S+'] # value regexes, added to the built-ins
extend_keys: [client_secret] # key names, added to the built-ins
replace_builtin: false # true: only your patterns (warned about)
upstreams:
<name>: # [a-z0-9_-]+ ; becomes the prefix in <name>.<tool>
transport: stdio | http
command: ... args: [...] env: { KEY: "${FROM_PROXY_ENV}" } cwd: ... # stdio
url: https://... # http
tools:
<tool or glob>: allow | deny | approve
<tool>: { decision: approve, quota: { per_run: 10, per_minute: 3 }, approval_timeout_s: 60 }先前的工作,以及这取而代之的是什么
MCP 的网关存在并且做得更多:Lasso Security 的 mcp-gateway、IBM 的 mcp-context-forge 和 Docker 的 MCP Gateway 带来了注册表、多租户认证、插件管道和可观测性。mcpclerk 不声称新颖。它声称小巧和可验证:一个单一用途、可读、本地的代理,其全部表面就是上述五个控制和一个你可以检查的日志。它大约有 1,000 行 Python,你可以在一个下午读完,除了 MCP SDK 之外只有一个依赖(一个 YAML 解析器)。
它不做什么(尚未)
身份和按用户策略。假定只有一个操作员;日志记录的是有人类批准,而不是哪个人类。
Web UI 或远程审批渠道(Slack、email)。
mcpclerk approve是本地终端。跨上游的策略继承或模板化。
资源和提示。v0.1 仅代理工具;
resources/list和prompts/list为空。需要请求头的 HTTP 上游。此版本中 SDK 的 HTTP 传输不接受任何请求头;设置
headers的策略会大声失败,而不是静默地不发送任何内容。Windows:文件队列和
mcpclerk approve可用;进程内终端提示不可用(没有/dev/tty)。CI 尽力运行 Windows。
威胁模型,坦诚地说
攻击者如果占据代理的位置,首先会尝试调用一个不在列表中的工具名称。这会被拒绝并记录(refused-unknown 或 refused-denied)。这并不能阻止:一个被允许的工具被用于有害目的(策略是你的判断,mcpclerk 强制执行),一个橡皮图章式的审批者,以及任何对日志文件有写权限的人从第一条记录开始重写整个链。该链防御的是静默编辑,这是现实中的威胁;签名或外部锚点(将每日头部哈希发布到你无法控制的地方)将是下一步,但不在 v0.1 中。
开发
pip install -e ".[dev]"
pytest -q # 49 tests, all in-process, no network, no subprocesses
python examples/demo_driver.py --approve-via-file # the demo against the real filesystem server (needs npx)
vhs examples/demo.tape # re-record the GIF测试在两侧使用 MCP SDK 的内存传输:Client(proxy) → proxy → Client(fake_upstream)。假上游(tests/fake_upstream.py)有一个 secret_sink 工具,它返回它收到的确切内容,这就是测试套件如何证明上游看到未脱敏的参数而日志却没有。
相关项目:toilscan(同样的写安全直觉应用于开发者工具)、agent-slots(并行代理的运行时隔离)以及 agentkeel(进程侧:代理编写代码的门禁和爆炸半径;进行中)。
对于下一个接手的人:docs/learning/how-it-works.html 是导览(按调用顺序的代码、控制、面试答案);docs/spec.md 是契约。
许可证
MIT.
This server cannot be deployed
Maintenance
Related MCP Connectors
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Security & DLP proxy for MCP: tool-poisoning scans, PII redaction on tool args/results. Beta.
- gatewayOAuthai.sealgate
MCP gateway with runtime security policy, tool-call-level control, and audit of agent actions.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceA least-privilege enforcement proxy for MCP servers. It sits between MCP clients and upstream servers, enforcing tool policies, hiding denied tools, requiring human approval for risky actions, and providing a structured audit trail.MIT
- AlicenseNot gradedqualityAmaintenanceAn authorizing reverse proxy for MCP servers that enforces per-call policy rules on tool arguments with audit logging, dry-run, and rate limiting.Apache 2.0
- AlicenseAqualityCmaintenanceProvides a security governance layer for AI agents to safely access upstream MCP servers, enforcing tool-level RBAC, parameter constraints, authentication via static tokens or OIDC, and tamper-evident audit logging.21Apache 2.0
- FlicenseNot gradedqualityBmaintenanceEnforces default-deny policies, budgets, and tamper-evident audit logging for MCP tool calls before they reach upstream servers.-