Около года назад мы представили экспериментальную разработку от Postmark Labs: MCP-сервер, позволяющий ИИ-ассистенту отправлять электронную почту через Postmark. Он поставлялся с одним полезным инструментом, sendEmail, и тремя вспомогательными (всего четыре). Вы передавали ему получателя, тему и текст сообщения, и оно отправлялось. Тогда мы говорили, что начали с одного сервера Postmark, «потому что с чего-то нужно было начинать».
С тех пор многое изменилось. Проект вышел из стадии Labs и стал официальным пакетом @activecampaign/postmark-mcp. За это время мы многое узнали о том, что на самом деле нужно для ответственного внедрения ИИ-ассистента в рабочий API электронной почты. Последний релиз, v2.1.1, включает 24 инструмента в восьми категориях: отправка, шаблоны, поиск сообщений, диагностика доставки, возвраты (bounces), подавления (suppressions), статистика и вебхуки. Но дело не только в количестве инструментов. Главное — чему нас научил год работы над этим проектом: проектирование инструментов для ИИ-агента — это дисциплина, отличная от простого оборачивания API, и как только ваш сервер получает официальное имя, всё, что стоит за этим именем, должно соответствовать ему.
От одной конечной точки до полноценного интерфейса #
Первоначальные четыре инструмента напрямую дублировали отдельные конечные точки Postmark. Мы начали с того, что довели их количество до 24 наивным способом — по одному инструменту на каждую конечную точку. Но примерно на десятом инструменте мы поняли, что пользователи, взаимодействующие с ИИ-ассистентом, не мыслят категориями API-запросов. Они подходят к этому с человеческими вопросами. Это переосмысление определило всё, что было важно в релизе v2.0.
Проектирование для результатов, а не для конечных точек #
Лучший пример этого сдвига вообще не привязан к одной конечной точке Postmark. Он называется diagnoseDelivery и существует для ответа на один очень человеческий вопрос: дошло ли мое письмо до этого человека, и если нет, то почему?
Раньше ответ на этот вопрос требовал пятиэтапного расследования через панель управления: поиск исходящих сообщений, получение деталей сообщения, чтение хронологии событий, проверка списка подавления, проверка журнала возвратов — а затем сбор истории из пяти отдельных ответов. Это разумный рабочий процесс для человека с открытой вкладкой браузера. Но это плохой подход для ИИ-агента, которому приходится выполнять вызовы по очереди, каждый раз угадывая следующий шаг.
Поэтому diagnoseDelivery делает всё за один вызов. Он параллельно выполняет эти поисковые запросы, игнорирует возможные ошибки в отдельных из них и возвращает синтезированный ответ:
Строка «Рекомендуемое действие» (Recommended action) — это суть. Инструмент не возвращает пять наборов данных, оставляя модели задачу понять, как они связаны — он возвращает готовое суждение, которое меняется в зависимости от причины подавления получателя (жалоба на спам — это навсегда; жесткий отказ (hard bounce) может быть исправим; ручное подавление можно просто удалить). Это паттерн, к которому мы постоянно возвращались во всей системе: объединить многошаговый человеческий рабочий процесс в один вызов, ориентированный на результат, вместо того чтобы предоставлять шаги и надеяться, что модель каждый раз правильно восстановит процесс.
Быть идентифицируемым, намеренно #
Вот решение, которое кажется странным, пока не поймешь причину: начиная с v2.0.0, ни один из 24 инструментов больше не использует официальный Node SDK от Postmark. Каждый из них работает через небольшой HTTP-клиент, построенный на нативном fetch.
Этому способствовали три причины, в порядке их важности:
- Идентификация. Мы хотели, чтобы трафик, идущий через MCP, был однозначно связан с этим сервером в логах Postmark, а не смешивался с анонимными вызовами SDK, неотличимыми от любой другой интеграции. В v2.1.0 мы пошли дальше: сервер теперь захватывает имя и версию подключающегося MCP-клиента во время рукопожатия и сохраняет эту идентификацию в каждом исходящем запросе и строке лога, наряду с опциональной меткой (AGENT_LABEL), предоставляемой оператором для команд, запускающих несколько экземпляров и желающих различать их в своем трафике.
- Контроль. Один надежный клиент означает одно место, отвечающее за заголовки авторизации, тайм-ауты запросов и согласованное сопоставление ошибок, поэтому код ошибки Postmark (ErrorCode) отображается одинаково, независимо от того, какой из 24 инструментов его вызвал.
- Меньше движущихся частей. Отказ от SDK и дополнительной HTTP-зависимости оставил в среде выполнения всего три зависимости: сам MCP SDK, dotenv и zod, все зафиксированы на точных версиях, чтобы цепочка поставок оставалась узкой и проверяемой.
Компромисс реален — мы отказались от удобства SDK и теперь сами отслеживаем структуру API Postmark. Для сервера, чья единственная задача — быть чистым и наблюдаемым мостом между ИИ-агентом и провайдером электронной почты, этот компромисс того стоил.
Пусть неправильное использование будет очевидным, а риски — видимыми #
ИИ-агенты совершают специфическую ошибку: они уверенно вызывают инструмент, не имея достаточно информации. Поэтому мутирующие инструменты проводят валидацию перед обращением к API. createWebhook не запустится без хотя бы одного включенного триггера, а начиная с v2.1.0 — не примет URL без HTTPS; опциональный список разрешенных доменов позволяет командам ограничить его использование только своими доменами (см. наше руководство по настройке вебхуков). editTemplate требует, чтобы хотя бы одно поле действительно изменилось. sendEmailWithTemplate отклоняет вызов, в котором указаны и templateId, и templateAlias вместо одного из них.
В этом нет ничего хитрого. Это разница между инструментом, который выдает ошибку с пояснением, понятным модели, и тем, который молча ничего не делает или тратит API-вызов впустую. Когда ваш вызывающий объект — вероятностная система, быстрая реакция на ошибку (fail-fast) — это не приятное дополнение, а часть контракта интерфейса.
В v2.1.0 этот же принцип был распространен на клиентскую сторону интерфейса: все 24 инструмента теперь снабжены аннотациями readOnlyHint, destructiveHint и idempotentHint, поэтому любой MCP-клиент может показать индикатор риска или заблокировать деструктивный вызов перед его выполнением — удаление, создание вебхука, реальная отправка — без необходимости угадывать по названию инструмента, что он собирается сделать. А логи теперь по умолчанию очищены от персональных данных (PII): адреса электронной почты маскируются до первого и последнего символа перед записью, с возможностью использования переменной LOG_EMAIL_FULL для команд, которым явно нужны полные адреса в своих логах.
Первый мажорный релиз #
Самое негламурное изменение, и, возможно, самое важное: мы начали относиться к этому как к программному обеспечению, от которого зависят другие люди.
v2.0.0 была полноценным мажорным релизом по семантическому версионированию, потому что он был ломающим — минимальная версия Node поднялась с 16 до 20. v2.1.0 добавила набор из 52 автоматизированных тестов на трех уровнях — модульные тесты для логирования и маскирования, автономная проверка поведения вебхуков и аннотаций, а также сквозные проверки конфигурации переменных окружения. Это в дополнение к двум наборам дымовых тестов, которые уже проверяли каждый инструмент только для чтения и запускали полные циклы создания-редактирования-удаления, включая реальные отправки, которые очищают за собой данные, против реальной учетной записи перед любым релизом. v2.1.1 добавила проверку prepublishOnly, чтобы сломанная сборка буквально не могла попасть в npm. Маленькие, негламурные вещи — именно то, что превращает «проект» в «пакет с владельцем».
Взгляд спустя год #
Версия с четырьмя инструментами отвечала на вопрос «можешь ли ты это сделать?». Версия с 24 инструментами, вышедшая три релиза спустя, отвечает на более правильный вопрос: «каким это должно быть на самом деле?». Самое главное изменение заключается вовсе не в количестве инструментов — а в том, что мы перестали думать об обертке для эндпоинтов и начали думать о том, как агент взаимодействует с инструментом: какие вопросы он задает, к каким ошибкам склонен, какие решения он хочет получать готовыми, а не собирать их самостоятельно.
Если вы хотите заглянуть под капот, проект доступен на GitHub и публикуется в npm под именем @activecampaign/postmark-mcp.
Мы будем рады услышать, как вы его используете и какими, по вашему мнению, должны быть следующие 24 инструмента. Напишите нам через форму обратной связи или найдите нас в Твиттере по адресу @postmarkapp.









