Около года назад мы представили экспериментальную разработку от Postmark Labs: MCP сервер, который позволяет ИИ-ассистенту отправлять электронную почту через Postmark. Он поставлялся ровно с одним полезным инструментом sendEmail и тремя вспомогательными (всего четыре). Вы передавали ему получателя, тему и текст, и сообщение отправлялось. Тогда мы говорили, что начали с единственного сервера Postmark, «потому что с чего-то нужно было начинать».
С тех пор многое изменилось. Проект перерос рамки Labs и стал официальным @activecampaign/postmark-mcp пакетом, и по ходу дела мы многое узнали о том, что на самом деле нужно для ответственного внедрения ИИ-ассистента перед продакшн-API электронной почты. Последний релиз, v2.1.1, содержит 24 инструмента в восьми категориях: отправка, шаблоны, поиск сообщений, диагностика доставки, возвраты (bounces), подавления (suppressions), статистика и вебхуки. Но дело на самом деле не в количестве инструментов. Главное — это то, чему нас научил год работы с этим решением: проектирование инструментов для ИИ-агентa — это отдельная дисциплина, отличная от простого обертывания API, и как только ваш сервер получает официальное имя, все, что стоит за этим именем, должно соответствовать его уровню.
От одной конечной точки к целому интерфейсу #
Изначальные четыре инструмента напрямую дублировали отдельные эндпоинты Postmark. С этого мы и начали путь к 24 инструментам наивным способом — по одному инструменту на эндпоинт механическим путем. Но примерно на десятом инструменте мы поняли, что пользователи, общающиеся с ИИ-ассистентом, не воспринимают свои потребности как вызовы API. Они подходят к ним с точки зрения человеческих задач. Это переосмысление определило все самое важное в релизе v2.0.
Проектирование под результаты, а не под эндпоинты #
Лучший пример такого сдвига вообще не соответствует какому-либо одному эндпоинту Postmark. Он называется diagnoseDelivery и существует для ответа на один вполне человеческий вопрос: действительно ли мое письмо дошло до этого человека, а если нет, то почему?
Раньше ответ на этот вопрос требовал пятиэтажного расследования через панель управления: поиск исходящих сообщений, получение деталей сообщения, чтение хронологии событий, проверка списка подавления, проверка журнала возвратов — а затем сбор воедино картины из пяти разрозненных ответов. Это вполне нормальный рабочий процесс для человека с открытой вкладкой браузера. Но это плохой подход для ИИ-агента, которому приходится оркестрировать его вызов за вызовом, каждый раз угадывая следующий шаг.
Поэтому diagnoseDelivery делает это за один вызов. Он запускает эти поисковые запросы параллельно, допускает сбой любого из них и возвращает синтезированный ответ:
Строка рекомендуемого действия — это главное. Инструмент не возвращает пять наборов данных, оставляя модели задачу самостоятельно понять их взаимосвязь, — он возвращает готовое заключение, причем это заключение меняется в зависимости от причины подавления получателя (жалоба на спам — это перманентно; жесткий возврат может подлежать реактивации; ручное подавление можно просто удалить). Именно к этому паттерну мы постоянно возвращались по всему интерфейсу: сводить многоэтажный человеческий рабочий процесс к одному результативно-ориентированному вызову, вместо того чтобы обнажать отдельные шаги и надеяться, что модель каждый раз правильно реконструирует процесс.
Быть узнаваемым намеренно #
Вот решение, которое кажется шагом назад, пока вы не узнаете причину: начиная с версии 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 стала полноценным мажорным релизом semver, поскольку она нарушала обратную совместимость — минимальная версия Node поднялась с 16 до 20. В v2.1.0 был добавлен автоматизированный набор из 52 тестов на трех уровнях — модульные тесты для логирования и маскирования, офлайн-валидация поведения вебхуков и аннотаций, а также сквозные проверки настройки переменных окружения — в дополнение к двум тестовым окружениям для дымового тестирования, которые уже проверяли каждый инструмент только для чтения и прогоняли полный жизненный цикл создания-редактирования-удаления, включая реальные отправки с последующей самоочисткой, против реальной учетной записи перед любым релизом. Версия v2.1.1 добавила проверку перед публикацией (prepublishOnly), благодаря которой сломанная сборка буквально физически не может попасть в npm. Мелкие, негламурная детали, но именно они превращают «проект» в «пакет с владельцем».
Год осмысления #
Версия с четырьмя инструментами отвечала на вопрос «можешь ли ты это сделать?». Версия с 24 инструментами, вышедшая три релизом позже, отвечает на более правильный вопрос: «ким это должно быть на самом деле?». Самое большое изменение заключается вовсе не в количестве инструментов — а в том, что мы перестали думать об обертке эндпоинтов и начали задумываться о том, как агент взаимодействует с инструментом: какие вопросы он задает, к каким ошибкам склонен, какие решения он хочет получать в готовом виде, а не выстраивать самостоятельно.
Если вы хотите заглянуть под капот, проект доступен на GitHub и публикуется в npm как .
Мы будем рады услышать, как вы его используете и какими, по вашему мнению, должны быть следующие 24 инструмента. Напишите нам через нашу форму обратной связи или найдите нас в @postmarkapp.









