Перейти к содержимому

MCP Сервер

Notifly MCP Server — это реализация Model Context Protocol (MCP), позволяющая AI-ассистентам (Claude, GitHub Copilot и другим) управлять Notifly через набор готовых инструментов.

С помощью MCP-сервера AI-ассистент может:

  • отправлять уведомления в каналы;
  • читать, фильтровать и удалять сообщения;
  • создавать и управлять каналами и клиентами;
  • задавать вопросы человеку и ждать ответа (human-in-the-loop);
  • заводить heartbeat-ы, мониторы и сканы портов, смотреть историю проверок;
  • администрировать пользователей сервера — только с токеном устройства администратора (см. Пользователи).

Путь до первого вызова — пять шагов:

  1. Выберите клиент. Ниже — готовые конфиги для Claude Desktop, Claude Code и Cursor; для VS Code, Windsurf, Codex, Zed и Continue — в разделах «Подключение к …» дальше на странице.
  2. Соберите сервер. notifly-mcp — один исполняемый файл, готовых сборок для скачивания пока нет: его собирают из исходников (см. Установка) и кладут, например, в /usr/local/bin/notifly-mcp.
  3. Возьмите токены в админке: API-токен (M…, страница API-токены) — для работы с каналами, мониторами и сообщениями, и app-токен канала (A…, раздел «Каналы») — чтобы ассистент мог отправлять уведомления.
  4. Вставьте конфиг своего клиента и подставьте свои значения вместо MXXXXXXXXXXXXXXXXXXXXXX (API-токен) и AXXXXXXXXXXXXXXXXXXXXXX (app-токен). NOTIFLY_URL для облачного Notifly — https://api.notifly.ru; для self-hosted — адрес вашего сервера.
  5. Проверьте первым вызовом — см. ниже.

Claude Desktop — ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) или %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
"mcpServers": {
"notifly": {
"command": "/usr/local/bin/notifly-mcp",
"env": {
"NOTIFLY_URL": "https://api.notifly.ru",
"NOTIFLY_APP_TOKEN": "AXXXXXXXXXXXXXXXXXXXXXX",
"NOTIFLY_API_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
}

Claude Code — одна команда в терминале:

Окно терминала
claude mcp add notifly /usr/local/bin/notifly-mcp \
-e NOTIFLY_URL=https://api.notifly.ru \
-e NOTIFLY_APP_TOKEN=AXXXXXXXXXXXXXXXXXXXXXX \
-e NOTIFLY_API_TOKEN=MXXXXXXXXXXXXXXXXXXXXXX

Cursor — файл .cursor/mcp.json в корне проекта (или ~/.cursor/mcp.json глобально):

{
"mcpServers": {
"notifly": {
"command": "/usr/local/bin/notifly-mcp",
"env": {
"NOTIFLY_URL": "https://api.notifly.ru",
"NOTIFLY_APP_TOKEN": "AXXXXXXXXXXXXXXXXXXXXXX",
"NOTIFLY_API_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
}

Перезапустите клиент (Cursor подхватит конфиг сам) и попросите ассистента:

  1. «Покажи мои каналы в Notifly» — ассистент вызовет list_applications и вернёт JSON-список ваших каналов. Это проверяет адрес и API-токен.
  2. «Отправь в Notifly уведомление „MCP подключён“» — вызов send_message вернёт созданное сообщение с id, сообщение появится в ленте админки и — если подключено устройство-получатель — придёт уведомлением.

Если инструмент вернул HTTP 401 — проверьте токен; если клиент не видит инструментов Notifly вовсе — путь к notifly-mcp в конфиге. Адрес сервера без токенов проверяет get_health.


  • Go 1.27 или новее

Готового бинаря для скачивания пока нет, а репозиторий с исходниками закрыт: MCP-сервер собирается из исходников. Если доступа к репозиторию у вас нет — напишите на support@notifly.ru. Если исходники у вас есть, сборка такая:

Окно терминала
git clone https://github.com/truboter/notifly.ru.git
cd notifly.ru/mcp
go mod tidy
go build -o notifly-mcp .

Готовый бинарный файл notifly-mcp запускается через stdio-транспорт — MCP-клиент запускает его как дочерний процесс.


Сервер настраивается исключительно через переменные окружения:

ПеременнаяОбязательнаяОписание
NOTIFLY_URL✓Базовый URL сервера Notifly: https://api.notifly.ru для облака или адрес вашего сервера
NOTIFLY_APP_TOKENТокен канала (префикс A) — для send_message и инструментов вопросов: ask_question, get_ask_answer, extend_ask_question, list_pending_answers, ack_answers
NOTIFLY_API_TOKENAPI-токен (префикс M) — для всего остального
NOTIFLY_USERЛогин (запасной вариант вместо API-токена)
NOTIFLY_PASSПароль к нему

Откройте файл конфигурации Claude Desktop:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Добавьте секцию mcpServers:

{
"mcpServers": {
"notifly": {
"command": "/usr/local/bin/notifly-mcp",
"env": {
"NOTIFLY_URL": "https://api.notifly.ru",
"NOTIFLY_APP_TOKEN": "AXXXXXXXXXXXXXXXXXXXXXX",
"NOTIFLY_API_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
}

После перезапуска Claude Desktop инструменты Notifly появятся в интерфейсе.


Добавьте в .vscode/mcp.json в корне проекта или в пользовательские настройки VS Code:

{
"servers": {
"notifly": {
"type": "stdio",
"command": "/usr/local/bin/notifly-mcp",
"env": {
"NOTIFLY_URL": "https://api.notifly.ru",
"NOTIFLY_APP_TOKEN": "AXXXXXXXXXXXXXXXXXXXXXX",
"NOTIFLY_API_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
}

Добавьте файл .cursor/mcp.json в корень проекта (project-scope) или ~/.cursor/mcp.json глобально:

{
"mcpServers": {
"notifly": {
"command": "/usr/local/bin/notifly-mcp",
"env": {
"NOTIFLY_URL": "https://api.notifly.ru",
"NOTIFLY_APP_TOKEN": "AXXXXXXXXXXXXXXXXXXXXXX",
"NOTIFLY_API_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
}

После сохранения файла Cursor подхватит сервер автоматически. Убедитесь, что notifly-mcp доступен в PATH.


Откройте или создайте файл ~/.codeium/windsurf/mcp_config.json и добавьте секцию mcpServers:

{
"mcpServers": {
"notifly": {
"command": "/usr/local/bin/notifly-mcp",
"env": {
"NOTIFLY_URL": "https://api.notifly.ru",
"NOTIFLY_APP_TOKEN": "AXXXXXXXXXXXXXXXXXXXXXX",
"NOTIFLY_API_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
}

После сохранения перезапустите Windsurf — инструменты Notifly появятся в Cascade.


Используйте команду claude mcp add для регистрации сервера:

Окно терминала
claude mcp add notifly /usr/local/bin/notifly-mcp \
-e NOTIFLY_URL=https://api.notifly.ru \
-e NOTIFLY_APP_TOKEN=AXXXXXXXXXXXXXXXXXXXXXX \
-e NOTIFLY_API_TOKEN=MXXXXXXXXXXXXXXXXXXXXXX

Флаг --scope user добавляет сервер глобально для всех проектов (по умолчанию — project-scope). Проверить список добавленных серверов: claude mcp list.


Откройте или создайте файл ~/.codex/config.toml и добавьте секцию:

[mcp_servers.notifly]
command = "/usr/local/bin/notifly-mcp"
env = { NOTIFLY_URL = "https://api.notifly.ru", NOTIFLY_APP_TOKEN = "AXXXXXXXXXXXXXXXXXXXXXX", NOTIFLY_API_TOKEN = "MXXXXXXXXXXXXXXXXXXXXXX" }

После сохранения Codex подхватит сервер при следующем запуске. Убедитесь, что notifly-mcp доступен в PATH.


Откройте файл настроек Zed (~/.config/zed/settings.json) и добавьте секцию context_servers:

{
"context_servers": {
"notifly": {
"command": {
"path": "/usr/local/bin/notifly-mcp",
"args": [],
"env": {
"NOTIFLY_URL": "https://api.notifly.ru",
"NOTIFLY_APP_TOKEN": "AXXXXXXXXXXXXXXXXXXXXXX",
"NOTIFLY_API_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
}
}

Zed подхватит сервер без перезапуска.


Добавьте секцию mcpServers в файл конфигурации Continue (~/.continue/config.json):

{
"mcpServers": [
{
"name": "notifly",
"command": "/usr/local/bin/notifly-mcp",
"env": {
"NOTIFLY_URL": "https://api.notifly.ru",
"NOTIFLY_APP_TOKEN": "AXXXXXXXXXXXXXXXXXXXXXX",
"NOTIFLY_API_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX"
}
}
]
}

Continue поддерживается как расширение для VS Code и JetBrains IDE.


Всего сервер регистрирует 117 инструментов. Чаще всего нужны несколько:

ЗадачаИнструменты
Проверить подключениеget_health, list_applications
Отправить уведомлениеsend_message
Спросить человека и дождаться ответаask_question → get_ask_answer (wait_sec)
Прочитать и найти сообщенияlist_messages, search_messages
Завести каналcreate_application

Полный каталог ниже сгруппирован по разделам.

ИнструментОписание
get_healthПроверить работоспособность сервера и базы данных
get_versionПолучить версию, commit и дату сборки
get_server_infoПолучить флаги сервера (регистрация, OIDC)
ИнструментПараметрыОписание
send_messagemessage*, title, priority, markdown, extras, app_tokenОтправить уведомление (требует NOTIFLY_APP_TOKEN или app_token). priority 0–10, 0 — приоритет канала по умолчанию; markdown: true — рендерить текст как Markdown; extras — строка с JSON-объектом extras, объединяется с markdown; app_token — токен другого канала (A…) вместо NOTIFLY_APP_TOKEN
list_messageslimit, sinceСписок всех сообщений с пагинацией
list_application_messagesapp_id*, limit, sinceСообщения конкретного канала
delete_messageid*Удалить сообщение по ID
delete_all_messages—Удалить все сообщения
delete_application_messagesapp_id*Удалить все сообщения канала
search_messagesq*, app_id, recursive, limit, sinceПоиск сообщений по тексту (мин. 2 символа); по всем каналам или в одном. recursive: true вместе с app_id — искать и в дочерних каналах
mark_messages_readids*Отметить сообщения прочитанными (JSON-массив ID, например [1,2,3])
mark_application_readapp_id*, recursiveОтметить прочитанными все сообщения канала (recursive — вместе с дочерними). Прочтение останавливает эскалацию доставки по этим сообщениям
ИнструментПараметрыОписание
ask_questionquestion*, options, fields, next, title, timeout_sec, default_answer, allow_multi, json_format, client_message_id, app_tokenЗадать вопрос человеку (push/Telegram/email с кнопками); вернёт id вопроса. fields — форма до 10 полей, ответ придёт объектом {name: value} (несовместимо с options); next — ветвление закрытого вопроса {"<вариант>": {…вопрос…}}: только с options и без allow_multi, глубина цепочки до 5, ответ содержит nextQuestionId. Требует NOTIFLY_APP_TOKEN или app_token. См. Вопросы (Ask)
get_ask_answerid*, wait_sec, app_tokenПолучить ответ; при wait_sec > 0 — дождаться: ответ приходит push-ом по WebSocket, при недоступности сокета — опросом раз в 3 с, до 300 с. Вернёт answered+ответ (для формы — объект {name: value}, при ветвлении — ещё и nextQuestionId), pending, expired или cancelled. Требует NOTIFLY_APP_TOKEN или app_token
extend_ask_questionid*, timeout_sec*, app_tokenПродлить вопрос: у pending дедлайн сдвигается на timeout_sec (1–86400) от текущего момента; expired, истёкший менее 24 часов назад, возвращается в pending; для answered/cancelled — конфликт. Требует NOTIFLY_APP_TOKEN или app_token
cancel_ask_questionid*Отменить ожидающий вопрос
answer_questionid*, answer*Ответить на вопрос от имени пользователя — когда решение принимает сам агент, а не человек
list_pending_answersapp_tokenВопросы канала, на которые уже ответили, но ответ ещё не забран. Удобно, когда вопросов много: получить список, обработать ответы, затем подтвердить через ack_answers. Требует NOTIFLY_APP_TOKEN или app_token
ack_answersids*, app_tokenПодтвердить, что ответы обработаны, — list_pending_answers перестанет их показывать. ids — массив ID вопросов, например [1,2,3]. Требует NOTIFLY_APP_TOKEN или app_token

Пара ask_question → get_ask_answer(wait_sec) — готовый approval-гейт для AI-агента: спросить разрешение у человека и продолжить по ответу.

ИнструментПараметрыОписание
list_applications—Список всех каналов
create_applicationname*, description, default_priority, tagsСоздать канал. tags — до 10 тегов из [a-z0-9_-]; используются тег-скоупом API-токенов
update_applicationid*, name, description, default_priority, tagsОбновить канал; tags заменяют текущие (не передан — не меняются)
delete_applicationid*Удалить канал
get_application_statusapp_id*, recursiveСводный статус канала по его heartbeat-ам: сколько всего, сколько алертит, когда был последний сигнал; recursive — учесть дочерние каналы
list_event_sourcesapp_id*Что шлёт события в канал: мониторы, heartbeat-ы и другие источники
test_deliveryapp_id*, adapter*Отправить тестовое уведомление через настроенный способ доставки. adapter — email, sms, call, slack, telegram, webhook, discord, teams, mattermost, pagerduty или opsgenie
ИнструментПараметрыОписание
list_clients—Список всех клиентов (устройств/токенов)
create_clientname*Создать устройство, получить его токен (C…)
update_clientid*, name*Переименовать клиента
delete_clientid*Удалить клиента (отозвать токен)

create_client, update_client и delete_client с API-токеном отвечают 403: управлять устройствами API-токен не может, нужен токен устройства (C…).

ИнструментПараметрыОписание
get_current_user—Информация о текущем пользователе
list_users—Список всех пользователей (admin)
get_userid*Получить пользователя по ID (admin). В текущей версии сервера маршрута GET /user/:id нет — вызов вернёт ошибку
create_username*, pass*, adminСоздать пользователя. Без прав администратора вызов считается обычной регистрацией: пройдёт, только если регистрация открыта, и без admin
delete_userid*Удалить пользователя (admin)
request_password_resetemail*Запросить сброс пароля — ссылка с токеном уйдёт на email (публичный, без авторизации)
confirm_password_resettoken*, new_password*Подтвердить сброс: задать новый пароль по токену из письма

Права администратора API-токен не получает никогда, даже если это токен администратора: list_users и delete_user с ним отвечают 403. Этим инструментам нужен токен устройства администратора (C…) в NOTIFLY_API_TOKEN и, кроме того, свежее sudo-подтверждение на этом устройстве (окно — 15 минут), иначе тоже 403.

Подробнее о heartbeat-ах — на странице Heartbeat.

ИнструментПараметрыОписание
list_heartbeats—Список heartbeat-уведомлений (dead-man-switch)
create_heartbeatappid*, name*, intervalSec*, alertMessage*, graceSec, alertTitle, alertPriority, recoveryTitle, recoveryMessageСоздать heartbeat. intervalSec ≥ 30; алёрт уходит, если ping не пришёл за intervalSec+graceSec секунд; alertPriority по умолчанию 8
update_heartbeatid*, name*, intervalSec*, alertMessage*, graceSec, alertTitle, alertPriority, recoveryTitle, recoveryMessageОбновить настройки heartbeat-а
delete_heartbeatid*Удалить heartbeat
pause_heartbeatid*Приостановить (алёрты не отправляются до resume_heartbeat)
resume_heartbeatid*Возобновить приостановленный heartbeat
ping_heartbeatping_token*Отправить ping по публичному ping-токену (как это делает приложение из cron)
test_heartbeat_alertid*Отправить alert-уведомление heartbeat-а прямо сейчас — проверить канал и доставку. Создаёт настоящее сообщение в канале
test_heartbeat_recoveryid*Отправить recovery-уведомление heartbeat-а прямо сейчас. Создаёт настоящее сообщение в канале

Подробнее об активных проверках — на странице Мониторы.

ИнструментПараметрыОписание
list_monitors—Список активных мониторов (HTTP, TCP и SSL)
create_monitorappid*, name*, kind*, target*, intervalSec*, alertMessage*, timeoutSec, expectedStatus, certMinDays, consecutiveFails, alertTitle, alertPriority, recoveryTitle, recoveryMessageСоздать монитор. kind = http (тогда target — URL), tcp (target — host:port) или ssl — срок и валидность TLS-сертификата (target — host или host:port, порт по умолчанию 443). intervalSec 30–86400; timeoutSec 1–60, по умолчанию 10; expectedStatus (только http) 0 = «любой 2xx»; certMinDays (только ssl) 1–365, по умолчанию 14 — алёрт, если до истечения сертификата осталось меньше; consecutiveFails по умолчанию 1 (макс. 20); alertPriority по умолчанию 8
update_monitorid*, name*, kind*, target*, intervalSec*, alertMessage*, timeoutSec, expectedStatus, certMinDays, consecutiveFails, alertTitle, alertPriority, recoveryTitle, recoveryMessageОбновить настройки монитора (поля — как у create_monitor)
delete_monitorid*Удалить монитор
pause_monitorid*Приостановить (проверки не выполняются до resume_monitor)
resume_monitorid*Возобновить приостановленный монитор
test_monitorkind*, target*, timeoutSec, expectedStatus, certMinDaysРазовая проверка цели без создания монитора — тот же зонд, что у активного монитора. Недоступная цель возвращает ok: false в теле, а не ошибку инструмента

Пять семейств устроены одинаково: list_*, create_*, update_*, delete_*, pause_*, resume_*. Обновление замещает настройки целиком (непереданные поля сбрасываются), а канал (appid) у существующего монитора сменить нельзя.

СемействоИнструментыДля чего
http_monitorlist_http_monitors, create_http_monitor, update_http_monitor, delete/pause/resume_http_monitorЗапрос с проверкой ответа по фильтрам: статус, подстрока, регулярное выражение, JSONPath, длительность. intervalSec 30–86400
port_monitorlist_port_monitors, create_port_monitor, update_port_monitor, delete/pause/resume_port_monitorСледит, что нужные TCP-порты открыты (alertMode: closed) или, наоборот, закрыты (open). intervalSec 60–86400
content_monitorlist_content_monitors, create_content_monitor, update_content_monitor, delete/pause/resume_content_monitorЗначение на странице: mode = hash, json, text, css или xpath; useBrowser рендерит JS. intervalSec 60–86400
workflow_monitorlist_workflow_monitors, create_workflow_monitor, update_workflow_monitor, delete/pause/resume_workflow_monitorЦепочка HTTP-запросов (логин, затем вызов) с подстановкой {{name}} из извлечённых значений. intervalSec 60–86400
browser_workflowlist_browser_workflows, create_browser_workflow, update_browser_workflow, delete/pause/resume_browser_workflowНастоящий браузер проходит по шагам страницы. intervalSec от 300 — минимум выше остальных; пауза отвечает без тела

Пробные прогоны без создания монитора: test_http_monitor, test_port_monitor, test_content_rule, test_workflow (у browser_workflow пробного прогона нет; для обычного монитора — test_monitor выше). Недоступная цель возвращает ok: false в теле, а не ошибку инструмента.

ИнструментПараметрыОписание
get_monitor_historykind*, id*, bucket, from, toСтатистика проверок по корзинам: сколько всего, сколько успешных, длительности. bucket = 1m, 1h (по умолчанию) или 1d; from/to — Unix-секунды
get_monitor_logkind*, id*, limitПоследние отдельные проверки с текстом ошибки каждой; до 200, хранятся 7 дней

kind пишется в snake_case и не совпадает с путями мониторов: monitor, heartbeat, http_monitor, content_monitor, port_monitor, workflow_monitor, browser_workflow_monitor.

ИнструментПараметрыОписание
list_port_scans—Список сканов
get_port_scanid*Скан вместе с прогрессом и найденными портами
create_port_scanappid*, name*, host*, profile, rangeFrom, rangeTo, timeoutSec, repeatIntervalSec, alertTitle, alertMessage, alertPriorityЗапустить скан. profile = quick, standard, full или custom; кроме custom профиль перезаписывает диапазон. Приватный хост разрешён. alertTitle/alertMessage/alertPriority — уведомление о результате (текст здесь необязателен)
update_port_scanid*, остальные — по желаниюНастоящий патч: меняются только переданные поля (те же, что у create_port_scan, кроме profile). Запущенный скан править нельзя; appid здесь сменить можно
delete_port_scanid*Удалить скан
cancel_port_scanid*Остановить скан в очереди или в работе
restart_port_scanid*Перезапустить завершённый скан
port_scan_to_monitorid*, name, intervalSec, timeoutSec, alertTitle, alertMessage, alertPriorityПревратить найденные открытые порты в монитор их закрытия
list_verified_hosts—Подтверждённые хосты (подтверждение живёт 365 дней)
start_host_verificationhost*, method*Начать подтверждение: dns или http. Приватный адрес подтверждается сразу, публичный возвращает token для публикации
check_host_verificationhost*, method*, token*Подтвердить опубликованный челлендж. Пока запись не видна — 422, имеет смысл повторить
delete_verified_hostid*Отозвать подтверждение
ИнструментПараметрыОписание
push_metricmetric_token*, name + value либо pointsЗаписать значения в источник метрик. points — JSON-массив до 500 точек с необязательным ts в Unix-миллисекундах. Ответ 204 приходит и на неизвестный токен

Подробнее — на странице Делегирование каналов.

ИнструментПараметрыОписание
list_channel_sharesapp_id*Список share-токенов (делегаций) канала; доступно владельцу или пользователю с правом send
create_channel_shareapp_id*, permission*, recipient_email, noteСоздать делегацию. permission = view (чтение) или send (чтение + отправка); пустой recipient_email — открытый токен
update_channel_shareid*, permission*, recipient_email, noteИзменить email получателя, уровень доступа или заметку (только владелец канала)
delete_channel_shareid*Отозвать share-токен (удалить делегацию)
list_incoming_shares—Каналы, к которым текущий пользователь получил доступ (входящие share-ы по email)
accept_shareid*Принять входящую делегацию (статус → active)
decline_shareid*Отклонить входящую делегацию
join_share_by_tokentoken*Присоединиться к каналу по share-токену (префикс S)
ИнструментПараметрыОписание
get_client_subscriptionsclient_id*Каналы, на которые подписано устройство по ID клиента
set_client_subscriptionsclient_id*, app_ids*Задать полный список подписок устройства; app_ids — массив ID, например [1,2,3] (заменяет текущие; пустой снимает все подписки)
get_my_subscriptions—Подписки текущего устройства
subscribe_to_channelapp_id*Подписать текущее устройство на канал
unsubscribe_from_channelchannel_id*Отписать текущее устройство от канала

get_my_subscriptions, subscribe_to_channel и unsubscribe_from_channel работают с текущим устройством: нужен токен устройства (C…) в NOTIFLY_API_TOKEN, у API-токена устройства нет, и сервер отвечает 401.

ИнструментПараметрыОписание
get_quota_breakdowndayДетальная разбивка использования квоты событий за день (YYYY-MM-DD, по умолчанию — сегодня по MSK)
topup_balanceamount_rubles*Пополнить баланс (целое ≥ 1; только admin, остальным возвращаются реквизиты для оплаты)

* — обязательный параметр


Отправь уведомление в Notifly с заголовком "Деплой завершён"
и текстом "Версия 2.1.0 успешно развёрнута на prod" с приоритетом 7.

Claude вызовет инструмент send_message автоматически.

Покажи список всех каналов в Notifly и последние 10 сообщений
из канала с ID 3.

Claude последовательно вызовет list_applications и list_application_messages.

Создай нового пользователя в Notifly с именем "devops"
и паролем "securepass", без прав администратора.

Claude вызовет create_user с нужными параметрами. Создать пользователя от имени администратора получится с токеном устройства администратора в NOTIFLY_API_TOKEN; без прав администратора сервер сочтёт вызов обычной регистрацией (см. Пользователи).


Автономный агент не должен сам решать, применять ли миграцию к prod, — он должен спросить. Пара инструментов ask_question → get_ask_answer превращает Notifly в готовый approval-гейт: вопрос прилетает push-уведомлением (и в Telegram, если подключён), человек отвечает кнопкой прямо из уведомления, агент получает ответ и действует.

Агент вызывает ask_question с вариантами-кнопками, таймаутом и безопасным ответом по умолчанию:

{
"tool": "ask_question",
"arguments": {
"question": "Применить миграцию к prod?",
"options": ["да", "нет"],
"timeout_sec": 300,
"default_answer": "нет",
"client_message_id": "deploy-2026-07-13-migration"
}
}

Ответ инструмента — id созданного вопроса:

{"id": 8260183728527568, "status": "pending"}
  • timeout_sec: 300 + default_answer: "нет" — если человек не ответил за 5 минут, вопрос закроется безопасным «нет»: молчание не равно согласию.
  • client_message_id — ключ идемпотентности: если агент повторит вызов (ретрай после обрыва), новый вопрос не создастся — вернётся существующий.

На телефон приходит push «Применить миграцию к prod?» с кнопками да / нет; тот же вопрос с кнопками — в Telegram, если он подключён к каналу. Одно касание — ответ записан, открывать приложение не нужно.

{
"tool": "get_ask_answer",
"arguments": {"id": 8260183728527568, "wait_sec": 300}
}

get_ask_answer с wait_sec > 0 блокируется до ответа и возвращает терминальный статус. Ответ приходит push-ом по WebSocket, поэтому инструмент возвращается в тот же момент, когда человек нажал кнопку; если сокет недоступен, вместо него идёт опрос раз в 3 секунды:

{"id": 8260183728527568, "status": "answered", "answer": "да"}

Псевдодиалог целиком:

Агент: собираюсь применить миграцию 0042 к prod. Спрашиваю разрешение.
→ ask_question("Применить миграцию к prod?", options=["да","нет"],
timeout_sec=300, default_answer="нет")
← {"id": 8260…, "status": "pending"}
→ get_ask_answer(id=8260…, wait_sec=300)
Человек: [push на телефоне] «Применить миграцию к prod?» [да] [нет]
— нажимает «да»
Агент: ← {"status": "answered", "answer": "да"}
применяю миграцию… готово, отправляю send_message("Миграция 0042 применена").

Если статус expired — сработал таймаут и засчитан default_answer («нет»); если cancelled — вопрос отменили. В обоих случаях агент не выполняет действие. Подробнее о механике вопросов — на странице Вопросы (Ask).

Безопасность: тег-скоуп и TTL для агентского токена

Заголовок раздела «Безопасность: тег-скоуп и TTL для агентского токена»

Агенту не нужен доступ ко всем каналам аккаунта. Ограничьте его API-токен:

  1. Повесьте на «агентские» каналы тег ai (поле «Теги» канала или create_application/update_application с tags: ["ai"]).
  2. Выпустите API-токен с тег-скоупом и сроком действия:
POST /api-token
{
"name": "deploy-agent",
"access": "write",
"appTags": ["ai"],
"expiresAt": "2026-08-01T00:00:00Z"
}

Такой токен видит только каналы с тегом ai — включая созданные позже (динамический скоуп, править токен не нужно), а после expiresAt перестаёт работать сам: забытый в конфиге агента токен не останется вечной дырой. Подробности про скоуп — на странице API-токены.


  • MCP-сервер работает локально через stdio — сетевой порт не открывается.
  • Токены хранятся только в переменных окружения процесса.
  • Инструменты delete_all_messages и delete_user выполняют необратимые операции — AI-ассистент должен запросить подтверждение перед их вызовом.