mailwarden
mailwarden
Надёжный, нативный сервер Gmail MCP — полная триаж почтового ящика для ИИ-ассистентов, с функцией, которой нет ни у одного другого MCP-сервера для Gmail: отложенная отправка на уровне почтового ящика.
Основные возможности
Отложенная отправка — единственная на уровне почтового ящика в MCP-сервере для Gmail. Архивируйте цепочку сейчас, а она снова появится во входящих в указанную дату. Основана на датированных метках + очистке, поэтому работает из любого клиента, видна в самом Gmail и переживает перезапуски. (Там, где другой сервер предлагает «отложенную отправку», это локальный список напоминаний — письмо никогда не покидает входящие и не возвращается в них.)
Поиск, которому можно доверять.
threads.listGmail — вызов, через который проходит любой поиск по цепочкам — может отвечать наis:unreadна основе устаревшего состояния прочтения на уровне цепочки: в одном реальном почтовом ящике 86% возвращённых цепочек не содержали ни одного непрочитанного сообщения; во втором почтовом ящике отклонений не было вовсе. Вы не можете определить, в каком почтовом ящике находитесь, не заглянув внутрь, поэтомуsearchповторно проверяет каждый результат на соответствие его актуальным меткам. Пагинация черезpageToken/nextPageToken.Массовые операции, которые масштабируются.
bulk_modifyархивирует/маркирует всё, соответствующее запросу, со скоростью 1000 сообщений на один API-запрос — с отчётом о частичном успехе для каждого блока вместо принципа «всё или ничего». Очистка отложенной отправки использует тот же пакетный путь.Структурированные выходные данные. Каждый инструмент объявляет
outputSchemaи возвращает проверенныеstructuredContentвместе с экранированным JSON-текстом — никаких догадок при разборе для клиентов.Небольшая поверхность для атак. Нет инструментов отправки (нет пути эксфильтрации для писем, внедрённых через промпт), опциональный режим «только чтение», нет телеметрии, нет открытых портов по умолчанию, защита загрузок от символических ссылок, экранированный вывод. Одно осознанное исключение:
unsubscribe/bulk_unsubscribe(тариф manage) обращаются к конечной точке отказа от подписки, указанной в заголовке самого сообщения — единственный хост, не принадлежащий Google, которого когда-либо достигает mailwarden, а развёртывание уровняreadвообще не выполняет исходящих запросов. Подробности в разделах Безопасность и конфиденциальность и Отписка.Корректная работа с реальной почтой. Заголовки RFC 2047 декодируются (
=?UTF-8?B?…?=→ читаемый текст), тела декодируются в их заявленной кодировке (без кракозябр для писем в ISO-8859-1/Shift_JIS), 429/5xx повторяются с экспоненциальной задержкой.
Related MCP server: Gmail MCP
Зачем
Коннекторы, которые синхронизируют или кешируют ваш почтовый ящик, могут отставать от него — и даже собственный поисковый индекс Gmail иногда неточен (см. ниже). mailwarden общается напрямую с живым Gmail API (без кешированного снимка) и перепроверяет то, что возвращает индекс, так что вы видите именно то, что есть на самом деле. Это универсальный слой возможностей Gmail — храните свои собственные правила/логику в вашем ИИ-клиенте, а не на сервере.
search идёт на шаг дальше, чем сырой API: индекс threads.list Gmail может отвечать на операторы состояния прочтения на основе устаревшей копии этого состояния, поэтому is:unread возвращает цепочки, которые вы дочитали недели назад — в одном измеренном почтовом ящике подавляющее большинство того, что было возвращено. Поскольку каждый результат всё равно извлекается в реальном времени, search перепроверяет однозначные предикаты (is:unread/is:read/is:starred/in:inbox/category:…, с отрицанием) по реальным меткам каждой цепочки и отбрасывает ложные срабатывания индекса.
По сравнению с другими MCP-серверами Gmail
Большинство MCP-серверов Gmail покрывают одну и ту же поверхность чтения/маркировки/отправки. Две возможности всё ещё уникальны для mailwarden (отложенная отправка на уровне почтового ящика, перепроверка поиска), а одно осознанное упущение является функцией безопасности, а не пробелом. Собственный сервер Google также уже, чем кажется: только черновики, и нет корзины, фильтров или отписки.
Возможность | mailwarden | ||||
Отложенная отправка на уровне почтового ящика — архивировать сейчас, вернуть во входящие в дату/время или по预设 | ✅ | — | — | — | — |
Перепроверка результатов поиска — отбрасывает ложные срабатывания индекса цепочек по реальным меткам | ✅ | — | — | — | — |
Очистка / массовая операция по запросу — одно действие для каждой цепочки, возвращённой поиском | ✅ 1000/запрос, частичный успех | — | ⚠️ пакетная по явным id | — | ⚠️ пакетная по явным id |
Отписка — обзор по отправителям + одношаговая отписка RFC 8058, без необходимости в области отправки | ✅ | — | ⚠️ показан заголовок, без действия | — | — |
Обзор триажа входящих — один вызов, который группирует то, что ожидает | ✅ отправитель/метка/возраст + сигналы заголовков | — | — | ✅ флаги эвристик + статистика | — |
Серверные фильтры — правила, которые продолжают триаж без ассистента в цикле | ✅ без пересылки | — | ✅ | — | ✅ |
Нет инструментов отправки — по замыслу — внедрённое через промпт письмо не имеет пути эксфильтрации | ✅ нет составления вообще | ⚠️ только черновики | ❌ отправляет | ❌ отправляет | ❌ отправляет |
Уровни инструментов с минимальными привилегиями — области OAuth, выводимые из включённых вами инструментов | ✅ | ⚠️ разделение областей | — | — | ⚠️ обратное: инструменты, ограниченные предоставленными областями |
Шифрование токенов в покое (опционально) | ✅ AES-256-GCM | н/д (хостинг) | ✅ | — | — |
Нет облака вендора — вы управляете сервером | ✅ | ❌ хостинг Google | ✅ | ✅ | ✅ |
Структурированные выходные данные — каждый инструмент объявляет | ✅ | — | — | — | — |
Снимок на 16 августа 2026 года из публичной документации и исходных кодов каждого проекта; — = не предлагается / не документировано. Столбцы — это серверы, к которым читатель, скорее всего, обратится: собственный сервер Google, два крупнейших сервера сообщества и klodr, который ближе всего подходит к собственному дизайну с минимальными привилегиями mailwarden. Возможность отправки указана как свойство безопасности: её отсутствие в mailwarden является намеренным (см. Безопасность и конфиденциальность). Последняя строка спрашивает, кто управляет сервером, а не где он работает: самостоятельный хостинг здесь является общей основой, и каждый сервер сообщества в этой таблице предлагает какое-либо удалённое развёртывание, кроме klodr (только stdio) — mailwarden через --http, taylorwilsdon через потоковый HTTP с OAuth 2.1, a-bonus на Cloud Run. Запуск одного из них на вашем собственном хосте — это не облачная копия; запуск на хосте вендора — это она.
Ров не в какой-либо отдельной строке — это отложенная отправка + проверка в реальном времени вместе: фактический слой рабочего процесса с входящими, который действует на текущее состояние почтового ящика, а не на кешированный снимок. Там, где другие догнали, это честно отмечено выше: шифрование в покое (taylorwilsdon), ограничение инструментов по областям (klodr), более богатая эвристика триажа для каждого сообщения (a-bonus) и массовая организация в почтовом ящике (хостинг mcpemails.com, у которого тоже нет отложенной отправки). Никто из них не действует на основе запроса и не проверяет ответ почтового ящика перед тем, как действовать на его основе.
Почему перепроверка важна — конкретный пример
Попросите ассистента «архивировать непрочитанные рекламные письма, которые уже обошли мои входящие», и он потянется к очевидному запросу category:updates is:unread -in:inbox. Сервер, который доверяет индексу Gmail, теперь архивирует цепочки, которые вы уже прочитали — письма, к которым вы не собирались прикасаться, исчезнувшие в результате массового действия, которое вы не можете легко отменить.
Измерено, а не утверждено. Один реальный почтовый ящик (~70 000 сообщений), 15.08.2026, только чтение:
Запрос ( | Возвращено нитей | С непрочитанным сообщением | Устаревшие |
| 131 | 17 | 87% |
| 128 | 14 | 89% |
| 235 | 99 | 58% |
Индекс не игнорирует предикат — тот же запрос без is:unread возвращает более 800 нитей, значит, он применяется. Он применяется к состоянию прочитанности на уровне нити, которое не успело обновиться: нити, в которых каждое сообщение прочитано, всё ещё считаются непрочитанными. Одна возвращённая нить имела единственную метку SENT. И это не особенность экзотических комбинаций операторов: самый простой из трёх запросов тоже это показывает — с наименьшей долей (58%), но с наибольшим абсолютным числом ошибочных нитей (136).
Это именно индекс нитей. Тот же запрос, тот же почтовый ящик, та же минута, выполненный через messages.list: 19 сообщений, ни одного устаревшего. Так что это не «поиск Gmail ненадёжен» — это представление состояния прочитанности на уровне нитей отстаёт, в то время как представление на уровне сообщений — нет. search проходит через threads.list, именно поэтому он выполняет повторную проверку.
Второй почтовый ящик, измеренный тем же способом в тот же день, не дрейфовал вообще — нулевое количество попаданий в сыром индексе для is:unread, хотя он много раз в день помечается как прочитанный через API. Так что это свойство конкретного почтового ящика, а не Gmail повсеместно. Что их различает, остаётся открытым: они различаются по объёму (примерно на три порядка) и возрасту, и во втором отсутствует нечто более фундаментальное — ни одна нить в нём никогда не была архивирована, оставаясь непрочитанной, а это единственная форма, в которой может проявиться устаревшее состояние прочитанности. Так что это не контрпример к какой-либо конкретной причине; это почтовый ящик без кандидата.
В этом и суть: сервер не может знать, с каким типом почтового ящика он имеет дело. Повторная проверка ничего не стоит там, где ничего не дрейфует, и спасает там, где дрейфует — в приведённых измерениях каждая нить, отброшенная search, была действительно прочитана, и он не отбросил ни одного действительно непрочитанного письма.
Где это не бесплатно: массовые инструменты. search выполняет повторную проверку, потому что всё равно загружает каждое совпадение; bulk_modify (и проход create_filter's applyToExisting) рассчитан на тысячи сообщений, где одна загрузка на каждое совпадение — это другой порядок затрат. Они действуют на основе того, что возвращает индекс, — поэтому теперь они сообщают unverifiedPredicates, условия из вашего запроса, которые были приняты на слово индексу (+UNREAD, -INBOX, …). Пустое значение означает, что нечему было не доверять. Непустое, а результат должен быть точным по состоянию прочитанности? Сначала разрешите набор с помощью search и действуйте на основе этих идентификаторов нитей. dryRun не устраняет этот разрыв: он перечитывает тот же индекс, так что подтверждает размер набора, но никогда — его правильность.
mailwarden всё равно загружает каждое совпадение в реальном времени, поэтому search перепроверяет однозначные предикаты (is:unread, is:read, in:inbox, category:…, с отрицанием) по истинным меткам каждой нити и отбрасывает ложные срабатывания индекса до того, как их увидит какой-либо инструмент. Затем массовое действие выполняется именно над тем набором, который вы запросили. В этом разница между действием на основе того, что Gmail проиндексировал, и действием на основе того, что действительно находится в почтовом ящике прямо сейчас — и именно поэтому откладывание/очистку можно безопасно доверить ассистенту: очистка извлекает только те нити, чьё откладывание действительно истекло, проверенное по живым меткам во время выполнения.
Убедитесь сами — учётная запись Gmail не нужна. Из клона репозитория (демонстрация — это скрипт проверки, находящийся только в репозитории, не часть npm-пакета):
git clone https://github.com/csitte/mailwarden && cd mailwarden
npm install && npm run build
node scripts/demo-reverify.mjsРядом с ним есть второй скрипт, node scripts/probe-reverify.mjs, который измеряет то же самое в вашем почтовом ящике вместо фиктивного — только чтение, только метаданные (тема, отправитель и тело не загружаются), выводя количество и названия меток. Именно так были получены числа выше, и так вы можете проверить, дрейфует ли ваш почтовый ящик вообще.
Демонстрация запускает реальный search() против фиктивного Gmail API, чей индекс намеренно устарел (возвращает прочитанную нить для запроса is:unread, в точности как Gmail) и показывает, как mailwarden отбрасывает ложное срабатывание. Она проверяет результат, поэтому завершается с ненулевым кодом, если поведение когда-либо регрессирует. Тот же случай закреплён модульными тестами в test/gmail.test.ts ("drops index false positives via live-label re-verify").
Инструменты
Инструмент | Что делает |
| Синтаксис запросов Gmail → сводки по темам (от/тема/дата/метки/фрагмент); предикаты состояния чтения/категории повторно сверяются с живыми метками каждого результата; постраничная навигация через |
| Полная цепочка: заголовки, тела в plaintext + HTML, метаданные вложений |
| Все метки (системные и пользовательские) |
| Адрес подключенного аккаунта + общее количество сообщений/цепочек — подтвердите, какой почтовый ящик подключен, прежде чем действовать |
| Структурированный обзор среза почтового ящика для принятия решений: топ-отправители (каждый с сигналами, которые несут его цепочки), категории по меткам и возрасту, количество непрочитанных и вложений, а также сколько цепочек являются рассылками / автоматическими / приглашениями в календарь / несовпадениями reply-to — вместо сырого списка цепочек |
| Какие возможности отказа от подписки рекламирует цепочка ( |
| Срез почтового ящика, сгруппированный по отправителю: количество цепочек/непрочитанных, временной промежуток, в течение которого каждый наблюдался, и возможности отказа от подписки каждого — один запрос заголовка на отправителя, ни с кем не связывается. |
| Создать пользовательскую метку (идемпотентно; вложенность через |
| Добавить/удалить метки по имени или id — неизвестное имя в |
| Пакетное изменение меток для каждого сообщения, соответствующего запросу — 1000 сообщений на один API-запрос, частичный успех сообщается по частям (список thread-id ограничен 500, |
| Удобные обёртки |
| Переместить в корзину / восстановить из корзины |
| Сохранить вложение в локальный путь (никогда не перезаписывает — при коллизиях добавляется числовой суффикс) |
| Отказ от подписки в один клик (RFC 8058) с использованием конечной точки из собственного заголовка сообщения — единственный инструмент, который связывается с не-Google хостом (подробнее) |
| То же самое для нескольких цепочек, последовательно и не более одного запроса на отправителя; частичный успех сообщается по цепочке. |
| Архивировать сейчас, всплыть в/после даты ( |
| Отменить отсрочку, вернуть во входящие сейчас |
| Все отложенные цепочки + даты выполнения |
| Поднять цепочки, срок отсрочки которых истёк (запуск по требованию, через cron или демон); пакетно, с отчётом о частичных сбоях. |
| Все фильтры Gmail (критерии + действия с метками); отображает любые адреса |
| Создать серверное правило автосортировки (только критерии → действия с метками; без пересылки — см. ниже). Опционально |
| Удалить фильтр по id |
Все инструменты объявляют outputSchema и возвращают структурированный контент (проверенный, машиночитаемый) вместе с тем же JSON в виде текста в кавычках — клиентам никогда не приходится разбирать прозу.
Как работает snooze (API Gmail snooze не существует — мы его создаем)
snooze удаляет INBOX и применяет датированную метку MCP/Snoozed/<key>, где ключ — это либо YYYY-MM-DD (на весь день), либо YYYY-MM-DDTHHMM (до указанной локальной минуты). Аргумент until принимает явную дату, дату+время (2026-06-20 9am, …T17:00) или предустановку, разрешаемую на сервере — today, tomorrow, weekend (следующая суббота), next week (следующий понедельник), название дня недели (monday–sunday, следующее вхождение), in N days или in N hours — и предустановка даты может содержать завершающее время (tomorrow 9am, monday 8:30), так что вызывающему никогда не приходится вычислять момент самостоятельно. sweep_snoozed находит просроченные метки и возвращает эти цепочки в папку «Входящие» (помечая как непрочитанные); отложенное пробуждение срабатывает при первом сканировании в/после указанной минуты, поэтому задержка пробуждения равна вашему интервалу сканирования. Запустите сканирование:
по требованию (инструмент
sweep_snoozed),через cron:
mailwarden --sweep,или автоматически: установите
MAILWARDEN_AUTO_SWEEP=1(ежечасное сканирование, пока сервер работает).
Фильтры (постоянные правила автоматической сортировки)
create_filter настраивает правило на стороне сервера Gmail: почта, соответствующая критериям, автоматически получает указанные действия с метками — почтовый ящик продолжает сортироваться сам без участия ассистента.
Критерии:
from,to,subject,query(полный синтаксис поиска Gmail),negatedQuery,hasAttachment,excludeChatsиsize+sizeComparison(smaller/larger, указываются вместе). Требуется хотя бы один.Действия (только метки):
addLabels/removeLabels, по имени или идентификатору (неизвестное имя вaddLabelsсоздается автоматически, вложенное через/). Типичные рецепты: пропустить папку «Входящие» →removeLabels: ["INBOX"]; автоматически пометить как прочитанное →removeLabels: ["UNREAD"]; автоматически переместить в корзину →addLabels: ["TRASH"]; пометить звездочкой →addLabels: ["STARRED"]; никогда не в спам →removeLabels: ["SPAM"]; поместить под метку →addLabels: ["Receipts"].Существующая почта: фильтр применяется только к сообщениям, поступившим после его создания. Передайте
applyToExisting: true, чтобы также однократно применить те же действия к почте, уже находящейся в ящике — mailwarden строит поисковый запрос Gmail из критериев и выполняет массовое изменение (доmaxMessages, по умолчанию 1000; те же оговорки о непроверенном индексе, что и дляbulk_modify, и однократный проход исключает Спам/Корзину). Это требует хотя бы одного положительного критерия (from/to/subject/query/hasAttachment:true/size): правило, основанное только на исключениях (negatedQueryилиhasAttachment:false), отклоняется дляapplyToExisting, поскольку оно соответствовало бы почти всему почтовому ящику — создавайте такой фильтр без этого флага. Результат возвращается вapplied(использованныйquery, счетчикиmatchedMessages/modifiedMessages/modifiedThreadCount,capped, когда набор совпадений достигmaxMessages,failedпо частям и строкаerror, если весь проход завершился неудачей); он равенnull, когдаapplyToExistingне был установлен. Фильтр создается первым, поэтому частичный или неудачный проход по накопившимся сообщениям сообщается вapplied, но никогда не вызывает ошибку — правило все равно действует.Без пересылки — см. Безопасность и конфиденциальность.
Требует область
gmail.settings.basic; повторно запустите--authодин раз, если вы авторизовали более старую версию. Недоступно в режиме только для чтения.
Отписка — единственный исходящий запрос
list_unsubscribe (уровень чтения) сообщает, что предлагает отправитель, не связываясь ни с кем. Он читает самое новое сообщение, которое действительно содержит заголовок List-Unsubscribe — ответ, привязанный к рассылке, находится в конце и ничего не рекламирует, что иначе было бы прочитано как «у этого списка нет возможности отказаться от подписки». list_subscriptions (уровень чтения) делает то же самое для целого среза, сгруппированного по отправителю, так что вы можете увидеть, кто продолжает писать и от кого из них можно на самом деле отказаться — один запрос заголовка на отправителя, а не на цепочку. unsubscribe и bulk_unsubscribe (уровень управления) действуют на основе этого — и это единственное место, где mailwarden когда-либо общается с хостом, не являющимся Google, поэтому правила строги:
Параметра URL нет. Конечная точка берется из собственного заголовка сообщения и ниоткуда больше. Аргумент URL позволил бы почте с внедренной подсказкой превратить инструмент в канал утечки (содержимое почтового ящика в строке запроса); заголовок не может нести данные, выбранные моделью.
Выполняется только одно нажатие RFC 8058 — отправитель должен был согласиться через
List-Unsubscribe-Post. Обычная ссылкаhttps:предназначена для человека в браузере и возвращается обратно, а не загружается.Отказ от подписки через
mailto:никогда не выполняется. Для этого потребовалось бы отправить письмо, чего mailwarden делать не умеет. Адрес сообщается, чтобы вы могли действовать самостоятельно.Фиксированный запрос, отброшенный ответ. Тело POST всегда равно
List-Unsubscribe=One-Clickи никогда не выводится ни из чего; тело ответа отменяется как непрочитанное. Модели возвращается код состояния и фактически вызванный URL — никакого содержимого от конечной точки, поэтому она не может ответить инструкциями. (Перенаправление 301/302/303 выполняется как GET, т.е. вообще без тела.)Один запрос на отправителя, последовательно, в рамках одного бюджета.
bulk_unsubscribeпринимает идентификаторы цепочек (никогда не запрос — запросный массовый запуск отправил бы запрос каждому соответствующему отправителю, прежде чем кто-либо посмотрел). Цепочки от отправителя, чей запрос уже был отправлен, сообщаются сduplicateOfи не требуют второго запроса: две цепочки из одного списка используют один отказ от подписки, и повторный вызов только дважды подтверждает ваш адрес. Отправитель записывается только после того, как запрос фактически достиг конечной точки, поэтому отказ или разрыв соединения все равно оставляют следующей цепочке свою собственную попытку — и если пропущенная цепочка рекламирует другую конечную точку, причина сообщает об этом, поскольку один отправитель может управлять несколькими списками. Ограничено 25 цепочками и 60 секундами на вызов; то, что бюджет не покрывает, возвращается какskippedOutOfTime, а не молча невыполненным. Ни одно из этих действий нельзя отменить, поэтому и существуют все три ограничения.Защита SSRF. Только https, только порт по умолчанию, никаких учетных данных в URL, и каждый переход — включая перенаправления, не более 3 раз — должен разрешаться исключительно в глобально доступные адреса. Проверка разбирает каждый адрес в байты и сопоставляет его с реестром специального назначения IANA, поэтому все варианты написания одного и того же адреса получают одинаковый вердикт (
::1и0:0:0:0:0:0:0:1одинаково); адрес, который не разбирается, отклоняется. Разрешение DNS и все переходы имеют общий бюджет в 10 секунд. Не защищено от rebinding (fetchразрешается снова при подключении) — см. SECURITY.md; то, что переживает этот разрыв, представляет собой слепой POST, ответ на который никогда не читается.
Проверьте это на своей собственной почте, прежде чем доверять. Из клона репозитория (только репозиторий, не в пакете npm), после npm run build и mailwarden --auth:
node scripts/probe-unsubscribe.mjs --vet # category:promotions, 25 threads
node scripts/probe-unsubscribe.mjs "from:substack.com" --max 50 --vetОн печатает каждый реальный заголовок List-Unsubscribe рядом с тем, что из него извлек парсер, а --vet также прогоняет конечную точку через проверку URL и защиту адреса — так что вы видите и то, понял ли парсер заголовок, и то, пропустили бы защитные механизмы этот отказ от подписки. Строго только для чтения: запрос к отправителю никогда не выполняется, и ничего в почтовом ящике не меняется.
Что он не может отменить: запрос сообщает отправителю, что ваш адрес активен. Отправитель, который игнорирует собственный отказ от подписки, находится вне досягаемости любого клиента — для таких случаев комбинируйте unsubscribe с create_filter или trash. Отсутствие автоматизируемого варианта сообщается как unsubscribed:false с альтернативами, а не как ошибка. Развертывание в режиме read получает list_unsubscribe и list_subscriptions и никогда не выполняет запрос вообще.
Безопасность и конфиденциальность
Полную модель угроз — границы доверия, меры смягчения для каждой угрозы, явные нецели и способы сообщить об уязвимости — см. в SECURITY.md. Основные моменты:
Никакой телеметрии. Ничего не отправляется на домой — никакой аналитики, никаких отчетов о сбоях, никакого отслеживания.
Нет открытых портов по умолчанию. Только stdio. Опциональный слушатель
--httpпривязывается к127.0.0.1(не к локальной сети) и отказывается запускаться без токена-носителяMAILWARDEN_TOKEN— установитеMAILWARDEN_ALLOW_NO_TOKEN=1, чтобы переопределить это в доверенной изолированной сети. При привязке к loopback он также проверяет заголовокHost(защита от DNS-ребендинга). Для удаленного хостинга задайтеMAILWARDEN_HOSTи используйте TLS.Нет инструментов отправки — намеренно. mailwarden не может составлять, отвечать или пересылать. Инструкция, внедренная в электронное письмо, не имеет пути для утечки через этот сервер.
create_filterподчиняется тому же правилу: он может маркировать, архивировать, перемещать в корзину, помечать звездочкой или отмечать почту, но никогда не создает пересылающий фильтр (который был бы путем для утечки).list_filtersпо-прежнему показывает любые пересылающие фильтры, уже имеющиеся на аккаунте, так что вы можете их заметить. Это верно, потому что такого инструмента не существует, и ни один не может быть зарегистрирован во время выполнения; для более строгого варианта, где Google отказывается отправлять, а не mailwarden отклоняет, см. Режим только для чтения ниже.Один исходящий хост, без URL, выбранного моделью. Инструмент
unsubscribe— единственный путь кода, который связывается с хостом, не принадлежащим Google. Его конечная точка берется из заголовкаList-Unsubscribeсообщения — никогда из аргумента инструмента — тело запроса фиксировано, а тело ответа отбрасывается, поэтому он не может стать каналом передачи данных. Только https/порт по умолчанию, перенаправления повторно проверяются, и любой переход, разрешающийся в частный, loopback, link-local или метаданные адрес, отклоняется. См. Отписка.Уровни инструментов (постепенное раскрытие + наименьшая область).
MAILWARDEN_TOOLSобъявляет только те уровни, которые вы называете —read(инструменты чтения),manage(мутации почтового ящика, откладывание, загрузки),filters(CRUD серверных фильтров, единственный уровень, инструменты которого требуютgmail.settings.basic). По умолчанию все три; например,read,manageдает полную поверхность для триажа без управления фильтрами. Области действия OAuth, запрашиваемые при--auth, выводятся из включенных уровней — развертываниеreadзапрашивает толькоgmail.readonly, аgmail.settings.basicзапрашивается только при включенном уровнеfilters. И инструменты фильтрации скрываются автоматически, когда сохраненный токен не имеетgmail.settings.basic(например, токен, авторизованный до того, как вы включили уровень) — повторно запустите--auth, чтобы предоставить его. Старые токены без записанной области действия объявляются как прежде, с сообщением о недостаточной области действия во время выполнения в качестве запасного варианта.Режим только для чтения. Установите
MAILWARDEN_READONLY=1(сокращение дляMAILWARDEN_TOOLS=read), и будут зарегистрированы только инструменты чтения (search,get_thread,list_labels,list_snoozed,get_profile,triage_digest,list_unsubscribe,list_subscriptions) — клиентам не рекламируется ничего, что может изменить почтовый ящик или записать файлы (инструменты фильтрации, которым требуется более широкая областьgmail.settings.basic, также исключены). Рекомендуется для общих/HTTP-развертываний, которые только выполняют триаж. Это также единственный уровень, свойство "не отправлять" которого обеспечивается Google: он содержит токенgmail.readonly, который конечные точки отправки Gmail категорически отклоняют.manageтребуетgmail.modify, и Gmail принимает эту область для отправки — mailwarden просто не предоставляет инструмента, который бы это сделал. Таким образом, развертываниеreadне могло бы отправлять, даже если бы этот бинарный файл был заменен;manageне может отправлять, потому что нечего вызывать. (Нет области записи без отправки, на которую можно было бы переключиться — см. SECURITY.md, угроза 1.)Ограниченные загрузки. При установке
MAILWARDEN_DOWNLOAD_DIRзапись вложений ограничена этим каталогом (канонизирован по реальному пути, с учетом символических ссылок) и никогда не перезаписывает существующий файл.Изоляция недоверенного контента. Каждый результат инструмента обернут в маркеры
<untrusted-tool-output>и очищен от невидимых символов/символов двунаправленного переопределения, чтобы клиенты могли отличить цитируемое почтовое содержимое от инструкций.Живой API, без копирования. Зеркало почтового ящика или поисковый индекс нигде не хранятся. Единственное локальное состояние — это ваш токен OAuth в
~/.mailwarden/.Опциональное шифрование токена в покое.
token.jsonсодержит токен обновления; на диске он защищен только режимомmode 0o600(бездействие на Windows). УстановитеMAILWARDEN_TOKEN_PASSPHRASEв виде ключевой фразы, и токен будет храниться зашифрованным с помощью AES-256-GCM (ключ, полученный через scrypt), так что копия файла — резервная копия, синхронизированная папка, другой компьютер — бесполезна без ключевой фразы. Повторно запуститеmailwarden --authпосле установки, чтобы зашифровать существующий токен. Обратите внимание на границу: это защищает от кражи файла, но не от вредоносного ПО, работающего от вашего имени пользователя (которое также может прочитать ключевую фразу из окружения).
Быстрый старт
claude mcp add mailwarden -- npx -y mailwardenЭто вся установка — npx загружает и запускает опубликованный пакет, без клонирования или сборки. Учетные данные Google OAuth нужны только один раз (ниже).
Настройка
Впервые настраиваете приложение Google OAuth? Следуйте пошаговому руководству по настройке — оно проведет вас через Google Cloud Console с точными путями кликов, объясняет экран "непроверенное приложение" и охватывает ловушку, из-за которой токены умирают через 7 дней. Краткая версия:
Google Cloud: создайте проект → включите Gmail API → настройте экран согласия OAuth и опубликуйте его в Production (в статусе Тестирование Google аннулирует токены обновления через 7 дней) → создайте идентификатор клиента OAuth типа Десктопное приложение → загрузите его как
credentials.json.Поместите
credentials.jsonв~/.mailwarden/(или установитеMAILWARDEN_CREDENTIALS=/путь/к/credentials.json).Авторизуйтесь один раз — откроется браузер, сохранит токен обновления в
~/.mailwarden/token.json:npx -y mailwarden --authЗапрашиваемые области:
gmail.modify(чтение + метка/архив/корзина) иgmail.settings.basic(только управление фильтрами). Если вы авторизовали версию до появления фильтров, повторно запустите--authодин раз, чтобы предоставить добавленную область. Чтобы получить токен, с которым Gmail сам отказывается отправлять, авторизуйтесь с помощьюMAILWARDEN_TOOLS=read— см. Режим только для чтения выше.Проверьте настройку в любое время с помощью встроенного доктора:
npx -y mailwarden --checkОн проверяет
credentials.json, существует ли токен (и зашифрован ли он), покрывают ли предоставленные области ваши включенные уровни, и выполняет один живой вызов Gmail, чтобы доказать, что токен все еще работает — печатая конкретное исправление для всего, что не так, и завершаясь с ненулевым кодом, если это так (удобно в CI/проверках работоспособности). Диагностирует распространенные ловушки: отсутствие/неправильныйфайл учетных данных, никогда не авторизован, зашифрованный токен безMAILWARDEN_TOKEN_PASSPHRASE, отсутствующая область или истечение 7-дневного токена согласия "Тестирование".
Подключение
Claude Code (локальный stdio):
claude mcp add mailwarden -- npx -y mailwardenПлагин Claude Code — тот же сервер плюс навык /mailwarden:setup, который проведет вас через
настройку OAuth и диагностирует неработающую. Корень репозитория — это плагин (.claude-plugin/plugin.json), так что
из клона:
claude --plugin-dir /path/to/mailwardenОн отправлен в сообщество marketplace Anthropic; после публикации /plugin marketplace add anthropics/claude-plugins-community
затем /plugin install mailwarden@claude-community делает то же самое без клона. Плагин запускает полную
поверхность инструментов — для более узкого уровня (MAILWARDEN_TOOLS=read) или второй учетной записи используйте claude mcp add с
нужным вам окружением (см. Конфигурация (env) и Несколько учетных записей).
Claude Desktop — добавьте в claude_desktop_config.json:
{
"mcpServers": {
"mailwarden": { "command": "npx", "args": ["-y", "mailwarden"] }
}
}Или установите пакет MCPB (mailwarden-<версия>.mcpb, прикрепленный к
релизам GitHub начиная с версии 0.10.0) как расширение Desktop — Настройки →
Расширения → Установить расширение… — тот же сервер, самодостаточный во время выполнения (без npx; Claude
Desktop предоставляет среду выполнения Node), с уровнями инструментов в качестве настройки. Пакет собран из упакованного
пакета npm (тот же набор файлов, что и опубликованный; npm run mcpb, проверено в CI: проверен, распакован и запущен)
и представляет собой тот же набор файлов, который распространяет Smithery. Однократный npx -y mailwarden --auth все еще применяется
(Node нужен один раз для этого) — пакет считывает тот же токен ~/.mailwarden/.
Smithery — указан как csitte/mailwarden, который обслуживает
этот пакет:
npx -y @smithery/cli install csitte/mailwarden --client claude # local stdio entry in the client's configОбратите внимание, какой из двух путей Smithery вы выбираете. Приведенная выше установка записывает простую локальную запись сервера:
процесс, ваш токен и ваша почта остаются на вашем компьютере, точно так же, как с npx. Добавление его в
панель инструментов Smithery (smithery mcp add) также запускает пакет локально, но ретранслирует трафик инструментов
через шлюз Smithery, так что удаленный клиент может достичь его — содержимое почтового ящика в этих ответах затем
проходит через третью сторону. Это свойство шлюза, а не mailwarden; если вы хотите
гарантию без третьих сторон, используйте локальную установку, пакет npm или .mcpb со страницы релиза.
Удаленно (Streamable HTTP) — для VPS / пользовательского коннектора claude.ai:
# Loopback + token required by default. For real hosting, bind outward and keep the token:
MAILWARDEN_TOKEN=<secret> MAILWARDEN_HOST=0.0.0.0 npx -y mailwarden --http # :8787/mcpЗатем в claude.ai: Настройки → Коннекторы → Добавить пользовательский коннектор → URL вашего https://your-host/mcp. В Claude Code: claude mcp add --transport http mailwarden https://your-host/mcp.
Несколько учетных записей
Одно приложение OAuth (один credentials.json) может авторизовать несколько учетных записей Gmail. Каждая учетная запись хранит свой
собственный токен обновления в отдельном файле, выбираемом с помощью MAILWARDEN_ACCOUNT:
mailwarden --auth --account work # stores token.work.json
mailwarden --auth --account personal # stores token.personal.jsonЗапускайте их бок о бок, регистрируя сервер по одному разу для каждой учетной записи, каждый со своим
MAILWARDEN_ACCOUNT. Каждый экземпляр полностью изолирован — свой токен, свои предоставленные области, своя
поверхность инструментов — так что ничто не может действовать от имени неправильного почтового ящика:
{
"mcpServers": {
"gmail-work": { "command": "npx", "args": ["-y", "mailwarden"], "env": { "MAILWARDEN_ACCOUNT": "work" } },
"gmail-personal": { "command": "npx", "args": ["-y", "mailwarden"], "env": { "MAILWARDEN_ACCOUNT": "personal" } }
}
}Имена учетных записей нечувствительны к регистру — они становятся именами файлов, так что Work и work будут одним
и тем же файлом в Windows/macOS. mailwarden приводит их к нижнему регистру (--account Work → token.work.json), так что
имя всегда сопоставляется ровно с одним почтовым ящиком.
Какой файл записывает --auth, зависит только от --account / MAILWARDEN_ACCOUNT — никогда от
учетной записи, которую вы выбираете в браузере. Авторизация второго почтового ящика без --account поэтому
была бы нацелена прямо на файл токена первого, так что --auth сначала проверяет и отказывается,
а не заменяет токен другого почтового ящика; --force намеренно переопределяет это. Два рычага не
взаимозаменяемы: MAILWARDEN_ACCOUNT предназначен для нескольких почтовых ящиков из одного каталога конфигурации
(он выбирает token.<имя>.json), тогда как MAILWARDEN_DIR перемещает весь каталог —
полезно для полного разделения настроек, но не дает вам вторую учетную запись в одном.
npm run auth из клона репозитория не передает ни то, ни другое, т.е. он всегда обслуживает учетную запись по умолчанию.
mailwarden --check показывает активную учетную запись и перечисляет другие, которые он находит. Если
MAILWARDEN_ACCOUNT не задан, все использует файл по умолчанию token.json точно так же, как и раньше — это полностью
обратно совместимо.
Из исходного кода
git clone https://github.com/csitte/mailwarden && cd mailwarden
npm install && npm run build
node dist/index.js --authКонфигурация (env)
Var | Значение |
| каталог конфигурации (по умолчанию |
| путь к |
| выберите именованную учетную запись (ее токен — |
| парольная фраза → шифрует |
|
|
| ограничить |
|
|
| уровни инструментов, разделенные запятыми, для рекламы: |
|
|
| HTTP-порт (по умолчанию 8787) |
| HTTP-адрес привязки (по умолчанию |
| токен-носитель для HTTP-конечной точки — обязателен для |
|
|
| дополнительные значения |
Статус
Работает и используется в ежедневной автоматизации почтового ящика. Основные инструменты Gmail + отложенные письма реализованы на googleapis, покрыты набором тестов vitest (789 тестов — npm run coverage). Текущая версия: см. значок npm выше, журнал изменений или релизы. PR приветствуются.
Лицензия
MIT © C.Sitte Softwaretechnik
Maintenance
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server that enables Gmail integration, allowing users to manage emails (send, receive, read, trash, mark as read) directly through MCP clients like Claude Desktop.1MIT
- AlicenseBqualityDmaintenanceManage your emails effortlessly with a standardized interface for drafting, sending, retrieving, and organizing messages. Streamline your email workflow with complete Gmail API coverage, including label and thread management.641,39856MIT
- AlicenseNot gradedqualityAmaintenanceGmail MCP server — scope-gated tools (readonly / send / modify), path jails for attachments + downloads, hardened OAuth credentials, Sigstore-signed releases.20711MIT
- AlicenseAqualityFmaintenanceA Gmail MCP server with native multi-account support, enabling management of multiple Gmail accounts from a single server instance.75MIT
Related MCP Connectors
Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.
Shipmail MCP server for AI agent custom-domain email inboxes with REST API and webhooks.
Fully-managed email as MCP tools - register domains, real mailboxes, send and receive mail.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/csitte/mailwarden'
If you have feedback or need assistance with the MCP directory API, please join our Discord server