mcpclerk
mcpclerk
Управляющий прокси для MCP-серверов: встаёт перед любым MCP-сервером, применяет разрешённый список инструментов, удерживает инструменты класса записи для одобрения человеком, применяет квоты на каждый инструмент, редактирует аргументы, похожие на секреты, и пишет хэш-цепочный журнал аудита каждого вызова.
ИИ-агент на MCP-серверах может вызывать любой инструмент, который они предоставляют, сколько угодно раз, с любыми аргументами, и ничто не фиксирует, что он делал, в форме, которую можно проверить. В корпоративной среде вопрос не в том, «может ли агент выполнить работу», а в том, что ему разрешено делать, кто одобрил опасные части и что он фактически сделал?
mcpclerk отвечает на эти три вопроса кодом. Он сам является MCP-сервером: агент подключается к нему, он подключается к реальным серверам и повторно предоставляет их инструменты как upstream.tool. Каждый вызов проходит через один конвейер: разрешённый список, квота, редактирование, одобрение, пересылка, журнал. Неперечисленный инструмент отклоняется. Инструмент класса записи ждёт, пока человек ответит y. Отказы возвращаются как читаемые ошибки. Журнал — это append-only JSON Lines, каждая запись хэшируется с предыдущей, так что любое изменение где-либо разрывает цепочку.
Демонстрация оборачивает официальный файловый сервер: чтение проходит, запись удерживается и одобряется, перемещение отклоняется, четвёртый поиск в минуту отклоняется по квоте, и журнал проверяется. 49 тестов доказывают каждый контроль против фейкового upstream, включая то, что upstream всегда получает нередактированные аргументы.

Установка
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: Agentrim MCP
Пять минут
Напишите политику. Вот та, что из демонстрации (
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Посмотрите, что предлагает upstream и что ваша политика с ним делает. Собственные аннотации сервера показаны рядом с вашим решением, что позволяет заметить, что вы разрешили разрушительный инструмент:
$ 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 на вызов с временной меткой, upstream, инструментом, редактированными аргументами, решением, кто одобрил, результатом, задержкой и | Тихое редактирование, удаление или переупорядочивание записей после факта; усечение завершённого запуска ( | Атакующий, который переписывает всю цепочку с начала (это цепочка, а не подпись; см. ниже). Усечение запуска, убитого на полпути. |
|
Результаты не записываются, только их размер и типы содержимого. Журнал — это аудит решений, а не копия данных; хранение результатов сделало бы его вторым местом утечки секретов.
Как движется вызов
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тоже работает — так делают headless-задачи или скрипты.Если у прокси всё же есть управляющий терминал (вы запустили его вручную), он также запрашивает там. Оба пути соревнуются; первый ответ побеждает.
Отсутствие ответа в течение
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— только время upstream; время размышлений человека — этоheld_ms, так что p95 задержки вreportозначает инструмент, а не человека.Событийные записи (
run-startс SHA-256 политики и флагами,discoverсо счётчиками exposed/hidden,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 — verify не прошёл или политика недействительна, 2 — использование. Политика проверяется при запуске, и любая проблема (неизвестный ключ, плохое решение, неустановленный ${ENV_VAR}, stdio-upstream без command) останавливает прокси до того, как он начнёт обслуживать что-либо.
Справочник по политике
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's mcp-gateway, IBM's mcp-context-forge и Docker's MCP Gateway приносят реестры, мультитенантную аутентификацию, плагинные конвейеры и наблюдаемость. mcpclerk не претендует на новизну. Он претендует на малость и проверяемость: одноцелевой, читаемый, локальный прокси, вся поверхность которого — пять контролей выше и журнал, который можно проверить. Это около 1000 строк Python, которые можно прочитать за вечер, с одной зависимостью помимо MCP SDK (парсер YAML).
Что он (пока) не делает
Идентичность и политики для каждого пользователя. Предполагается один оператор; журнал фиксирует что человек одобрил, а не какой человек.
Веб-интерфейс или удалённые каналы одобрения (Slack, email).
mcpclerk approve— это локальный терминал.Наследование политик или шаблонизация для вышестоящих систем.
Ресурсы и промпты. v0.1 проксирует только инструменты;
resources/listиprompts/listпусты.HTTP-апстримы, которым нужны заголовки запросов. HTTP-транспорт SDK в этой версии не принимает их; политика, устанавливающая
headers, громко завершается с ошибкой, а не молча ничего не отправляет.Windows: файловая очередь и
mcpclerk approveработают; внутрипроцессный терминальный промпт — нет (нет/dev/tty). CI запускает Windows по принципу best-effort.
Модель угроз, честно
Что атакующий, находящийся на месте агента, попробует в первую очередь — вызвать инструмент по имени, скрытый из списка. Это отклоняется и записывается в журнал (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 installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityCmaintenanceSecurity gateway that wraps any MCP server with per-tool policies, approval gates, and optional Ed25519-signed decision receipts. Shadow mode logs every tool call without blocking; enforce mode applies block, rate-limit, and minimum-tier rules. Receipts are independently verifiable offline with no accounts needed.54699MIT
- 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
- AlicenseAqualityAmaintenanceAn MCP proxy that enforces policy on every tool call, blocking or flagging actions before they reach downstream MCP servers.1249MIT
- 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
Related MCP Connectors
Remote MCP for A2A caller identity, scope policy, verdict receipts, and audit history.
Runtime permission, approval, and audit layer for AI agent tool execution.
A paid remote MCP for CLI tool MCP, built to return verdicts, receipts, usage logs, and audit-ready
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/hishamalward/mcpclerk'
If you have feedback or need assistance with the MCP directory API, please join our Discord server