Skip to main content
Glama

approval-gate-mcp

MCP-сервер, который ставит человеческий шлюз одобрения перед длительным автономным процессом, плюс операционные инструменты, необходимые для реальной работы с ним: статус, журналы, перезапуск, параметры горячей перезагрузки и сводка о том, что он сделал.

Создан на основе FastMCP. Работает с любым MCP-клиентом.

Проблема

Процесс, который действует сам по себе, полезен ровно до тех пор, пока одно из его действий не становится значимым. Обычные ответы одинаково плохи. Выключите его — и вы потеряете всё, что он делал хорошо. Оставьте работать — и узнаете об этом потом.

Шлюз — это третий вариант. Процесс продолжает работать без присмотра, но когда он хочет выполнить действие, которое вы пометили как значимое, он записывает предложение и движется дальше, вместо того чтобы действовать. Вы просматриваете предложения, когда до них доходят руки, в любом уже открытом MCP-клиенте, и одобряете или отклоняете. Процесс подхватывает ваше решение на следующем цикле.

Ни одна из сторон не блокирует другую. Между ними нет никакого сервиса. Контракт — это два JSON-файла.

  process                            you
     |                                |
     |-- writes proposal ----> pending.json
     |                                |
     |                          list_pending_approvals
     |                          approve(0) / reject(1)
     |                                |
     |<-- reads on next cycle -- approved.json
     |
     |-- acts, appends to records.json

Related MCP server: conduit-mcp

Инструменты

Шлюз одобрения

Инструмент

Что делает

list_pending_approvals

Каждое предложение, ожидающее решения, со всеми его полями

approve(index)

Переместить одно предложение в файл одобренных

reject(index)

Отклонить одно предложение

Управление процессом

Инструмент

Что делает

process_status

Запущен или нет, PID, время работы, ЦП, память, диск, последняя строка журнала

process_logs(lines)

Хвост файла журнала

restart_process

Перезапуск через ваш стартовый скрипт, в отвязанном режиме, чтобы пережить SSH-сессию

run_command(cmd)

Запасной выход для разовых проверок

Записи

Инструмент

Что делает

record_summary(n)

Итоги, решённые и открытые, разбивка по типам, последние записи

record_dashboard

Более широкая таблица, а также открытые записи и их экспозиция

Параметры — регистрируются только если PARAMS_SCHEMA указывает на ваш манифест

Инструмент

Что делает

list_params

Что данное развертывание объявляет настраиваемым и что переопределено прямо сейчас

set_param(name, value)

Записать одно переопределение с проверкой по вашему манифесту

clear_param(name)

Удалить одно переопределение или все сразу

Цепочка — регистрируется только если заданы EVM_RPC_URL, WALLET_ADDRESS и TOKEN_CONTRACT

Инструмент

Что делает

wallet_balance

Баланс ERC-20 и нативный баланс для отслеживаемого адреса только для чтения. Ничего не подписывается

Установка

git clone https://github.com/WillyV347/approval-gate-mcp
cd approval-gate-mcp
pip install -r requirements.txt
cp .env.example .env      # then edit it

Попробуйте в инспекторе, прежде чем подключать к клиенту:

fastmcp dev server.py

Затем зарегистрируйте его. Для клиента, который читает JSON-конфигурацию:

{
  "mcpServers": {
    "approval-gate": {
      "command": "python3",
      "args": ["/absolute/path/to/approval-gate-mcp/server.py"],
      "env": {
        "VPS_HOST": "your.host.or.ip",
        "VPS_USER": "your-ssh-user",
        "PROCESS_DIR": "/srv/my-process",
        "PROCESS_MATCH": "my_process.py",
        "PARAMS_SCHEMA": "/absolute/path/to/params.schema.json"
      }
    }
  }
}

Для VPS_HOST, VPS_USER и PROCESS_DIR нет значений по умолчанию. Сервер завершает работу с понятным сообщением, если они отсутствуют. Инструмент мониторинга, который молча откатывается к хосту, зашитому его автором, — это баг, поэтому этот отказывается угадывать.

Аутентификация — это ваша существующая настройка SSH. Сервер вызывает системный бинарник ssh, поэтому агенты, аппаратные ключи и менеджеры паролей, поддерживающие агента, работают без изменений. Сам он никогда не читает закрытый ключ.

Контракт, который реализует ваш процесс

На стороне процесса нужны три вещи. Ни одна из них не требует библиотеки.

1. Записи. Добавляйте в JSON-массив. Четыре ключа интерпретируются, если присутствуют, а всё остальное переносится без изменений:

[
  {
    "id": "job-1041",
    "record_type": "reindex",
    "resolved": true,
    "outcome": "win",
    "cost": 4.25,
    "result": 11.80,
    "label": "nightly reindex, shard 3"
  }
]

2. Предложения. В режиме одобрения записывайте сюда вместо действия:

{
  "proposals": [
    {
      "id": "job-1042",
      "label": "reindex shard 7",
      "action": "reindex",
      "cost": 6.00,
      "created_at": "2026-08-18T22:14:07Z"
    }
  ]
}

Каждое включенное поле отображается. У сервера нет схемы для предложений, и она ему не нужна.

3. Опросите файл одобренных. На каждом цикле читайте approved.json, выполняйте то, что там есть, и очищайте его. Примерно:

approved = read_json(APPROVED_FILE) or {"proposals": []}
for proposal in approved["proposals"]:
    execute(proposal)
write_json(APPROVED_FILE, {"proposals": []})

Порядок на стороне сервера продуман. Решение удаляет предложение из pending.json до записи в approved.json, поэтому сбой при незавершенном решении приводит к потере предложения, но никогда к дублированию действия.

Параметры и почему их нет в этом репозитории

Горячая перезагрузка полезна только если сервер знает, что можно настраивать, а зашивание параметров одного развертывания в общий инструмент делает его узкоспециализированным. Поэтому вы объявляете свои параметры в манифесте и указываете на него через PARAMS_SCHEMA:

{
  "poll_interval_seconds": { "type": "int",  "description": "Seconds between work cycles" },
  "max_concurrent_jobs":   { "type": "int",  "description": "Jobs in flight at once" },
  "dry_run":               { "type": "bool", "description": "Plan work but do not execute" },
  "approval_mode":         { "type": "bool", "description": "Queue proposals instead of acting" }
}

Поддерживаемые типы: int, float, bool, str, dict и list. set_param приводит и проверяет по ним и отклоняет всё, что не конвертируется. Без манифеста инструменты параметров просто не регистрируются, что лучше, чем открывать путь записи без проверки.

params.schema.json находится в .gitignore, потому что ваша настройка — ваша. params.schema.example.json поставляется в качестве отправной точки.

Пусть ваш процесс читает файл переопределений при запуске и на каждом цикле, если вы хотите, чтобы изменения применялись без перезапуска:

overrides = read_json(PARAMS_FILE) or {}
poll_interval = overrides.get("poll_interval_seconds", POLL_INTERVAL_DEFAULT)

Пример сеанса

> is it running?

  Process RUNNING

  PID:      31882
  Uptime:   14h 22m (51720s)
  CPU:      0.6%
  Memory:   84.3 MB
  Disk:     212M

  Last log: 2026-08-18 22:03:11 cycle complete, 2 proposals queued

> anything waiting on me?

  2 proposal(s) awaiting approval

  --- Proposal #0 ------------------------------
    id:           job-1042
    label:        reindex shard 7
    action:       reindex
    cost:         6.00
    created_at:   2026-08-18T22:14:07Z

  --- Proposal #1 ------------------------------
    id:           job-1043
    label:        reindex shard 12
    action:       reindex
    cost:         6.00
    created_at:   2026-08-18T22:14:07Z

  Use approve(index) or reject(index) to decide.

> approve 0, reject 1

  Approved and queued for execution: reindex shard 7
  Rejected and removed: reindex shard 12

Вывод выше носит иллюстративный характер.

Заметки о безопасности

  • run_command выполняет произвольный shell на удаленном хосте. Он существует, потому что альтернатива — всё равно открывать терминал, но это самый опасный инструмент здесь. Ограничьте SSH-пользователя тем, что ему действительно нужно, а не запускайте всё от root.

  • wallet_balance доступен только для чтения и никогда не касается ключа. Если вы его не настроили, его не существует.

  • Ничто в этом репозитории не хранит учетные данные. RPC-URL несут ключи провайдера в пути, поэтому держите EVM_RPC_URL в переменных окружения, а не в конфигурационных файлах.

  • StrictHostKeyChecking установлен в accept-new: неизвестные хосты доверяются при первом подключении, измененные ключи хоста по-прежнему приводят к ошибке. Установите yes и заранее заполните known_hosts, если хотите более строгое поведение.

Лицензия

MIT

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    MCP server that enforces governance on agentic decisions with auditable evidence records, providing tools for understanding, calibrating confidence, and navigating handoffs based on policy.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    A governance-layer MCP server that gates AI writes to systems of record, requiring human signatures and providing a tamper-evident audit trail. It offers read, propose, approve, commit, and audit tools, with demo and Xero backends.
    69 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server that provides human-in-the-loop approval for risky AI agent actions, with durable state and audit logs.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server that adds a trust layer to AI agent memory, enforcing independent review and tamper-evident audit chains for any memory store. It provides tools to search, get, propose, and promote memories under governance rules.
    37 PyPI
    MIT