MCP Сервер
Notifly MCP Server — это реализация Model Context Protocol (MCP), позволяющая AI-ассистентам (Claude, GitHub Copilot и другим) управлять Notifly через набор готовых инструментов.
С помощью MCP-сервера AI-ассистент может:
- отправлять уведомления в каналы;
- читать, фильтровать и удалять сообщения;
- создавать и управлять каналами и клиентами;
- задавать вопросы человеку и ждать ответа (human-in-the-loop);
- администрировать пользователей сервера.
Быстрый старт: скопируй и работай
Заголовок раздела «Быстрый старт: скопируй и работай»Три шага — и ассистент отправляет уведомления:
- Соберите бинарь
notifly-mcp(см. Установка) и положите его, например, в/usr/local/bin/notifly-mcp. - Возьмите токены в админке: app-токен канала
(
A…, вкладка каналов) и MCP-код (M…, страница MCP). - Скопируйте конфиг своего клиента и подставьте свои значения вместо
AXXXXXXXXXXXXXX(app-токен) иMXXXXXXXXXXXXXXXXXXXXXX(MCP-код).NOTIFLY_URLдля облачного Notifly —https://api.notifly.ru; для self-hosted — адрес вашего сервера.
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": "AXXXXXXXXXXXXXX", "NOTIFLY_CLIENT_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX" } } }}Claude Code — одна команда в терминале:
claude mcp add notifly /usr/local/bin/notifly-mcp \ -e NOTIFLY_URL=https://api.notifly.ru \ -e NOTIFLY_APP_TOKEN=AXXXXXXXXXXXXXX \ -e NOTIFLY_CLIENT_TOKEN=MXXXXXXXXXXXXXXXXXXXXXXCursor — файл .cursor/mcp.json в корне проекта (или ~/.cursor/mcp.json глобально):
{ "mcpServers": { "notifly": { "command": "/usr/local/bin/notifly-mcp", "env": { "NOTIFLY_URL": "https://api.notifly.ru", "NOTIFLY_APP_TOKEN": "AXXXXXXXXXXXXXX", "NOTIFLY_CLIENT_TOKEN": "MXXXXXXXXXXXXXXXXXXXXXX" } } }}Перезапустите клиент (Cursor подхватит конфиг сам) — и попросите ассистента: «Отправь в Notifly уведомление „MCP подключён“». Другие клиенты (VS Code, Windsurf, Codex, Zed, Continue) — в разделах ниже.
Установка
Заголовок раздела «Установка»Требования
Заголовок раздела «Требования»- Go 1.21 или новее
Сборка из исходников
Заголовок раздела «Сборка из исходников»git clone https://github.com/notifly/mcp.gitcd mcpgo mod tidygo build -o notifly-mcp .Готовый бинарный файл notifly-mcp запускается через stdio-транспорт — MCP-клиент запускает его как дочерний процесс.
Конфигурация
Заголовок раздела «Конфигурация»Сервер настраивается исключительно через переменные окружения:
| Переменная | Обязательная | Описание |
|---|---|---|
NOTIFLY_URL | ✓ | Базовый URL сервера Notifly, например https://your-domain.com |
NOTIFLY_APP_TOKEN | App-токен (префикс A) — для инструмента send_message | |
NOTIFLY_CLIENT_TOKEN | MCP-код (префикс M) или client-токен (префикс C) — для управления ресурсами | |
NOTIFLY_USER | Логин для Basic Auth (альтернатива MCP-коду) | |
NOTIFLY_PASS | Пароль для Basic Auth |
Подключение к Claude Desktop
Заголовок раздела «Подключение к Claude Desktop»Откройте файл конфигурации 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://your-notifly-domain.com", "NOTIFLY_APP_TOKEN": "AGdjfk_L.dKe8q", "NOTIFLY_CLIENT_TOKEN": "CaQw5lL_L.yiRbN" } } }}После перезапуска Claude Desktop инструменты Notifly появятся в интерфейсе.
Подключение к VS Code (GitHub Copilot)
Заголовок раздела «Подключение к VS Code (GitHub Copilot)»Добавьте в .vscode/mcp.json в корне проекта или в пользовательские настройки VS Code:
{ "servers": { "notifly": { "type": "stdio", "command": "/usr/local/bin/notifly-mcp", "env": { "NOTIFLY_URL": "https://your-notifly-domain.com", "NOTIFLY_APP_TOKEN": "AGdjfk_L.dKe8q", "NOTIFLY_CLIENT_TOKEN": "CaQw5lL_L.yiRbN" } } }}Подключение к Cursor
Заголовок раздела «Подключение к Cursor»Добавьте файл .cursor/mcp.json в корень проекта (project-scope) или ~/.cursor/mcp.json глобально:
{ "mcpServers": { "notifly": { "command": "/usr/local/bin/notifly-mcp", "env": { "NOTIFLY_URL": "https://your-notifly-domain.com", "NOTIFLY_APP_TOKEN": "AGdjfk_L.dKe8q", "NOTIFLY_CLIENT_TOKEN": "CaQw5lL_L.yiRbN" } } }}После сохранения файла Cursor подхватит сервер автоматически. Убедитесь, что notifly-mcp доступен в PATH.
Подключение к Windsurf
Заголовок раздела «Подключение к Windsurf»Откройте или создайте файл ~/.codeium/windsurf/mcp_config.json и добавьте секцию mcpServers:
{ "mcpServers": { "notifly": { "command": "/usr/local/bin/notifly-mcp", "env": { "NOTIFLY_URL": "https://your-notifly-domain.com", "NOTIFLY_APP_TOKEN": "AGdjfk_L.dKe8q", "NOTIFLY_CLIENT_TOKEN": "CaQw5lL_L.yiRbN" } } }}После сохранения перезапустите Windsurf — инструменты Notifly появятся в Cascade.
Подключение к Claude Code (CLI)
Заголовок раздела «Подключение к Claude Code (CLI)»Используйте команду claude mcp add для регистрации сервера:
claude mcp add notifly /usr/local/bin/notifly-mcp \ -e NOTIFLY_URL=https://your-notifly-domain.com \ -e NOTIFLY_CLIENT_TOKEN=CaQw5lL_L.yiRbNФлаг --scope user добавляет сервер глобально для всех проектов (по умолчанию — project-scope). Проверить список добавленных серверов: claude mcp list.
Подключение к Codex CLI
Заголовок раздела «Подключение к Codex CLI»Откройте или создайте файл ~/.codex/config.toml и добавьте секцию:
[[mcp_servers]]name = "notifly"command = "/usr/local/bin/notifly-mcp"env = { NOTIFLY_URL = "https://your-notifly-domain.com", NOTIFLY_CLIENT_TOKEN = "CaQw5lL_L.yiRbN" }После сохранения Codex подхватит сервер при следующем запуске. Убедитесь, что notifly-mcp доступен в PATH.
Подключение к Zed
Заголовок раздела «Подключение к Zed»Откройте файл настроек Zed (~/.config/zed/settings.json) и добавьте секцию context_servers:
{ "context_servers": { "notifly": { "command": { "path": "/usr/local/bin/notifly-mcp", "args": [], "env": { "NOTIFLY_URL": "https://your-notifly-domain.com", "NOTIFLY_CLIENT_TOKEN": "CaQw5lL_L.yiRbN" } } } }}Zed подхватит сервер без перезапуска.
Подключение к Continue
Заголовок раздела «Подключение к Continue»Добавьте секцию mcpServers в файл конфигурации Continue (~/.continue/config.json):
{ "mcpServers": [ { "name": "notifly", "command": "/usr/local/bin/notifly-mcp", "env": { "NOTIFLY_URL": "https://your-notifly-domain.com", "NOTIFLY_CLIENT_TOKEN": "CaQw5lL_L.yiRbN" } } ]}Continue поддерживается как расширение для VS Code и JetBrains IDE.
Доступные инструменты
Заголовок раздела «Доступные инструменты»Информация о сервере
Заголовок раздела «Информация о сервере»| Инструмент | Описание |
|---|---|
get_health | Проверить работоспособность сервера и базы данных |
get_version | Получить версию, commit и дату сборки |
get_server_info | Получить флаги сервера (регистрация, OIDC) |
Сообщения
Заголовок раздела «Сообщения»| Инструмент | Параметры | Описание |
|---|---|---|
send_message | message*, title, priority | Отправить уведомление (требует NOTIFLY_APP_TOKEN) |
list_messages | limit, since | Список всех сообщений с пагинацией |
list_application_messages | app_id*, limit, since | Сообщения конкретного канала |
delete_message | id* | Удалить сообщение по ID |
delete_all_messages | — | Удалить все сообщения |
delete_application_messages | app_id* | Удалить все сообщения канала |
search_messages | q*, app_id, limit, since | Поиск сообщений по тексту (мин. 2 символа); по всем каналам или в одном |
mark_messages_read | ids* | Отметить сообщения прочитанными (JSON-массив ID, например [1,2,3]) |
Вопросы (ask) — human-in-the-loop
Заголовок раздела «Вопросы (ask) — human-in-the-loop»| Инструмент | Параметры | Описание |
|---|---|---|
ask_question | question*, options, title, timeout_sec, default_answer, allow_multi, json_format, client_message_id | Задать вопрос человеку (push/Telegram/email с кнопками); вернёт id вопроса. Требует NOTIFLY_APP_TOKEN. См. Вопросы (Ask) |
get_ask_answer | id*, wait_sec | Получить ответ; при wait_sec > 0 — дождаться (опрос раз в 3 с, до 300 с). Вернёт answered+ответ, pending, expired или cancelled. Требует NOTIFLY_APP_TOKEN |
cancel_ask_question | id* | Отменить ожидающий вопрос |
Пара ask_question → get_ask_answer(wait_sec) — готовый approval-гейт для
AI-агента: спросить разрешение у человека и продолжить по ответу.
| Инструмент | Параметры | Описание |
|---|---|---|
list_applications | — | Список всех каналов |
create_application | name*, description, default_priority, tags | Создать канал. tags — до 10 тегов из [a-z0-9_-]; используются тег-скоупом MCP-кодов |
update_application | id*, name, description, default_priority, tags | Обновить канал; tags заменяют текущие (не передан — не меняются) |
delete_application | id* | Удалить канал |
Клиенты
Заголовок раздела «Клиенты»| Инструмент | Параметры | Описание |
|---|---|---|
list_clients | — | Список всех клиентов (устройств/токенов) |
create_client | name* | Создать клиента, получить client-токен |
update_client | id, name | Переименовать клиента |
delete_client | id* | Удалить клиента (отозвать токен) |
Пользователи
Заголовок раздела «Пользователи»| Инструмент | Параметры | Описание |
|---|---|---|
get_current_user | — | Информация о текущем пользователе |
list_users | — | Список всех пользователей (требует admin) |
get_user | id* | Получить пользователя по ID (admin) |
create_user | name, pass, admin | Создать пользователя (admin) |
delete_user | id* | Удалить пользователя (admin) |
request_password_reset | email* | Запросить сброс пароля — ссылка с токеном уйдёт на email (публичный, без авторизации) |
confirm_password_reset | token, new_password | Подтвердить сброс: задать новый пароль по токену из письма |
Heartbeats (контрольные сигналы)
Заголовок раздела «Heartbeats (контрольные сигналы)»Подробнее о heartbeat-ах — на странице Heartbeat.
| Инструмент | Параметры | Описание |
|---|---|---|
list_heartbeats | — | Список heartbeat-уведомлений (dead-man-switch) |
create_heartbeat | appid, name, intervalSec, alertMessage, graceSec, alertTitle, alertPriority, recoveryTitle, recoveryMessage | Создать heartbeat. intervalSec ≥ 30; алёрт уходит, если ping не пришёл за intervalSec+graceSec секунд; alertPriority по умолчанию 8 |
update_heartbeat | id, name, intervalSec, alertMessage, graceSec, alertTitle, alertPriority, recoveryTitle, recoveryMessage | Обновить настройки heartbeat-а |
delete_heartbeat | id* | Удалить heartbeat |
pause_heartbeat | id* | Приостановить (алёрты не отправляются до resume_heartbeat) |
resume_heartbeat | id* | Возобновить приостановленный heartbeat |
ping_heartbeat | ping_token* | Отправить ping по публичному ping-токену (как это делает приложение из cron) |
Мониторы
Заголовок раздела «Мониторы»Подробнее об активных проверках — на странице Мониторы.
| Инструмент | Параметры | Описание |
|---|---|---|
list_monitors | — | Список активных мониторов (HTTP-URL и TCP-портов) |
create_monitor | appid, name, kind, target, intervalSec, alertMessage, timeoutSec, expectedStatus, consecutiveFails, alertTitle, alertPriority, recoveryTitle, recoveryMessage | Создать монитор. kind = http (тогда target — URL) или tcp (target — host:port). intervalSec 30–86400; timeoutSec по умолчанию 10; expectedStatus 0 = «любой 2xx»; consecutiveFails по умолчанию 1 (макс. 20); alertPriority по умолчанию 8 |
update_monitor | id, name, kind, target, intervalSec, alertMessage, timeoutSec, expectedStatus, consecutiveFails, alertTitle, alertPriority, recoveryTitle, recoveryMessage | Обновить настройки монитора |
delete_monitor | id* | Удалить монитор |
pause_monitor | id* | Приостановить (проверки не выполняются до resume_monitor) |
resume_monitor | id* | Возобновить приостановленный монитор |
Делегирование каналов (shares)
Заголовок раздела «Делегирование каналов (shares)»Подробнее — на странице Делегирование каналов.
| Инструмент | Параметры | Описание |
|---|---|---|
list_channel_shares | app_id* | Список share-токенов (делегаций) канала; доступно владельцу или пользователю с правом send |
create_channel_share | app_id, permission, recipient_email, note | Создать делегацию. permission = view (чтение) или send (чтение + отправка); пустой recipient_email — открытый токен |
update_channel_share | id, permission, recipient_email, note | Изменить email получателя, уровень доступа или заметку (только владелец канала) |
delete_channel_share | id* | Отозвать share-токен (удалить делегацию) |
list_incoming_shares | — | Каналы, к которым текущий пользователь получил доступ (входящие share-ы по email) |
accept_share | id* | Принять входящую делегацию (статус → active) |
decline_share | id* | Отклонить входящую делегацию |
join_share_by_token | token* | Присоединиться к каналу по share-токену (префикс S) |
Подписки устройств
Заголовок раздела «Подписки устройств»| Инструмент | Параметры | Описание |
|---|---|---|
get_client_subscriptions | client_id* | Каналы, на которые подписано устройство по ID клиента |
set_client_subscriptions | client_id, app_ids | Задать полный список подписок устройства; app_ids — JSON-массив ID, например [1,2,3] (заменяет текущие) |
get_my_subscriptions | — | Подписки текущего устройства (авторизация device-токеном через NOTIFLY_CLIENT_TOKEN) |
subscribe_to_channel | app_id* | Подписать текущее устройство на канал |
unsubscribe_from_channel | channel_id* | Отписать текущее устройство от канала |
Аккаунт и биллинг
Заголовок раздела «Аккаунт и биллинг»| Инструмент | Параметры | Описание |
|---|---|---|
get_quota_breakdown | day | Детальная разбивка использования квоты событий за день (YYYY-MM-DD, по умолчанию — сегодня по MSK) |
topup_balance | amount_rubles* | Пополнить баланс (целое ≥ 1; только admin, остальным возвращаются реквизиты для оплаты) |
* — обязательный параметр
Примеры использования
Заголовок раздела «Примеры использования»Отправить уведомление через Claude
Заголовок раздела «Отправить уведомление через Claude»Отправь уведомление в 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 с нужными параметрами.
Рецепт: approval-гейт для AI-агента (human-in-the-loop)
Заголовок раздела «Рецепт: approval-гейт для AI-агента (human-in-the-loop)»Автономный агент не должен сам решать, применять ли миграцию к prod, — он
должен спросить. Пара инструментов ask_question → get_ask_answer превращает
Notifly в готовый approval-гейт: вопрос прилетает push-уведомлением (и в
Telegram, если подключён), человек отвечает кнопкой прямо из уведомления,
агент получает ответ и действует.
Шаг 1. Агент задаёт вопрос
Заголовок раздела «Шаг 1. Агент задаёт вопрос»Агент вызывает 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— ключ идемпотентности: если агент повторит вызов (ретрай после обрыва), новый вопрос не создастся — вернётся существующий.
Шаг 2. Человек отвечает из уведомления
Заголовок раздела «Шаг 2. Человек отвечает из уведомления»На телефон приходит push «Применить миграцию к prod?» с кнопками да / нет; тот же вопрос с кнопками — в Telegram, если он подключён к каналу. Одно касание — ответ записан, открывать приложение не нужно.
Шаг 3. Агент ждёт ответ
Заголовок раздела «Шаг 3. Агент ждёт ответ»{ "tool": "get_ask_answer", "arguments": {"id": 8260183728527568, "wait_sec": 300}}get_ask_answer с wait_sec > 0 блокируется до ответа (опрос раз в 3 секунды)
и возвращает терминальный статус:
{"id": 8260183728527568, "status": "answered", "answer": "да"}Шаг 4. Агент действует по ответу
Заголовок раздела «Шаг 4. Агент действует по ответу»Псевдодиалог целиком:
Агент: собираюсь применить миграцию 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 для агентского MCP-кода
Заголовок раздела «Безопасность: тег-скоуп и TTL для агентского MCP-кода»Агенту не нужен доступ ко всем каналам аккаунта. Ограничьте его MCP-код:
- Повесьте на «агентские» каналы тег
ai(поле «Теги» канала илиcreate_application/update_applicationсtags: ["ai"]). - Создайте MCP-код с тег-скоупом и сроком действия:
POST /mcp/token{ "name": "deploy-agent", "access": "write", "appTags": ["ai"], "expiresAt": "2026-08-01T00:00:00Z"}Такой код видит только каналы с тегом ai — включая созданные позже
(динамический скоуп, править код не нужно), а после expiresAt перестаёт
работать сам: забытый в конфиге агента токен не останется вечной дырой.
Скоуп можно комбинировать со статическим списком каналов (appIds) — доступ
разрешён, если канал в списке или несёт подходящий тег; пустые appIds и
appTags означают «все каналы».
Безопасность
Заголовок раздела «Безопасность»- MCP-сервер работает локально через stdio — сетевой порт не открывается.
- Токены хранятся только в переменных окружения процесса.
- Инструменты
delete_all_messagesиdelete_userвыполняют необратимые операции — AI-ассистент должен запросить подтверждение перед их вызовом.