
Легковесный mcp для предотвращения отравления CVE (CVE-2025-54136), исследователи, захватывающие Claude Code/Copilot/Gemini через prompt injection, и сотни MCP-серверов, доступных без аутентификации, этот mcp защищает ноутбук отдельного разработчика, где на самом деле работает большинство MCP-серверов.
Шлюз безопасности для MCP-серверов — каждый вызов инструмента проверяется на входе.
CI npm License: Apache-2.0 PR приветствуются
mcp-doorman — это прокси, который встраивается между вашим AI-агентом (Claude Desktop, Claude Code, Cursor, VS Code, любой MCP-клиент) и используемыми MCP-серверами. Одна команда, нулевая инфраструктура, и каждый вызов tools/list и tools/call проходит через цепочку защиты:
Каждый находится в одном npx some-random-mcp-server от передачи непроверенному процессу своих API-ключей и прямого доступа в контекстное окно модели. Задокументированные классы атак реальны, а не гипотетичны:
| Атака | Как это работает |
|---|---|
| Отравление инструментов | Вредоносные инструкции, спрятанные в описании инструмента, невидимые в большинстве интерфейсов клиента |
| Подмена | Сервер в первый день показывает безобидные инструменты, а после утверждения меняет их определения |
| Косвенная инъекция подсказок | Веб-страница/задача/письмо, полученные легитимным инструментом, содержат инструкции, нацеленные на модель |
| Эксфильтрация секретов | Утекшие учётные данные в одном результате инструмента + одна внедрённая инструкция = ваш ключ на чужом сервере |
| Неуправляемые циклы | Спутанный или захваченный агент массово удаляет, массово рассылает, массово парсит |
Корпоративные MCP-шлюзы существуют для платформенных команд с кластерами Kubernetes. Ничего лёгкого не защищает ноутбук отдельного разработчика — то место, где на самом деле работают 99% MCP-серверов. Этот пробел и заполняет данный проект.
# 1. Создайте конфигурацию
npx -y mcp-doorman init
# 2. Отредактируйте doorman.config.json — вставьте свои реальные серверы
# 3. Зафиксируйте текущие определения инструментов (доверие при первом использовании)
npx -y mcp-doorman pin --config doorman.config.json
Затем укажите вашему клиенту на шлюз вместо ваших серверов. Claude Desktop / Claude Code / Cursor:
// ДО — каждый сервер общается напрямую с моделью
{
"mcpServers": {
"github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] },
"filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/repos"] }
}
}
// ПОСЛЕ — один doorman охраняет их всех
{
"mcpServers": {
"doorman": {
"command": "npx",
"args": ["-y", "mcp-doorman", "run", "--config", "/absolute/path/to/doorman.config.json"]
}
}
}
Инструменты отображаются с пространством имён, например github__create_issue, filesystem__read_file и т.д., а также два встроенных: doorman__status и doorman__recent_events (спросите агента «что недавно заблокировал doorman?»).
Примечание для Windows: если запись сервера использует
npxнапрямую, запускайте её через cmd:"command": "cmd", "args": ["/c", "npx", "-y", "..."].
git clone https://github.com/Sushank05/mcp-doorman && cd mcp-doorman
npm install
npm run demo
Демонстрация подключает шлюз к намеренно некорректному серверу (examples/demo-server.mjs), который раскрывает поддельные учётные данные, отправляет полезную нагрузку инъекции подсказок и предлагает деструктивный инструмент — и показывает, как каждый защитник ловит это.
flowchart LR
A["MCP-клиент\n(Claude Desktop, Cursor, ...)"] -- stdio --> D
subgraph D [mcp-doorman]
direction TB
P[политика] --> R[ограничение частоты] --> AP[одобрение] --> RD[редактирование] --> I[сканирование инъекций] --> AU[(журнал аудита)]
end
D -- stdio --> S1[сервер github]
D -- stdio --> S2[сервер filesystem]
D -- streamable HTTP --> S3[удалённый сервер]Шлюз является MCP сервером для вашего клиента и MCP клиентом для каждого вышестоящего сервера (дочерние процессы stdio или конечные точки streamable-HTTP), объединяя их за одним подключением. Он построен на официальном TypeScript SDK.
Всё находится в одном JSON-файле. Полный пример со всеми опциями:
{
"servers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" } // ${VAR} = читать из окружения шлюза
},
"remote": { "url": "https://mcp.example.com/mcp", "headers": { "Authorization": "Bearer ${MCP_TOKEN}" } }
},
"policy": {
"defaultAction": "allow", // "allow" | "deny" | "approve"
"rules": [ // первое совпадение выигрывает, оценка сверху вниз
{ "match": "*__delete*", "action": "deny", "reason": "нет деструктивных инструментов" },
{ "match": ["github__create_*", "*__send_*"], "action": "approve" },
{ "match": "filesystem__*", "action": "allow" }
]
},
"redaction": {
"enabled": true,
"disable": [], // названия встроенных правил для отключения
"enableOptIn": ["email"], // опции добровольного включения: "email", "us-ssn", "ipv4"
"custom": [{ "name": "acme-id", "pattern": "ACME-[0-9]{6}" }],
"redactArguments": false // также очищать аргументы, предоставленные моделью
},
"injection": {
"action": "flag", // "flag" (предупредить модель) | "block" | "off"
"scanToolDescriptions": true, // проверка на отравление инструментов при tools/list
"custom": []
},
"pinning": {
"enabled": true,
"onNewTool": "pin", // "pin" (TOFU) | "block" (до `mcp-doorman pin`)
"onChangedTool": "block" // "block" | "warn"
},
"rateLimit": { "perMinute": 120, "perTool": { "*__send_*": 5 } },
"approval": { "fallback": "deny", "timeoutMs": 120000 }, // fallback, если у клиента нет elicitation
"audit": { "enabled": true, "includeArguments": true, "includeResults": false },
"logLevel": "info"
}
Состояние фиксации и журнал аудита по умолчанию находятся в <config-name>.pins.json / <config-name>.audit.jsonl рядом с файлом конфигурации.
| Команда | Что делает |
|---|---|
mcp-doorman run --config <path> | Запустить шлюз через stdio (команда по умолчанию) |
mcp-doorman pin --config <path> | Подключиться ко всем вышестоящим серверам и зафиксировать (довериться) их текущие определения инструментов |
mcp-doorman init | Записать стартовую конфигурацию с разумными значениями по умолчанию |
Инструменты безопасности, которые преувеличивают, хуже, чем их отсутствие. Прочтите эту часть.
deny/approve как жёсткую границу; сканирование — это защита в глубину.approval.fallback (по умолчанию deny).resources/* и prompts/* (сейчас только инструменты)doorman-rules-finance, doorman-rules-healthcare…)mcp-doorman audit: красивая печать и запросы к JSONL-журналуВозьмитесь за что-нибудь из этого или начните с [first good issue](https://github.com/YOUR_GITHUB_USERNAME/mcp-doorman/labels/good%20first issue). Новые правила обнаружения — самый лёгкий вклад: одно регулярное выражение + два теста. См. CONTRIBUTING.md и docs/detection-rules.md.
npm install
npm test # 69 тестов: модульные + полные сквозные stdio
npm run build
npm run demo # смотрите, как защитники срабатывают вживую
Apache-2.0 — бесплатно для любого использования, с явной патентной оговоркой.