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_read | list, read, read_batch, search, attachment, extract, original | read:email (для search также принимается search:email) |
email_organize | move, move_batch, copy, copy_batch, flag, archive | manage:folders |
email_search_and_move | (одно действие) | manage:folders |
email_delete | delete, delete_batch, search_and_delete | delete:email |
email_compose | send, reply, forward | send:email |
folder_list | (одно действие) | read:email |
folder | create, rename, delete | manage:folders |
draft_list | (одно действие) | manage:drafts |
draft | create, reply, update, send, delete | manage:drafts (create/reply/update/delete), read:email (также для reply), send:email (для send) |
schedule_list | (одно действие) | schedule:email |
schedule | create, cancel | schedule:email |
signature_get | (одно действие) | read:email |
signature_set | (одно действие) | send:email |
automation_read | list, get, runs, preview | manage:automations |
automation | create, update, enable, disable, delete | manage: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требуется scopesend:email, а неmanage:drafts, поэтому ключ, умеющий работать только с черновиками, не сможет использовать их в обход согласия на отправку почты. -
Действие
replyуdraftсоздаёт неотправленный нативный ответ провайдера в исходной переписке. Для него нужны оба scope —manage:draftsиread:email; по умолчанию ответ адресуется только отправителю. -
Инструменты только для чтения (
folder_list,draft_list,schedule_list,signature_get,automation_read) были выделены из соответствующих инструментов записи 2026-09-09, поэтому ключу с правами только на чтение никогда не показывается инструмент записи. Старые комбинированные формы (folderaction: "list",draftaction: "list",scheduleaction: "list",signatureaction: "get"/"set",automationaction: "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 Workspace | OAuth 2.0 | ✅ | ✅ | Ярлыки | Только корзина | ✅ |
| Fastmail | Пароль приложения (IMAP/SMTP) | ✅ | ✅ | ✅ | ✅ | ✅ |
| iCloud, Yahoo, Zoho, Yandex | Пароль приложения (IMAP/SMTP) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Любой почтовый ящик IMAP/SMTP | Пароль приложения | ✅ | ✅ | ✅ | ✅ | ✅ |
| Outlook / Microsoft 365 | OAuth 2.0 | 🚧 реализовано, скрыто до проверки |
OAuth для Outlook реализован от начала до конца, но пока доступ к нему закрыт до прохождения верификации издателя Microsoft; в интерфейсе подключения он скрыт, пока функция не будет выпущена.
Тарифы
Основная метрика тарификации — подключённые почтовые ящики. Тариф Free позволяет подключить один ящик, Personal — до трёх, Pro — все ящики, которыми вы владеете, а Team дополнительно добавляет участников, роли и отдельное рабочее пространство для каждого клиента. Годовая оплата экономит около 20 %.
| Free | Personal | Pro | Team | |
|---|---|---|---|---|
| Цена | $0 | $5/мес · $48/год ($4/мес) | $15/мес · $144/год ($12/мес) | $79/мес · $756/год ($63/мес) |
| Подключённые ящики | 1 | 3 | Без ограничений | Без ограничений |
| Действия с почтой за месяц | 150 (первые 7 дней не учитываются) | Без месячного лимита (fair use) | Без месячного лимита (fair use) | Без месячного лимита (fair use) |
| Ключи API | Без ограничений | Без ограничений | Без ограничений | Без ограничений |
| Участники | 1 (только владелец) | 1 (только владелец) | 1 (только владелец) | Без ограничений, с ролями |
| Ограничение частоты (fair use) | 60 запросов/мин | 120 запросов/мин | 300 запросов/мин | 1 000 запросов/мин |
| Роли и рабочие пространства команды | Нет | Нет | Нет | ✅ |
| SSO (SAML/OIDC) + журнал аудита | Нет | Нет | Нет | ✅ |
| Поддержка | Сообщество | Приоритетная |
Также действуют лимиты на каждый ключ 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-функции Supabasemcp-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_KEY | 64-символьный hex-ключ AES-256-GCM для шифрования учётных данных при хранении — секрет |
CSRF_SECRET | 64-символьный hex-ключ HMAC для CSRF-токенов (отличается от предыдущего) — секрет |
Зависят от используемых функций:
| Переменные | Для чего нужны |
|---|---|
GMAIL_CLIENT_ID / GMAIL_CLIENT_SECRET | Gmail OAuth (gmail.readonly, gmail.send, gmail.modify) |
OUTLOOK_CLIENT_ID / OUTLOOK_CLIENT_SECRET / OUTLOOK_TENANT_ID | Outlook 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.