API VEGA

MCPEmails

Дайте вашему AI-агенту почтовый ящик. Облачный сервер Model Context Protocol, который позволяет Claude, Cursor или любому MCP-совместимому клиенту читать, искать, отправлять, упорядочивать письма и планировать их отправку через ваши существующие почтовые ящики — не сохраняя вашу почту.

Подключите почтовый ящик один раз, вставьте один URL в агента — и он сможет работать с вашей почтой в реальном времени. Письма получаются по запросу и нигде не хранятся; учётные данные шифруются при хранении и расшифровываются только в момент вызова внутри изолированной edge-функции.

🔗 mcpemails.com · 📚 Документация · 💳 Тарифы


Содержание

  • Как это работает

  • Быстрый старт (подключение агента)

  • Возможности

  • Инструменты

  • OAuth-скоупы

  • Поддерживаемые провайдеры

  • Тарифы

  • Архитектура

  • Структура репозитория

  • Локальная разработка

  • Переменные окружения

  • База данных и миграции

  • Развёртывание

  • Самостоятельный хостинг

  • Интернационализация

  • Модель безопасности


Как это работает

  • Подключите почтовый ящик. Войдите на mcpemails.com и добавьте Gmail (OAuth в один клик) или любой аккаунт IMAP/SMTP (через пароль приложения). Учётные данные шифруются алгоритмом AES-256-GCM ещё до того, как попадут в базу данных.

  • Получите доступ. Клиенты с поддержкой OAuth (claude.ai, Claude Desktop, Cursor) подключаются в один клик через OAuth 2.0 + PKCE. Для всех остальных используется API-ключ с ограниченной областью действия (mcpe_…).

  • Направьте клиент на сервер. MCP-эндпоинт — это один URL:

https://mcpemails.com/api/mcp
  • Агент работает с почтой. Он вызывает инструменты вроде inbox_list, email_read (action: "search"), email_compose (action: "send") и schedule (action: "create"). Каждый запрос получает данные напрямую у вашего провайдера — ничего не дублируется и не кэшируется на стороне сервера.

Права ограничиваются на уровне ключа: агенту можно выдать только read:email, либо разрешить отправку и управление папками, не открывая доступ к удалению.

Быстрый старт (подключение агента)

Claude Desktop / Cursor (OAuth): добавьте удалённый MCP-сервер с адресом https://mcpemails.com/api/mcp и одобрите экран согласия. Выберите скоупы, которые должны быть у агента.

API-ключ (любой MCP-клиент): создайте ключ в панели управления, выберите для него скоупы и (опционально) ограничьте его конкретными ящиками, а затем передавайте его как bearer-токен:

// Example MCP client config
{
  "mcpServers": {
    "mcpemails": {
      "url": "https://mcpemails.com/api/mcp",
      "headers": { "Authorization": "Bearer mcpe_your_key_here" }
    }
  }
}

Протокол — JSON-RPC 2.0 поверх HTTP (MCP 2025-06-18, транспорт Streamable). Начинайте каждую сессию с inbox_list: инструмент возвращает ящики, доступные ключу, их возможности для каждого провайдера и версионированный профиль совместимости. Профиль помечает нормализованные операции как exact, different или unavailable, чтобы агенты могли учитывать различия между провайдерами, а не молча ослаблять запрос.

Инструкции по настройке

Готовые к копированию инструкции для каждого клиента — включая расположение его файла конфигурации: mcpemails.com/docs/clients.

Claude · Claude Code · ChatGPT · Cursor · VS Code · Cline · Windsurf · Gemini CLI · Zed · JetBrains · Raycast · Warp · curl

Возможности

  • Работа в реальном времени, без хранения — при каждом вызове письма читаются напрямую у вашего провайдера; тела сообщений нигде не сохраняются.

  • Мультипровайдерность — Gmail через OAuth, а также любой ящик IMAP/SMTP (Fastmail, iCloud, Yahoo, Zoho, Yandex, собственный сервер…) через пароль приложения.

  • Без релея — исходящая почта отправляется через SMTP/API вашего провайдера, с вашего настоящего адреса.

  • Гранулярные скоупы — восемь областей разрешений, которые выдаются независимо для каждого API-ключа и каждого ящика.

  • Пакетные операции и «поиск с действием» — чтение, перемещение, удаление или пометка до сотен писем за один вызов, включая комбинированные операции «найти, затем переместить/удалить».

  • Черновики и отложенная отправка — составление черновиков и постановка писем в очередь на отправку в будущем (отправка выполняется на стороне сервера).

  • Поиск, независимый от провайдера — синтаксис Gmail, IMAP SEARCH и JMAP нормализованы за единым интерфейсом email_read (action: "search").

  • Готовность к командной работе: рабочие пространства, участники, роли, SSO и журнал аудита в тарифе Team.

Инструменты

17 инструментов, которые вы вызываете напрямую. Большинство из них ориентированы на ресурсы и принимают аргумент action, выбирающий конкретную операцию (а для действий, требующих разных прав, — необходимый scope):

  • inbox_list — перечисляет почтовые ящики, доступные ключу, вместе с возможностями провайдера каждого из них.

  • email_read — перечисляет, читает и ищет письма (в том числе пакетно), а также работает с вложениями, извлечённым из них текстом и оригинальным файлом .eml.

  • email_organize — перемещает, копирует, помечает флагом и архивирует письма по указанным идентификаторам — по одному или пакетно.

  • email_search_and_move — перемещает все письма, соответствующие поисковому запросу, в указанную папку. Вынесен в отдельный инструмент как потенциально опасный: ошибочный фильтр переместит письма сразу во всём ящике.

  • email_delete — удаляет письма в корзину или безвозвратно: по одному, пакетно или по поисковому запросу.

  • email_compose — отправляет, отвечает и пересылает письма через вашего провайдера и с вашего реального адреса.

  • folder_list — перечисляет папки (в Gmail — ярлыки) с их нативными идентификаторами провайдера и количеством писем. Только чтение.

  • folder — создаёт, переименовывает и удаляет папки (в Gmail — ярлыки).

  • draft_list — перечисляет черновики, сохранённые в ящике, с их идентификаторами. Только чтение.

  • draft — создаёт, обновляет, отправляет и удаляет черновики, включая нативные ответы провайдера.

  • schedule_list — перечисляет письма, ожидающие отложенной отправки. Только чтение.

  • schedule — ставит письмо в очередь на отложенную отправку и отменяет уже запланированное.

  • signature_get — читает подпись и имя отправителя, настроенные для ящика. Только чтение.

  • signature_set — задаёт подпись, добавляемую к исходящим письмам, и имя отправителя.

  • automation_read — перечисляет правила сортировки, читает конкретное правило, показывает историю запусков и выполняет пробный прогон фильтра. Только чтение.

  • automation — создаёт, обновляет, включает, отключает и удаляет автономные правила сортировки, работающие без участия модели.

  • contact_search — ищет контакты, сканируя недавнюю почту в реальном времени; отдельная адресная книга не хранится.

ИнструментДействияScope(s)
inbox_list(одно действие)read:email
email_readlist, read, read_batch, search, attachment, extract, originalread:email (для search также принимается search:email)
email_organizemove, move_batch, copy, copy_batch, flag, archivemanage:folders
email_search_and_move(одно действие)manage:folders
email_deletedelete, delete_batch, search_and_deletedelete:email
email_composesend, reply, forwardsend:email
folder_list(одно действие)read:email
foldercreate, rename, deletemanage:folders
draft_list(одно действие)manage:drafts
draftcreate, reply, update, send, deletemanage:drafts (create/reply/update/delete), read:email (также для reply), send:email (для send)
schedule_list(одно действие)schedule:email
schedulecreate, cancelschedule:email
signature_get(одно действие)read:email
signature_set(одно действие)send:email
automation_readlist, get, runs, previewmanage:automations
automationcreate, update, enable, disable, deletemanage:automations
contact_search(одно действие)manage:contacts (также принимается read:email)

Ключ с полным набором scope видит в tools/list 22 инструмента: 16 перечисленных выше плюс шесть инструментов, доступных только приложению (approval_review, approval_decide, approval_update, approval_schedule, bulk_execute, bulk_cancel). Они содержат _meta.ui.visibility: ["app"] и отвечают за карточку подтверждения, которую MCP-клиент показывает для отправки, ожидающей подтверждения, или массовой операции в режиме предпросмотра; вручную эти инструменты не вызывают.

Примечания:

  • Инструменты принимают либо явный inbox_id (UUID), либо email-адрес в параметре inbox; для ключей с доступом к одному ящику цель определяется автоматически.

  • Лимиты пакетных действий — от 50 писем за вызов (read_batch у email_read) до 500 (перемещение/удаление/пометка флагом).

  • Для точечного изменения сначала используйте email_read с action: "search", а затем передайте полученные message_id или message_ids в email_organize или email_delete. Поля поиска принимаются только инструментом email_search_and_move и действием search_and_delete у email_delete.

  • contact_search сканирует недавнюю почту в реальном времени, поэтому отдельная адресная книга не хранится.

  • Действие original у email_read возвращает одно полное MIME-сообщение в том виде, в каком оно хранится у провайдера, в виде переносимого файла .eml (до 25 МБ). Операция доступна только для чтения и никогда не помечает письмо как прочитанное.

  • Действию send у draft требуется scope send:email, а не manage:drafts, поэтому ключ, умеющий работать только с черновиками, не сможет использовать их в обход согласия на отправку почты.

  • Действие reply у draft создаёт неотправленный нативный ответ провайдера в исходной переписке. Для него нужны оба scope — manage:drafts и read:email; по умолчанию ответ адресуется только отправителю.

  • Инструменты только для чтения (folder_list, draft_list, schedule_list, signature_get, automation_read) были выделены из соответствующих инструментов записи 2026-09-09, поэтому ключу с правами только на чтение никогда не показывается инструмент записи. Старые комбинированные формы (folder action: "list", draft action: "list", schedule action: "list", signature action: "get"/"set", automation action: "list"/"get"/"runs"/"preview") по-прежнему принимаются от уже подключённых клиентов, но больше не объявляются.

  • automation управляет автономными правилами сортировки по расписанию: сохранённый поисковый запрос плюс одно фиксированное действие, которые применяются с заданной периодичностью без участия модели. Действия для удаления почты нет, forward всегда ожидает подтверждения человека, а draft_reply лишь создаёт черновик. Подробнее — в docs/automations-trust-boundary.md.

  • tools/list возвращает только те инструменты, на которые реально распространяется действие вашего ключа (или OAuth-токена).

OAuth scopes

ScopeПредоставляемые права
read:emailПросмотр ящиков и папок; перечисление, чтение и поиск писем; чтение подписи ящика; поиск контактов
search:emailБолее узкая альтернатива: даёт доступ только к действию search инструмента email_read
send:emailОтправка, ответы и пересылка; установка подписи и имени отправителя; также требуется для отправки черновика
manage:foldersСоздание, переименование и удаление папок; перемещение, копирование, пометка флагом и архивирование писем
delete:emailПеремещение писем в корзину или безвозвратное удаление
manage:draftsСоздание, редактирование и удаление черновиков (для отправки также требуется send:email)
manage:contactsПоиск контактов по недавней почте в реальном времени
schedule:emailПостановка писем в очередь на отложенную отправку
manage:automationsСоздание автономных правил сортировки по расписанию и управление ими (действия удаления нет; пересылка всегда требует подтверждения)

Поддерживаемые провайдеры

ПровайдерСпособ подключенияЧтение/ПоискОтправкаПапкиБезвозвратное удалениеЧерновики
Gmail / Google WorkspaceOAuth 2.0ЯрлыкиТолько корзина
FastmailПароль приложения (IMAP/SMTP)
iCloud, Yahoo, Zoho, YandexПароль приложения (IMAP/SMTP)
Любой почтовый ящик IMAP/SMTPПароль приложения
Outlook / Microsoft 365OAuth 2.0🚧 реализовано, скрыто до проверки

OAuth для Outlook реализован от начала до конца, но пока доступ к нему закрыт до прохождения верификации издателя Microsoft; в интерфейсе подключения он скрыт, пока функция не будет выпущена.

Тарифы

Основная метрика тарификации — подключённые почтовые ящики. Тариф Free позволяет подключить один ящик, Personal — до трёх, Pro — все ящики, которыми вы владеете, а Team дополнительно добавляет участников, роли и отдельное рабочее пространство для каждого клиента. Годовая оплата экономит около 20 %.

FreePersonalProTeam
Цена$0$5/мес · $48/год ($4/мес)$15/мес · $144/год ($12/мес)$79/мес · $756/год ($63/мес)
Подключённые ящики13Без ограниченийБез ограничений
Действия с почтой за месяц150 (первые 7 дней не учитываются)Без месячного лимита (fair use)Без месячного лимита (fair use)Без месячного лимита (fair use)
Ключи APIБез ограниченийБез ограниченийБез ограниченийБез ограничений
Участники1 (только владелец)1 (только владелец)1 (только владелец)Без ограничений, с ролями
Ограничение частоты (fair use)60 запросов/мин120 запросов/мин300 запросов/мин1 000 запросов/мин
Роли и рабочие пространства командыНетНетНет
SSO (SAML/OIDC) + журнал аудитаНетНетНет
ПоддержкаСообществоEmailEmailПриоритетная

Также действуют лимиты на каждый ключ API (100 запросов/мин · 1 000/ч · 10 000/сутки). Лимиты частоты допускают повторные попытки: они возвращаются как ошибка JSON-RPC -32003 с полем data.retry_after в секундах.

В бесплатных рабочих пространствах доступно 150 действий с почтой за календарный месяц (UTC). Первые 7 дней после регистрации не учитываются, а inbox_list и панель управления не учитываются никогда. Когда лимит исчерпан, любые другие действия с почтой отклоняются до 1-го числа следующего месяца, автоматизации без участия человека приостанавливаются и автоматически возобновляются 1-го числа, а владельцу отправляются письма при достижении 80 % и 100 %. В тарифах Personal, Pro и Team месячного лимита нет — при условии добросовестного использования (их потолки служат защитой от злоупотреблений, а не возможностью тарифа, и нигде не публикуются). Отказ не допускает повторной попытки и не является ошибкой JSON-RPC: он возвращается как обычный результат инструмента с isError: true, текстом, который начинается со счётчика и даты сброса, и блоком _meta["com.mcpemails/usage_limit"], который очищается в reset_at.

Внутренние идентификаторы тарифов появились раньше их названий: solo продаётся как Pro, а pro — как Team. Более новый идентификатор personal — единственный, совпадающий со своим отображаемым названием, Personal. Все пользователи, зарегистрировавшиеся до изменения цен 2026-08-19, навсегда бесплатно сохраняют безлимитные ящики, а каждое рабочее пространство, созданное до запуска лимита действий 2026-09-12, считается ранним участником и не учитывается в этом лимите. См. apps/web/src/lib/stripe/plans.ts.

Архитектура

flowchart LR
    Agent["MCP client<br/>(Claude, Cursor, …)"] -->|"JSON-RPC / OAuth or API key"| Web

    subgraph Vercel["Vercel — Next.js 16"]
      Web["/api/mcp route<br/>+ marketing site + dashboard"]
    end

    subgraph Supabase
      Edge["mcp-server<br/>edge function (Deno)"]
      DB[("Postgres<br/>RLS + encrypted creds")]
      Cron["token-refresh<br/>edge functions"]
    end

    Web -->|proxies| Edge
    Edge -->|decrypt creds, fetch live| Providers["Email providers<br/>Gmail API · IMAP/SMTP"]
    Edge --> DB
    Cron --> DB
    Web --> Stripe[("Stripe<br/>billing")]
  • /api/mcp — это тонкий обработчик маршрута Next.js, который проксирует запросы к edge-функции Supabase mcp-server — настоящей реализации MCP, где расшифровываются учётные данные и выполняются вызовы провайдеров.

  • База данных Postgres хранит рабочие пространства, участников, ящики (зашифрованные токены и пароли), хешированные ключи API, OAuth-клиенты, отложенные отправки и журнал активности — всё под защитой Row-Level Security.

  • Cron edge-функции обновляют OAuth-токены Gmail и Outlook до истечения срока их действия.

Стек: Next.js 16 (App Router) · React 19 · next-intl 4 · Supabase (Auth, Postgres, Edge Functions) · Stripe · Resend · TypeScript. Разбор и очистка писем выполняются через mailparser, jsdom и isomorphic-dompurify.

Структура репозитория

.
├── apps/
│   └── web/                     # Next.js 16 app (marketing, dashboard, /api/mcp proxy)
│       ├── app/                 # App Router routes ([locale], dashboard, api, auth)
│       ├── components/          # marketing/ + dashboard/ React components
│       ├── messages/            # next-intl translations (en, nb, es, fr, zh)
│       ├── src/lib/             # stripe/, supabase/, blog/, crypto helpers
│       └── proxy.ts             # middleware: i18n + Supabase session + CDN cache
├── supabase/
│   ├── functions/
│   │   ├── mcp-server/          # the MCP server (tools, auth, scopes)
│   │   ├── gmail-token-refresh/
│   │   └── outlook-token-refresh/
│   └── migrations/              # SQL migrations (schema + RLS)
└── package.json                 # npm workspaces (apps/*)

Локальная разработка

Требования: Node.js 20+, npm и Supabase CLI (для миграций и edge-функций).

# 1. Install (npm workspaces — run from the repo root)
npm install

# 2. Configure environment
cp .env.example apps/web/.env.local
#   then fill in the values (see below) and generate the two secrets:
openssl rand -hex 32   # ENCRYPTION_KEY
openssl rand -hex 32   # CSRF_SECRET

# 3. Run the web app (http://localhost:3000)
npm run dev

# 4. Production build
npm run build

next.config.js проверяет обязательные переменные окружения во время сборки и запуска и отклоняет слабые значения ENCRYPTION_KEY, поэтому неправильно настроенное окружение падает сразу, а не во время работы.

Переменные окружения

Скопируйте .env.example и подставьте реальные значения. Обязательны в любом окружении:

ПеременнаяНазначение
NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEYКлиент Supabase (публичный)
SUPABASE_SERVICE_ROLE_KEYАдминистративный ключ на стороне сервера (обходит RLS) — секрет
NEXT_PUBLIC_APP_URLКанонический базовый URL; определяет URI перенаправления OAuth
GOOGLE_SITE_VERIFICATION (опционально)Токен верификации HTML-тега Google Search Console; задавайте только в продакшене
ENCRYPTION_KEY64-символьный hex-ключ AES-256-GCM для шифрования учётных данных при хранении — секрет
CSRF_SECRET64-символьный hex-ключ HMAC для CSRF-токенов (отличается от предыдущего) — секрет

Зависят от используемых функций:

ПеременныеДля чего нужны
GMAIL_CLIENT_ID / GMAIL_CLIENT_SECRETGmail OAuth (gmail.readonly, gmail.send, gmail.modify)
OUTLOOK_CLIENT_ID / OUTLOOK_CLIENT_SECRET / OUTLOOK_TENANT_IDOutlook OAuth (Mail.Read, Mail.Send, Mail.ReadWrite, offline_access)
NEXT_PUBLIC_OAUTH_VERIFICATION_PENDINGПоказывает предупреждение о непроверенном приложении, пока не завершится верификация Google/Microsoft
STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET / NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYБиллинг
STRIPE_PRICE_PERSONAL_MONTHLY / _YEARLY, STRIPE_PRICE_SOLO_MONTHLY / _YEARLY, STRIPE_PRICE_PRO_MONTHLY / _YEARLYИдентификаторы цен тарифов (personal = Personal, solo = Pro, pro = Team)
STRIPE_WEBHOOK_PROXY_KEYОпционально. Ограничивает доступ к /api/stripe/webhook только очередью доставки перед ним. Не задана = без ограничений. Задавайте её только ПОСЛЕ того, как очередь начнёт отправлять этот ключ, иначе каждая доставка получит 401 и попадёт в dead letter.
STRIPE_WEBHOOK_TOLERANCE_SECONDSОпционально. Предельный возраст подписи Stripe, по умолчанию 7 дней. Значение такое большое, потому что отложенный повтор несёт исходную подпись; стандартные 300 с в Stripe отклонили бы любой отложенный повтор.

Fastmail и другие IMAP-провайдеры подключаются через пароль приложения и не требуют учётных данных OAuth.

Вебхуки Stripe доставляются через очередь. Stripe отправляет запросы на вход Queuey, который перенаправляет их в /api/stripe/webhook. Две настройки этой очереди критически важны: полезная нагрузка должна передаваться без изменений (подпись вычисляется по точным байтам), а сопоставленный заголовок должен передавать header:Stripe-Signature. Без сопоставленного заголовка каждая доставка завершается ошибкой Missing stripe-signature header. Учтите, что STRIPE_WEBHOOK_SECRET должен быть секретом подписи того endpoint Stripe, который указывает на вход, а не на любой старый прямой endpoint.

База данных и миграции

Схема и политики Row-Level Security находятся в supabase/migrations/. Основные таблицы: workspaces, workspace_members, inboxes (зашифрованные учётные данные, с мягким удалением), api_keys (хешированные, с областями действия и привязкой к ящикам), oauth_clients, scheduled_sends, workspace_invites и разбитый по месяцам activity_log.

# Apply migrations to the linked project
npx supabase db push

# Regenerate TypeScript types from the live schema
npm run gen:types

Supabase CLI — источник истины для изменений базы данных в этом проекте.

apps/web/src/types/database.types.ts — СГЕНЕРИРОВАННЫЙ ФАЙЛ

Он полностью формируется командой npm run gen:types (supabase gen types typescript --linked), которая читает живой привязанный проект, а не файлы миграций.

Не редактируйте его вручную: столбец, добавленный руками, молча исчезнет при следующей регенерации, а столбец, которого никогда не было в базе, успешно компилируется и падает с 500 в продакшене. Перегенерируйте файл в том же изменении, что применяет миграцию, и коммитьте результат.

Таблицы, представления и RPC-функции — всё покрыто, а каждый Supabase-клиент, объявленный в .ts/.tsx файлах apps/web (а это вся программа, проходящая проверку типов), типизирован как SupabaseClient, поэтому .from(), .select(), .insert() и .rpc() проверяются типами относительно реальной схемы. Если таблица или столбец как будто отсутствует, исправление — npm run gen:types, а не локальный as any на Supabase-клиенте. Оставшиеся приведения типов относятся к тому, что генератор действительно не умеет выразить: формы jsonb-нагрузок, nullable-аргументы функций и один вспомогательный метод, который диспетчеризует множество RPC через одну сигнатуру. Каждый из них снабжён комментарием, объясняющим это.

Квалификатор .ts/.tsx здесь принципиален. apps/web/tsconfig.json не задаёт checkJs, а его include — это **/*.ts и **/*.tsx, поэтому файл .js, такой как app/dashboard/[[...section]]/page.js, целиком выпадает из программы: типы из JSDoc @param — это документация, и никто их не проверяет. Они записаны как SchemaTypedClient (это @typedef для SupabaseClient), чтобы документация хотя бы совпадала с тем, что передают вызывающие стороны, но поддерживать это соответствие приходится вручную.

Никогда не пишите SupabaseClient без параметра типа. Без аргумента типа он разворачивается в SupabaseClient, а это тот же as any, только его не найдёт ни один grep по as any: функция, объявленная как db: SupabaseClient, вообще не проверяет столбцы, а несуществующий столбец в .insert() компилируется без ошибок. SupabaseClient — та же дыра, произнесённая вслух, и точно так же SupabaseClient и SupabaseClient, где алиас — any. Поэтому apps/web/eslint.config.mjs не охотится за any: он требует Database, и npm run lint выдаёт ошибку на любое упоминание типа SupabaseClient, которое его не несёт, а также на непараметризованный вызов createServerClient(...) / createBrowserClient(...).

Это синтаксические селекторы (в репозитории нет linting с учётом типов), поэтому они срабатывают по написанию в точке использования, и мимо них иначе могли бы проскочить три вещи: import { SupabaseClient as SB }, import * as Supa, а затем Supa.SupabaseClient, и const mk = createServerClient; mk(...). Ни один селектор не видит сквозь такие конструкции, поэтому конфиг закрывает их на уровень выше: переименование импорта SupabaseClient и namespace-импорт @supabase/ssr или @supabase/supabase-js сами по себе считаются ошибками, а no-restricted-imports не пускает createClient / createServerClient / createBrowserClient ни в один файл, кроме обёрток в src/lib/supabase/ — единственного места, где создаётся клиент, и всегда с передачей ``. Всё остальное импортирует именно эти обёртки.

Правила не ограничены областью **/*.ts(x), поэтому ограничения на импорт и вызовы действуют и в .js/.jsx/.mjs. Чего они там не умеют — читать тип из JSDoc: синтаксический селектор не видит для него узла AST. Это известное ограничение из пункта выше, а не пробел, который правила якобы закрывают.

Две вещи, о которых успешный tsc всё равно не скажет:

  • --linked читает продакшен, а не supabase/migrations/. В файл попадает то, что реально есть в живом проекте, включая дрейф, а миграция, которая существует локально, но не была запушена, для него невидима. Для регенерации нужны учётные данные привязанного проекта, поэтому CI не может воспроизвести этот файл только из репозитория. Проверяйте supabase migration list --linked, прежде чем верить, что типы описывают то же, что и миграции. По состоянию на 2026-09-16 эта команда сообщает о восьми несоответствиях в обе стороны.

  • Приведение типа всё равно отключает проверку. И (row as any).some_column, и client as unknown as SupabaseClient скомпилируют что угодно. Lint-правила выше ловят объявление клиента, но не клиент, приведённый к any в точке вызова; такие случаи перехватывает @typescript-eslint/no-explicit-any, и eslint-disable на него — это осознанный выбор, который должен объяснять причину.

Развёртывание

Веб-приложение → Vercel (проект mcp-emails-web):

vercel --prod --yes

Заголовки безопасности и таймауты функций заданы в vercel.json. Маркетинговые маршруты отдаются с CDN‑кэшируемым Cache-Control (задаётся в proxy.ts), чтобы краулеры и повторные посетители попадали в edge-кэш; dashboard, auth и API-маршруты остаются no-store.

MCP-сервер → Supabase edge function:

npx supabase functions deploy mcp-server --project-ref <your-project-ref> --no-verify-jwt

Сначала миграции, потом функция. PostgREST не возвращает undefined для столбца, о котором ничего не знает, — он выдаёт ошибку, — а общая проекция входящих в сервере (INBOX_SELECT_COLUMNS) используется всеми почтовыми инструментами, и все они трактуют ошибку запроса как «входящие не найдены». Поэтому развёртывание функции раньше её миграции может уронить весь почтовый функционал, а не только ту фичу, которой понадобился новый столбец. Столбцы входящих, добавленные новой миграцией, намеренно читаются отдельными небольшими запросами (readSendReviewMode, readBulkReviewMode, readInboxDraftEditorHidden), чтобы развёртывание в неправильном порядке деградировало только эту одну фичу, а не ломало всё — это страховка, а не разрешение нарушать порядок.

Самостоятельный хостинг

Не хотите доверять свою почту хостинговому сервису? Запустите тот же MCP-сервер на своей машине. Каталог self-host/ поставляется с контейнеризованным стеком (Postgres + PostgREST + сервер на Deno, без Supabase/Stripe/dashboard), так что ваши учётные данные шифруются ключом, который есть только у вас, и расшифровываются только внутри вашего контейнера.

cd self-host
make setup      # generate secrets (.env)
make up         # build + start the stack
export IMAP_PASSWORD='your-app-password'
make provision EMAIL=you@example.com IMAP_HOST=imap.fastmail.com SMTP_HOST=smtp.fastmail.com SERVICE=fastmail
make key NAME="my agent"   # mint an mcpe_ key, then point your client at http://localhost:8787

Стек в первую очередь опирается на IMAP/SMTP (Fastmail, iCloud, Yahoo, Zoho, Yandex, generic) через пароль приложения; OAuth для Gmail/Outlook и веб-dashboard остаются доступны только в хостинговой версии. Контейнер запускает supabase/functions/mcp-server/ без изменений; полное руководство — в self-host/README.md.

Интернационализация

Построено на next‑intl (localePrefix: 'as-needed', localeDetection: false для стабильных канонических URL). Английский отдаётся по /; остальные локали имеют префикс (/nb, /es, /fr, /zh). Переводы хранятся в apps/web/messages/.

Поддерживаемые локали: английский, норвежский букмол, испанский, французский, китайский (упрощённый).

Модель безопасности

  • Учётные данные шифруются при хранении с помощью AES‑256‑GCM; расшифровываются только внутри edge function в момент вызова.

  • Письма не хранятся — тела писем и вложения загружаются на лету и никогда не сохраняются. Извлечение текста из вложений выполняется транзиентно в рамках запроса и не возвращает сырые байты вложения.

  • API-ключи хранятся в виде хешей (для отображения сохраняется только префикс) и ограничены по разрешениям и по входящим, с опциональным сроком действия.

  • OAuth 2.0 + PKCE для авторизации клиентов; Dynamic Client Registration (RFC 7591) для MCP-клиентов.

  • Row‑Level Security изолирует данные каждого workspace на уровне базы данных.

  • Строгий CSP, HSTS, X-Frame-Options: DENY и связанные заголовки в каждом ответе.

Лицензия

MCP Emails — открытый проект под лицензией GNU Affero General Public License v3.0 (AGPL‑3.0). Хостинговый сервис на mcpemails.com запускает тот же сервер, который вы можете развернуть самостоятельно, — так что вы можете прочитать код, проверить его и запустить у себя. Модель доверия описана в /security.


Отправляйте и получайте почту из любого агента. © MCPEmails, AGPL‑3.0.