mailwarden
mailwarden
信頼性の高いネイティブなGmail MCPサーバー。AIアシスタント向けの完全なメールボックストリアージを提供し、他のどのGmail MCPサーバーにもない機能を搭載しています:メールボックスサイドのスヌーズ。
ハイライト
スヌーズ — Gmail MCPサーバーで唯一のメールボックスサイドのスヌーズ。 スレッドを今すぐアーカイブし、指定した日付に受信箱に再表示させます。日付ラベルとスイープを組み合わせて構築されているため、どのクライアントからでも動作し、Gmail自体で表示可能で、再起動後も持続します。(他のサーバーが「スヌーズ」を提供する場合、それはローカルのリマインダーリストであり、メールは受信箱から出たり入ったりしません。)
信頼できる検索。 Gmailの
threads.list— スレッド検索が通る呼び出し — は、古いスレッドレベルの読み取り状態からis:unreadに答えることができます。実際のメールボックスで測定したところ、返されたスレッドの86%に未読メッセージがまったく含まれていませんでした。別のメールボックスでは全くずれはありませんでした。調べずにどちらのメールボックスにいるかは判断できないため、searchは各ヒットをそのライブラベルに対して再検証します。pageToken/nextPageTokenによるページネーション対応。スケールする一括操作。
bulk_modifyは、クエリに一致するすべてをAPIリクエストあたり1000メッセージでアーカイブ/ラベル付けします — オールオアナッシングではなく、チャンクごとの部分成功レポート付き。スヌーズスイープも同じバッチパスを使用します。構造化された出力。 すべてのツールは
outputSchemaを宣言し、検証済みのstructuredContentをフェンス付きJSONテキストとともに返します — クライアント側での解析の推測は不要。小さな攻撃面。 送信ツールなし(プロンプトインジェクションされたメールの流出経路なし)、オプションの読み取り専用モード、テレメトリなし、デフォルトで開いているポートなし、シンボリックリンク安全なダウンロードフェンシング、インジェクション対策済み出力。意図的な例外が1つ:
unsubscribe/bulk_unsubscribe(管理ティア)は、メッセージ自身のヘッダーに記載されたオプトアウトエンドポイントに連絡します — mailwardenが到達する唯一の非Googleホストであり、readティアのデプロイメントでは外部へのリクエストは一切行いません。詳細はセキュリティとプライバシーおよび購読解除を参照。現実のメールで正しく動作。 RFC 2047ヘッダーをデコード(
=?UTF-8?B?…?=→ 可読テキスト)、ボディを宣言された文字セットでデコード(ISO-8859-1/Shift_JISのメールで文字化けなし)、429/5xxは指数バックオフでリトライ。
Related MCP server: Gmail MCP
理由
メールボックスを同期またはキャッシュするコネクタは、メールボックスに遅れる可能性があります — そしてGmail自身の検索インデックスでさえも緩いことがあります(以下参照)。mailwardenはライブのGmail APIに直接話しかけ(キャッシュされたスナップショットなし)、インデックスが返すものを再検証するため、表示されるものは実際にそこにあるものです。これは汎用的なGmail機能レイヤーです — 独自のルール/ロジックはAIクライアントに保持し、サーバーには保持しません。
searchは生のAPIよりも一歩進んでいます:Gmailのthreads.listインデックスは、読み取り状態演算子に古いコピーから答えることができるため、is:unreadは何週間も前に読み終えたスレッドを返します — 測定した1つのメールボックスでは、返ってきたものの大部分がそうでした。すべてのヒットはライブで取得されるため、searchはあいまいでない述語(is:unread/is:read/is:starred/in:inbox/category:…、否定を含む)を各スレッドの真のラベルに対して再チェックし、インデックスの偽陽性を破棄します。
他のGmail MCPサーバーとの比較
ほとんどのGmail MCPサーバーは同じ読み取り/ラベル/送信の表面をカバーしています。2つの機能はまだmailwardenに固有のもの(メールボックスサイドのスヌーズ、検索再検証)であり、1つの意図的な省略はセキュリティ機能であり、ギャップではありません。Google自身のサーバーも見た目よりも狭いです:ドラフトのみで、ゴミ箱、フィルター、購読解除はありません。
機能 | mailwarden | ||||
メールボックスサイドのスヌーズ — 今すぐアーカイブし、日付/時間またはプリセットで受信箱に再表示 | ✅ | — | — | — | — |
検索結果の再検証 — スレッドインデックスの偽陽性をライブラベルに対して破棄 | ✅ | — | — | — | — |
クエリに対するスイープ/一括操作 — 検索が返すすべてのスレッドに1つのアクション | ✅ 1000/req、部分成功 | — | ⚠️ 明示的なIDによるバッチ | — | ⚠️ 明示的なIDによるバッチ |
購読解除 — 送信者ごとの概要 + RFC 8058 ワンクリックオプトアウト、送信スコープ不要 | ✅ | — | ⚠️ ヘッダー表示のみ、アクションなし | — | — |
受信箱トリアージ概要 — 1回の呼び出しで待機中のものを分類 | ✅ 送信者/ラベル/経過時間 + ヘッダーシグナル | — | — | ✅ ヒューリスティックフラグ + 統計 | — |
サーバーサイドフィルター — アシスタントなしでトリアージを継続するルール | ✅ 転送なし | — | ✅ | — | ✅ |
送信ツールなし — 設計による — プロンプトインジェクションされたメールに流出経路なし | ✅ 作成機能なし | ⚠️ ドラフトのみ | ❌ 送信あり | ❌ 送信あり | ❌ 送信あり |
最小権限ツールティア — 有効にしたツールから派生するOAuthスコープ | ✅ | ⚠️ スコープ分割 | — | — | ⚠️ 逆:許可されたスコープによってツールが制限 |
保存時のトークン暗号化(オプション) | ✅ AES-256-GCM | n/a(ホスト型) | ✅ | — | — |
ベンダークラウドなし — 自分でサーバーを運用 | ✅ | ❌ Googleホスト | ✅ | ✅ | ✅ |
構造化された出力 — すべてのツールが | ✅ | — | — | — | — |
2026年8月16日時点のスナップショット。各プロジェクトの公開ドキュメントとソースから取得。— = 提供されていない/文書化されていない。列は、読者が最も到達しやすいであろうサーバー — Googleのファーストパーティのもの、2つの最大のコミュニティサーバー — そしてklodr(mailwarden自身の最小権限設計に最も近いもの)です。送信機能はセキュリティプロパティとしてリストされています:mailwardenにそれが欠けているのは意図的です(セキュリティとプライバシーを参照)。最後の行は、サーバーがどこで実行されるかではなく、誰が運用するかを尋ねています:セルフホスティングはここでの共通点であり、この表のすべてのコミュニティサーバーは、klodr(stdioのみ)を除いて、何らかのリモートデプロイメントを提供しています — mailwardenは--http、taylorwilsdonはOAuth 2.1を備えたストリーム可能なHTTP、a-bonusはCloud Run上。自分のホストでそれらの1つを実行することはクラウドコピーではありません。ベンダーの上で実行することはクラウドコピーです。
堀は単一の行ではありません — それはスヌーズ + ライブ再検証の組み合わせです:キャッシュされたスナップショットではなく、メールボックスの現在の状態に作用する実際の受信箱ワークフローレイヤー。他のサーバーが追いついたところは、上記で正直に述べられています:保存時の暗号化(taylorwilsdon)、スコープ駆動のツールゲート(klodr)、よりリッチなメッセージごとのトリアージヒューリスティック(a-bonus)、およびメールボックス全体の一括整理(ホスト型のmcpemails.com、こちらにもスヌーズはありません)。しかし、それらのどれもクエリに基づいて行動し、その前にメールボックスの答えを確認することはありません。
なぜ再検証が重要なのか — 具体的なケース
アシスタントに*「既に受信箱をスキップした未読のプロモーションメールをアーカイブして」*と依頼すると、アシスタントは明白なクエリcategory:updates is:unread -in:inboxに手を伸ばします。Gmailのインデックスを信頼するサーバーは、今あなたが既に読んだスレッドをアーカイブします — 触れるつもりのなかったメールが、簡単に元に戻せない一括アクションで消えてしまいます。
主張ではなく測定。 1つの実際のメールボックス(約70,000メッセージ)、2026年8月15日、読み取り専用:
クエリ ( | 返されたスレッド数 | 未読メッセージがあるもの | 古いもの |
| 131 | 17 | 87% |
| 128 | 14 | 89% |
| 235 | 99 | 58% |
インデックスは述語を無視しているわけではありません。同じクエリで is:unread を外すと800以上のスレッドが返されるため、述語は適用されています。ただし、それは追いついていないスレッドレベルの既読状態に対して適用されています。つまり、すべてのメッセージが既読であるスレッドでも、そこで未読としてカウントされています。返されたスレッドの1つには、単一のラベル SENT が付いていました。これは特殊な演算子の組み合わせによる奇妙な動作ではありません。3つのクエリの中で最もシンプルなものにも同じ現象が見られます。その割合は最も低い(58%)ものの、絶対数で最も多くの誤ったスレッド(136件)が含まれています。
問題は特にスレッドインデックスにあります。 同じクエリ、同じメールボックス、同じ時間に messages.list で実行した場合:19メッセージ、古いものはなし。 つまり、これは「Gmailの検索が信頼できない」という話ではなく、スレッドの既読状態のビューが遅延する一方で、メッセージごとのビューは遅延しないということです。search は threads.list を経由するため、まさにそれが再検証を行う理由です。
別のメールボックスを同じ日に同じ方法で測定したところ、まったくずれはありませんでした — is:unread に対する生のインデックスヒットはゼロでした。ただし、このメールボックスは1日に何度もAPIを通じて既読マークが付けられています。つまり、これはGmail全体の性質ではなく、あるメールボックスの性質です。何が両者を分けているかは明らかではありません。ボリューム(およそ3桁の差)と経過期間が異なり、2つ目のメールボックスにはもっと基本的なものが欠けています。つまり、未読のままアーカイブされたスレッドが1つもないことです。これこそが古い既読状態が現れる唯一の形です。したがって、これは特定の原因に対する反例ではなく、単に該当する状態を持たないメールボックスです。
これこそが要点です。サーバーは自分がどの種類のメールボックスにいるのかを知ることはできません。 再検証は、ずれが生じないメールボックスでは何のコストもかからず、ずれが生じるメールボックスでは問題を解決します。上記の測定では、search が除外したすべてのスレッドは実際に既読であり、本当に未読のメールは1つも破棄されませんでした。
コストがかかる場合:一括ツール。 search はヒットをすべて取得するため再検証します。bulk_modify(および create_filter の applyToExisting スイープ)は数千のメッセージ単位でサイズ設定されており、ヒットごとに1回のフェッチを行うとコストの桁が異なります。これらはインデックスが返すものに基づいて動作するため、現在は unverifiedPredicates を報告します。これは、インデックスの情報をそのまま受け入れたクエリの条件(+UNREAD、-INBOX、…)です。空の場合は、信頼できないものがないことを意味します。空でなく、結果が既読状態として正確である必要がある場合?最初に search でセットを解決し、それらのスレッドIDに対してアクションを実行します。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その隣に2つ目のスクリプト node scripts/probe-reverify.mjs があります。これは、偽のメールボックスではなくあなたのメールボックスで同じことを測定します。読み取り専用で、メタデータのみ(件名、送信者、本文は取得しません)を取得し、カウントとラベル名を出力します。上記の数値はこれによって生成されたものであり、あなたのメールボックスがずれるかどうかを確認する方法です。
デモは、インデックスが意図的に古くなっている(is:unread クエリに対して既読のスレッドを返す、まさにGmailが行うように)偽のGmail APIに対して実際の search() を駆動し、mailwardenが誤検出を除外することを示します。結果をアサートするため、動作が後退した場合にはゼロ以外の終了コードで終了します。同じケースは、test/gmail.test.ts の単体テスト(「ライブラベルの再検証によるインデックスの誤検出の除外」)によっても保証されています。
ツール
ツール | 機能 |
| Gmailクエリ構文 → スレッドサマリー(差出人/件名/日付/ラベル/スニペット); 既読状態/カテゴリ述語は各ヒットのライブラベルに対して再検証されます; |
| 完全なスレッド: ヘッダー、プレーンテキスト + HTML本文、添付ファイルメタデータ |
| すべてのラベル(システム + ユーザー) |
| 接続アカウントのアドレス + メッセージ/スレッドの総数 — 操作前にどのメールボックスが接続されているか確認 |
| 決定のためのメールボックススライスの構造化概要: トップ送信者(各スレッドが持つシグナル付き)、ラベルと経過時間のバケット、未読 + 添付ファイル数、ニュースレター/自動/カレンダー招待/返信先不一致のスレッド数 — 生のスレッドリストの代わり |
| スレッドが宣伝するオプトアウトオプション( |
| 送信者ごとにグループ化されたメールボックススライス: スレッド/未読数、各送信者が確認された日付範囲、各送信者のオプトアウトオプション — 送信者ごとに1回のヘッダーフェッチ、誰にも連絡しない。 |
| ユーザーラベルを作成(冪等; |
| 名前またはIDでラベルを追加/削除 — |
| クエリに一致するすべてのメッセージに対するバッチラベル変更 — APIリクエストあたり1000メッセージ、チャンクごとに部分成功を報告(スレッドIDリストは最大500、 |
| 便利なラッパー |
| ゴミ箱に移動 / ゴミ箱から復元 |
| 添付ファイルをローカルパスに保存(上書きはしない — 競合時は数値サフィックスが付与) |
| メッセージのヘッダーからのエンドポイントを使用したワンクリックオプトアウト(RFC 8058)— Google以外のホストに連絡する唯一のツール(詳細) |
| 複数のスレッドに対して同様の処理を順次実行し、送信者ごとに最大1リクエスト; スレッドごとに部分成功を報告。 |
| 今すぐアーカイブし、日付( |
| スヌーズをキャンセルし、今すぐ受信トレイに戻す |
| すべてのスヌーズされたスレッド + 期限日 |
| スヌーズ期限が切れたスレッドを再表示(オンデマンド、cron、またはデーモンで実行); バッチ処理、部分失敗報告あり。 |
| すべてのGmailフィルター(条件 + ラベルアクション); 既存のフィルター上の |
| サーバーサイドの自動トリアージルールを作成(条件 → ラベルアクションのみ; 転送なし — 以下参照)。オプションで |
| IDでフィルターを削除 |
すべてのツールは outputSchema を宣言し、構造化コンテンツ(検証済み、機械可読)を同じJSONとともにフェンス付きテキストとして返します。クライアントが散文をパースする必要は決してありません。
snoozeの仕組み(Gmail APIにsnoozeは存在しません — 私たちが構築します)
snoozeはINBOXを削除し、日付ラベルMCP/Snoozed/<key>を適用します。ここで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は期限切れのラベルを見つけ、それらのスレッドを受信箱に戻し(未読としてマーク)、時間指定のsnoozeはその分以降の最初のスイープで起動されるため、起動レイテンシはスイープ間隔に等しくなります。スイープを実行します:
オンデマンド(
sweep_snoozedツール)、cron経由:
mailwarden --sweep、または自動で:
MAILWARDEN_AUTO_SWEEP=1(サーバー実行中は1時間ごとにスイープ)を設定。
フィルター(永続的な自動トリアージルール)
create_filterはGmailサーバー側ルールを設定します。条件に一致するメールは自動的に指定されたラベルアクションを取得します — アシスタントがループに入ることなく、メールボックスは自己トリアージを続けます。
条件:
from、to、subject、query(完全なGmail検索構文)、negatedQuery、hasAttachment、excludeChats、およびsize+sizeComparison(smaller/larger、一緒に指定)。少なくとも1つが必要です。アクション(ラベルのみ):
addLabels/removeLabels、名前またはIDで指定(addLabelsの未知の名前は自動生成され、/でネストされます)。一般的なレシピ:受信箱をスキップ →removeLabels: ["INBOX"];自動既読マーク →removeLabels: ["UNREAD"];自動ゴミ箱 →addLabels: ["TRASH"];スター →addLabels: ["STARRED"];迷惑メール除外 →removeLabels: ["SPAM"];ラベルの下にファイル →addLabels: ["Receipts"]。既存のメール: フィルターは作成後に到着するメッセージにのみ実行されます。
applyToExisting: trueを渡すと、同じアクションをメールボックス内の既存のメールにも一度適用します — mailwardenは条件からGmail検索を構築し、一括変更を実行します(最大maxMessages、デフォルト1000;bulk_modifyと同じ未検証インデックスの注意事項、および1回限りのパスは迷惑メール/ゴミ箱を除外します)。これには少なくとも1つの肯定的な条件(from/to/subject/query/hasAttachment:true/size)が必要です:除外のみのルール(negatedQueryまたはhasAttachment:false)はapplyToExistingには拒否されます。これはメールボックス全体にほぼ一致するためです — そのようなフィルターはフラグなしで作成してください。結果はappliedの下に返されます(使用されたquery、matchedMessages/modifiedMessages/modifiedThreadCountカウント、マッチセットがmaxMessagesに達した場合のcapped、チャンクごとのfailed、およびパス全体が失敗した場合のerror文字列);applyToExistingが設定されていない場合はnullになります。フィルターは最初に作成されるため、部分的なまたは失敗したバックログパスは報告され、appliedでエラーとして発生することはありません — ルールは引き続き有効です。転送なし — セキュリティとプライバシーを参照。
gmail.settings.basicスコープが必要です;古いバージョンを認可した場合は、--authを再実行してください。読み取り専用モードでは利用できません。
購読解除 — 唯一の送信リクエスト
list_unsubscribe(読み取り層)は、誰にも連絡せずに、送信者が提供するものを報告します。実際にList-Unsubscribeヘッダーを持つ最新のメッセージを読み取ります — ニュースレターにスレッド化された返信は末尾にあり、何も広告しませんが、そうでなければ「このリストにはオプトアウトがない」と読み取られます。list_subscriptions(読み取り層)は、送信者ごとにグループ化されたスライス全体で同じことを行うため、誰が書き続けていて、そのうちの誰が実際に離れることができるかを確認できます — スレッドごとではなく送信者ごとに1つのヘッダーフェッチです。unsubscribeおよびbulk_unsubscribe(管理層)はそれに基づいて動作します — そしてそれがmailwardenがGoogle以外のホストと通信する唯一の場所であるため、ルールは厳格です:
URLパラメータはありません。 エンドポイントはメッセージ自身のヘッダーからのみ取得され、他の場所からは取得されません。URL引数は、プロンプトインジェクションされたメールがツールを不正なチャネル(クエリ文字列内のメールボックスコンテンツ)に変えることを許します;ヘッダーはモデルが選択したデータを運ぶことはできません。
RFC 8058 one-clickのみ実行されます — 送信者は
List-Unsubscribe-Postを介してオプトインしている必要があります。プレーンなhttps:リンクはブラウザの人間向けであり、フェッチされずに返されます。mailto:オプトアウトは決して実行されません。 メールの送信が必要になりますが、mailwardenはそれができません。アドレスは報告されるため、自分で行動できます。固定リクエスト、破棄された応答。 POST本文は常に
List-Unsubscribe=One-Clickであり、他のものから派生することはありません;応答本文は読まれずにキャンセルされます。モデルに返されるのはステータスコードと実際に呼び出されたURLのみです — エンドポイントからのコンテンツはなく、指示で応答することはできません。(301/302/303リダイレクトはGETとして、つまり本文なしで追跡されます。)送信者ごとに1リクエスト、順次、1つの予算内。
bulk_unsubscribeはスレッドIDを受け取ります(クエリは受け取りません — クエリ駆動の一括操作は、誰も見る前にマッチした送信者ごとにリクエストを発射します)。リクエストが既に送信された送信者からのスレッドは、duplicateOfで報告され、2回目のリクエストはかかりません:1つのリストからの2つのスレッドはオプトアウトを共有し、2回呼び出すとアドレスが2回確認されるだけです。送信者は、リクエストが実際にエンドポイントに到達した場合にのみ記録されるため、拒否または接続切断が発生しても、次のスレッドは独自の試行を保持します — そして、スキップされたスレッドが異なるエンドポイントを広告している場合、理由はそれを示します。なぜなら、1つの送信者が複数のリストを実行できるからです。1回の呼び出しにつき25スレッドと60秒の上限;予算がカバーしなかったものは、黙って元に戻されずにskippedOutOfTimeとして返されます。これらのいずれも元に戻せないため、3つの制限すべてが存在します。SSRFガード。 httpsのみ、デフォルトポートのみ、URL内に資格情報なし、そしてすべてのホップ — 最大3回追跡されるリダイレクトを含む — はグローバルに到達可能なアドレスにのみ解決されなければなりません。チェックは各アドレスをバイトに解析し、IANA特殊目的レジストリと照合するため、同じアドレスのすべての綴りは同じ判定を得ます(
::1と0:0:0:0:0:0:0:1も同様);解析できないアドレスは拒否されます。DNS解決とすべてのホップは、1つの10秒の予算を共有します。リバインディング耐性はありません(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-onlyデプロイメントはlist_unsubscribeとlist_subscriptionsを取得し、リクエストを決して行いません。
セキュリティとプライバシー
完全な脅威モデル — 信頼境界、脅威ごとの緩和策、明示的な非目標、および脆弱性の報告方法については、**SECURITY.md**を参照してください。ハイライト:
テレメトリなし。 何も外部に送信しません — 分析、クラッシュレポート、トラッキングは一切ありません。
デフォルトではポートを開かない。 stdioのみ。オプションの
--httpリスナーは127.0.0.1(LANではない)にバインドし、MAILWARDEN_TOKENベアラートークンがないと起動を拒否します — 信頼できる隔離ネットワーク上で上書きするにはMAILWARDEN_ALLOW_NO_TOKEN=1を設定します。ループバックバインドではHostヘッダーも検証します(DNSリバインディング防御)。リモートホスティングの場合はMAILWARDEN_HOSTを設定し、TLSで前面に配置します。送信ツールなし — 設計による。 mailwardenは作成、返信、転送ができません。メール内のプロンプトインジェクションされた指示は、このサーバーを通じて外部に漏洩する経路がありません。
create_filterも同じルールに従います:ラベル付け、アーカイブ、ゴミ箱、スター、既読/未読のマークはできますが、決して 転送 フィルター(漏洩経路になる)を作成しません。list_filtersはアカウントに既にある転送フィルターを表示するので、発見できます。これは、そのようなツールが存在せず、実行時に登録できないためです。mailwardenが拒否するのではなく、Google が送信を拒否するより強力なバリアントについては、下記の 読み取り専用モード を参照してください。1つの送信先ホスト、モデルが選択したURLはなし。
unsubscribeツールは、Google以外のホストに接する唯一のコードパスです。そのエンドポイントはメッセージのList-Unsubscribeヘッダーから読み取られます — ツール引数からではありません — リクエストボディは固定され、レスポンスボディは破棄されるため、データチャネルにはなりません。https/デフォルトポートのみ、リダイレクトは再検証され、プライベート、ループバック、リンクローカル、メタデータアドレスに解決されるホップは拒否されます。購読解除 を参照してください。ツール階層(段階的開示+最小スコープ)。
MAILWARDEN_TOOLSは指定した階層のみを通知します —read(読み取りツール)、manage(メールボックスの変更、スヌーズ、ダウンロード)、filters(サーバーサイドフィルターのCRUD、ツールがgmail.settings.basicを必要とする唯一の階層)。デフォルトは3つすべて。例:read,manageはフィルター管理なしで完全なトリアージ面を提供します。--authで要求されるOAuthスコープは有効な階層から導出されます —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が設定されている場合、添付ファイルの書き込みはそのディレクトリに制限され(realpathで正規化、シンボリックリンク対応)、既存のファイルを上書きすることはありません。信頼できないコンテンツの隔離。 すべてのツール結果は
<untrusted-tool-output>マーカーで囲まれ、不可視文字/BiDiオーバーライド文字が除去されるため、クライアントは引用されたメールコンテンツと指示を区別できます。ライブAPI、コピーなし。 メールボックスのミラーや検索インデックスはどこにも保存されません。唯一のローカル状態は
~/.mailwarden/内のOAuthトークンです。オプションの保存時トークン暗号化。
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同意画面を設定し、本番環境に公開(テスト ステータスでは、Googleはリフレッシュトークンを7日後に期限切れにします) → タイプ デスクトップアプリ の OAuthクライアントID を作成 →
credentials.jsonとしてダウンロード。credentials.jsonを~/.mailwarden/に配置する(またはMAILWARDEN_CREDENTIALS=/path/to/credentials.jsonを設定する)。一度認可する — ブラウザが開き、リフレッシュトークンを
~/.mailwarden/token.jsonに保存します:
npx -y mailwarden --auth要求されるスコープ:gmail.modify(読み取り+ラベル/アーカイブ/ゴミ箱)および gmail.settings.basic(フィルター管理のみ)。フィルターが存在する前のバージョンを認可した場合は、--auth を一度再実行して追加されたスコープを付与してください。Gmail自体が送信を拒否するトークンを保持するには、MAILWARDEN_TOOLS=read で認可してください — 上記の 読み取り専用モード を参照。
4. セットアップを確認 するには、いつでも組み込みのドクターを使用します:
npx -y mailwarden --checkこれは credentials.json をチェックし、トークンが存在するか(および暗号化されているか)、付与されたスコープが有効な階層をカバーしているか、そしてトークンがまだ機能することを証明するために1回のライブGmail呼び出しを行います — 問題がある場合は具体的な修正方法を出力し、その場合は非ゼロで終了します(CI/ヘルスチェックで便利)。一般的なトラップを診断します:認証情報ファイルがない/間違っている、認可されていない、MAILWARDEN_TOKEN_PASSPHRASE なしの暗号化トークン、スコープの欠落、または7日間の「テスト」同意トークンの期限切れ。
接続
Claude Code(ローカル stdio):
claude mcp add mailwarden -- npx -y mailwardenClaude Code プラグイン — 同じサーバーに加えて、OAuthセットアップを案内し、壊れたものを診断する /mailwarden:setup スキルが含まれています。リポジトリルートがプラグイン(.claude-plugin/plugin.json)なので、クローンから:
claude --plugin-dir /path/to/mailwardenこれはAnthropicのコミュニティマーケットプレイスに提出されています。リストされると、/plugin marketplace add anthropics/claude-plugins-community の後 /plugin install mailwarden@claude-community でクローンなしで同じことができます。プラグインは完全なツールサーフェスを実行します — より狭い階層(MAILWARDEN_TOOLS=read)や2つ目のアカウントの場合は、代わりに希望の環境変数を使用して claude mcp add を使用してください(設定 および 複数アカウント を参照)。
Claude Desktop — claude_desktop_config.json に追加:
{
"mcpServers": {
"mailwarden": { "command": "npx", "args": ["-y", "mailwarden"] }
}
}または、MCPBバンドル(mailwarden-<version>.mcpb、0.10.0以降の GitHubリリース に添付)をデスクトップ拡張機能としてインストールします — 設定 → 拡張機能 → 拡張機能をインストール… — 同じサーバーで、実行時に自己完結型(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 configSmitheryの2つのパスのどちらを取るかに注意してください。上記のインストールはプレーンなローカルサーバーエントリを書き込みます:プロセス、トークン、メールは 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で:設定 → コネクタ → カスタムコネクタを追加 → あなたの https://your-host/mcp URL。Claude Codeでは:claude mcp add --transport http mailwarden https://your-host/mcp。
複数アカウント
1つのOAuthアプリ(1つの credentials.json)で複数のGmailアカウントを認可できます。各アカウントは独自のリフレッシュトークンを別々のファイルに保持し、MAILWARDEN_ACCOUNT で選択されます:
mailwarden --auth --account work # stores token.work.json
mailwarden --auth --account personal # stores token.personal.jsonサーバーを アカウントごとに1回 登録し、それぞれに独自の 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)。そのため、名前は常に正確に1つのメールボックスにマッピングされます。
--auth が書き込むファイルは --account / MAILWARDEN_ACCOUNT のみに依存し、ブラウザで選択したアカウントには依存しません。 --account なしで 2つ目のメールボックスを認可すると、最初のメールボックスのトークンファイルを直接狙うことになるため、--auth は最初にチェックし、別のメールボックスのトークンを置き換える代わりに 拒否 します。--force で意図的に上書きできます。2つのノブは交換可能ではありません:MAILWARDEN_ACCOUNT は1つの設定ディレクトリから複数のメールボックスを扱うためのもの(token.<name>.json を選択)、一方 MAILWARDEN_DIR はディレクトリ 全体 を移動します — セットアップを完全に分離するのに便利ですが、1つの中に2つ目のアカウントを提供するわけではありません。リポジトリクローンからの 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設定(環境変数)
変数 | 意味 |
| 設定ディレクトリ(デフォルト |
|
|
| 名前付きアカウントを選択(そのトークンは |
| パスフレーズ → |
|
|
|
|
|
|
| カンマ区切りで公開するツール階層を指定します: |
|
|
| 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