gmail-mcp
Gmail für deinen KI-Assistenten – mehrere Konten gleichzeitig, auf einem Server, der dir gehört.
gmail-mcp verbindet Gmail mit Claude und jedem anderen MCP-Client. Es kann E-Mails suchen und lesen, senden und Allen antworten mit zitiertem Verlauf, weiterleiten, Anhänge und Inline-Bilder verarbeiten sowie Entwürfe, Labels und Threads verwalten – über mehrere Google-Konten gleichzeitig.
Es läuft als entfernter Server auf deinem eigenen Cloudflare Worker, sodass dieselbe Verbindung von Claude Code auf einem Laptop, claude.ai im Browser und Claude auf dem Telefon aus antwortet. Jede Verbindung meldet sich bei einem Google-Konto an, und das Google-Refresh-Token bleibt in deinem Cloudflare-Konto.
Zwei Dinge treiben die Leute hierher. Die in Claude und Google integrierten Gmail-Konnektoren lesen E-Mails und schreiben Entwürfe, können aber nicht senden, und sie halten ein Google-Konto pro Assistentenkonto. Server, die senden können, sind normalerweise lokale Prozesse – am Schreibtisch in Ordnung, vom Telefon aus unsichtbar.
Vergleich
gmail-mcp | ||||||
Wo es läuft | Cloudflare Workers | vom Anbieter gehostet | dein Server oder lokal | lokal | lokal | lokal |
Vom Telefon aus erreichbar | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
Mehrere Postfächer gleichzeitig | ✅ pro Verbindung gebunden | ❌ | ✅ pro Aufruf wählbar | ❌ nur Aliase | ❌ | ✅ pro Aufruf wählbar |
E-Mails senden | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
Anhänge · Inline- | ✅ | undokumentiert | ✅ | ✅ | ❌ | ✅ |
Allen antworten mit zitiertem Verlauf | ✅ | ❌ | nur Entwürfe | kein Zitat | ❌ | ✅ |
Weiterleiten | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ |
Beachtet den Zeichensatz jedes Teils | ✅ | — | ❌ UTF-8 angenommen | ❌ UTF-8 angenommen | ❌ | ❌ |
Lehnt CRLF-Header-Injection ab | ✅ | — | ✅ Framework | ✅ entfernt | ❌ keine | ✅ |
Postfacheinstellungen (Filter, Abwesenheit) | ❌ außerhalb des Rahmens | ❌ | Filter | Filter | ✅ | ❌ |
Anzahl der Werkzeuge | 24 | 11–16 | 14 (Gmail) | 30 | 64 | 11 |
Wer dein Refresh-Token hält | du | Anbieter | du | du | du | du |
google_workspace_mcp ist das vollständigste Projekt hier. Es deckt ganz Workspace ab und nicht nur Gmail, und es hängt deine Gmail-Signatur an und ruft Anhänge direkt von einer URL ab – all das tut gmail-mcp nicht. shinzo-labs/gmail-mcp erreicht über seine 64 Werkzeuge Abwesenheitsantworten, Stellvertreter und S/MIME; diese liegen unter gmail.settings.*, einem Bereich, den gmail-mcp nie anfragt, sodass sie außerhalb seiner Reichweite bleiben, egal was mit einer Genehmigung passiert.
Zwei Designunterschiede entscheiden über den Rest. Konten über ein Aufrufargument zu routen, erlaubt es einer Genehmigung, jedes verbundene Postfach zu berühren, während das Binden des Postfachs an die Verbindung bedeutet, dass ein falsches Argument nichts erreicht. Und beim Lesen dekodieren die lokalen Server jeden Teil als UTF-8: ISO-2022-JP- und Shift_JIS-Mails kommen verstümmelt an, und lange Nachrichten, die Gmail als Anhangs-Blobs speichert, kommen mit leerem Text zurück.
Bereitstellen
Etwa zehn Minuten. Du brauchst ein Cloudflare-Konto, bun und ein Google-Konto. Eine Domain im Cloudflare-Konto ist optional – ohne eine antwortet der Worker auf workers.dev.
1 · Einen Google-OAuth-Client erstellen
PROJECT="gmail-mcp-$(openssl rand -hex 3)"
gcloud auth login
gcloud projects create "$PROJECT" --name="gmail-mcp"
gcloud config set project "$PROJECT"
gcloud services enable gmail.googleapis.comGoogle stellt für die nächsten beiden Schritte keine API bereit, also finden sie in der Cloud-Konsole statt:
OAuth-Zustimmungsbildschirm → External, dann unter Zielgruppe App veröffentlichen drücken. Im Testmodus lässt Google jedes Refresh-Token nach 7 Tagen ablaufen und jede Verbindung stirbt mit ihrem Token. Veröffentlicht zeigt die App beim Anmelden eine Warnung über eine unverifizierte App und bedient bis zu 100 Konten.
Anmeldedaten → Anmeldedaten erstellen → OAuth-Client-ID → Webanwendung, mit
https://<your-host>/callbackals autorisierter Weiterleitungs-URI. Client-ID und Secret behalten.
<your-host> ist die Domain, die Sie auf den Worker richten, oder der workers.dev-Hostname, den er andernfalls erhält. Zuerst bereitzustellen und später zurückzukommen, um das auszufüllen, funktioniert – die Anleitung, die der Worker unter / ausliefert, zeigt den genauen Wert.
2 · Worker bereitstellen
Der Button kopiert das Repository in Ihr GitHub-Konto, erstellt den KV-Namespace und das Durable Object und fragt nach den vier Secrets. Er stellt auf workers.dev bereit; eine eigene Domain wird anschließend unter Settings → Domains & Routes angehängt.
Stattdessen über ein Terminal:
git clone https://github.com/mkpoli/gmail-mcp && cd gmail-mcp
bun install
bun run setupbun run setup fragt, auf welcher Domain geantwortet werden soll, erstellt oder verwendet den OAUTH_KV-Namespace neu, nimmt Client-ID und Secret entgegen, generiert einen Cookie-Schlüssel und stellt bereit. Diese ersten beiden Antworten landen in wrangler.local.jsonc, das von git ignoriert wird – wrangler.jsonc nennt weder den Namespace eines Kontos noch die Domain von irgendjemandem, sodass ein Klon überall bereitgestellt werden kann. Das erneute Ausführen von Setup, um ein einzelnes Secret zu rotieren, ist sicher.
3 · Einen Client verbinden
Lassen Sie die Felder für Client-ID und Secret leer – MCP-Clients registrieren sich selbst.
claude mcp add --transport http gmail-personal https://<your-host>/mcp
claude mcp add --transport http gmail-work https://<your-host>/mcp/workFühren Sie /mcp in Claude Code aus, um jede Verbindung bei ihrem Google-Konto anzumelden. In claude.ai ist es Settings → Connectors → Add custom connector mit derselben URL. Jedes einsegmentige Label funktioniert nach /mcp/, wodurch eine Bereitstellung mehrere Postfächer für Clients bedienen kann, die zwei Server mit gemeinsamer URL ablehnen.
Ihre Bereitstellung bietet diese Anleitung unter https://<your-host>/.
Was es kann
whoami
search_messages
get_message
get_thread
get_attachment
send_message
reply_all
forward_message
create_draft
update_draft
send_draft
delete_draft
list_drafts
stage_attachment_begin
stage_attachment_append
stage_attachment_finish
list_labels
create_label
update_label
delete_label
modify_labels
modify_thread_labels
batch_modify_messages
trash_message · untrash_message
trash_thread · untrash_thread
Nachrichten verlassen das System so, wie ein Mail-Client sie sendet: Klartext mit einer HTML-Alternative, Dateianhänge und Inline-Bilder, die per cid: referenziert werden, verschachtelt als multipart/mixed › multipart/related › multipart/alternative. Betreffe und Anzeigenamen verwenden RFC 2047, Dateinamen RFC 2231, sodass Japanisch, Chinesisch und Emojis die Reise überstehen.
reply_all liest Reply-To, From, To und Cc des Originals, verwirft die eigene Adresse und jede Adresse, als die man Mails sendet, antwortet von der Adresse, an die der Absender geschrieben hat, führt die References-Kette weiter und zitiert das Original in den Teilen, die Sie senden. forward_message reproduziert den weitergeleiteten Umschlag und kann die Dateien des Originals erneut anhängen.
create_draft mit replyToMessageId schreibt die Antwort als Entwurf zum Bearbeiten vor dem Senden: Es tritt dem Thread des Originals bei, führt In-Reply-To und References weiter, leitet die Antwort-an-alle-Empfänger und den Re:-Betreff ab und zitiert das Original. update_draft ändert nur die Felder, die übergeben werden; Empfänger, Text, von Hand in jedem Client hinzugefügte Dateien und der Thread, auf den der Entwurf antwortet, werden zurückgelesen und beibehalten. Eine Datei, deren Base64 nicht durch Tool-Argumente passt, wird stattdessen gestaffelt: stage_attachment_begin gibt eine Upload-URL zurück, die die Rohbytes in einem einzigen curl -T entgegennimmt, stage_attachment_append nimmt Base64 in Blöcken entgegen, und jedes attachments-Feld akzeptiert die resultierende stagingId.
Das Lesen ist bewusst begrenzt: Nachrichten- und Thread-Bodies haben Zeichenbudgets, eine gesamte Antwort hat eine Byte-Obergrenze, und ein Anhang wird nur inline zurückgegeben, solange er klein genug zum Lesen bleibt. Ein langer Mailinglisten-Thread oder eine große Datei kommt abgeschnitten mit einem Hinweis zurück, statt den Kontext des Assistenten zu füllen.
So funktioniert es
Zwei OAuth-Flows treffen sich in einem Worker. Der MCP-Client authentifiziert sich gegenüber dem Worker; der Worker authentifiziert sich gegenüber Google in Ihrem Namen. Keine Seite hält die Anmeldedaten der anderen.
sequenceDiagram
autonumber
participant C as MCP client<br/>(Claude Code · claude.ai)
participant W as Worker<br/>(OAuthProvider + McpAgent)
participant G as Google<br/>(OAuth + Gmail API)
C->>W: POST /register (dynamic client registration)
C->>W: GET /authorize (PKCE challenge)
W->>C: approval dialog
C->>G: consent screen — pick the account
G->>W: GET /callback?code=…
W->>W: allowlist check on the verified email
W->>G: exchange code → access + refresh token
W->>C: MCP access token (Google tokens sealed inside the grant)
C->>W: POST /mcp — tools/call
W->>G: Gmail REST (token refreshed as needed)
G->>W: message / thread / label data
W->>C: tool resultEbene | Datei | Was sie tut |
🔐 MCP-seitiges OAuth | Dynamische Client-Registrierung, PKCE, Grants in KV mit den Google-Tokens darin versiegelt | |
🔗 Google-seitiges OAuth |
| Autorisierungscode mit Offline-Zugriff, Einmal-State gebunden an die Browser-Sitzung, Double-Submit-CSRF, Allowlist auf der verifizierten E-Mail |
🤖 Agent |
| Ein Durable Object pro MCP-Sitzung, gebunden an das Konto, das sie geöffnet hat; Single-Flight-Token-Refresh, gedrosselter Fan-out |
| RFC 822-Konstruktion, MIME-Baumdurchlauf, Zeichensatz-Dekodierung, Antwort- und Weiterleitungs-Komposition |
Erstellt mit
TypeScript auf Cloudflare Workers – Durable Objects halten je eine MCP-Sitzung, KV hält die OAuth-Grants
Hono – Routing für die OAuth-Endpunkte, den Google-Callback und die Einrichtungsseite unter
/@cloudflare/workers-oauth-provider– der OAuth-2.1-Server, gegen den sich MCP-Clients registrierenagents–McpAgent, der MCP-Transport über Durable Objects@modelcontextprotocol/sdkmit Zod – Tool-Definitionen und ArgumentvalidierungBun, Biome, Wrangler – installieren, testen, linten, bereitstellen
Gmail selbst wird über einfaches fetch gegen die REST-API aufgerufen. Das offizielle googleapis-SDK setzt Node voraus und bringt weit mehr mit, als ein Worker ausliefern sollte, daher leben Nachrichtenaufbau, MIME-Parsing und Token-Refresh stattdessen in src/gmail.ts und src/utils.ts.
Endpunkte
Pfad | Zweck |
| MCP-Endpunkt |
| Derselbe Server unter beliebigem einsegmentigem Label, für Clients, die zwei Server mit gemeinsamer URL ablehnen |
| Diese Einrichtungsanleitung |
| OAuth-Mechanik |
Wer sich anmelden kann
ALLOWED_EMAILS entscheidet, geprüft gegen die Adresse, die Google als verifiziert meldet – nach der Zustimmung, bevor ein Grant existiert.
Wert | Wer hineinkommt |
(leer) | niemand |
| diese Konten |
| jeder in dieser Domain |
| jedes verifizierte Google-Konto |
Jeder Grant erreicht nur das Postfach, das ihn authentifiziert hat, sodass eine Erweiterung dieser Liste den Zugriff auf bereits verbundene Postfächer nie erweitert. Die Einstellung von * lässt Fremde Ihre Bereitstellung und das Kontingent Ihrer Google-Client-ID für ihre eigene Mail nutzen.
Grenzen
Zwei Obergrenzen verhindern, dass eine gemeinsame Bereitstellung ausgeschöpft wird, beide festgelegt in wrangler.jsonc:
Einstellung | Wo | Standard | Was sie begrenzt |
|
|
| Ungefähr, wie viele verschiedene Google-Konten jemals die Anmeldung abschließen dürfen. Bereits verbundene Konten funktionieren weiter, wenn das Limit erreicht ist; neue werden abgewiesen. Gleichzeitig eintreffende Anmeldungen lesen den Zähler jeweils, bevor einer von ihnen aufgezeichnet wird, sodass die Gesamtzahl etwas über dieser Zahl liegen kann. Google begrenzt unverifizierte Apps auf 100 Benutzer, also lassen Sie darunter Platz. |
|
|
| Gmail-Aufrufe, die ein Konto in diesem Fenster über alle seine Sitzungen hinweg machen darf. Cloudflare führt diesen Zähler pro Standort, sodass ein Konto, das sich aus zwei Regionen verbindet, in jeder ungefähr so viele erhält. Ein breites Lesen verbraucht mehrere: |
|
|
| Client-Registrierungen, die eine Adresse in diesem Fenster machen darf. Ein Client registriert sich einmal und behält die ihm zugewiesene ID, sodass die normale Nutzung diesem Limit nie nahekommt; die Obergrenze existiert, weil die Registrierung keine Anmeldedaten benötigt und jeder Vorgang in KV schreibt. |
Im Workers-Free-Plan gilt eine weitere Obergrenze: 50 ausgehende Requests pro Aufruf. Ein breiter Lesevorgang verbraucht einen pro Nachricht, daher sollten search_messages und list_drafts dort einen maxResults von 45 oder darunter anstreben; darüber hinaus kommt der Überschuss als Fehler pro Nachricht zurück, statt als Ergebnisse. Der bezahlte Tarif erlaubt 1000.
Erhöhe einen der beiden Werte und deploye erneut. Der Rate-Limiter von Cloudflare liest seine Obergrenze zur Build-Zeit aus dem Binding, daher ist das simple.limit an jeder Stelle der einzige Ort, an dem sie geändert wird. Ein Einzelbenutzer-Deployment kann beide Werte unangetastet lassen – die normale Assistenten-Nutzung liegt weit darunter.
Sicherheit
Selfhosting verschiebt die Vertrauensfrage, löst sie aber nicht auf. Hier ist also die Gesamtübersicht.
Deine Tokens bleiben deine. Die Refresh-Tokens sind innerhalb ihres OAuth-Grants in deinem KV-Namespace verschlüsselt. Das Durable Object einer Sitzung hält das eine Stunde gültige Access Token, und des MCP-Agent-Frameworks eine Kopie des Grants, solange das Objekt lebt, inklusive des Refresh-Tokens. Beide Speicher liegen in deinem eigenen Cloudflare-Konto und sind im Ruhezustand verschlüsselt. E-Mails werden nie gespeichert – sie werden nur durchgeschleust.
Eine Sitzung, ein Postfach. Die MCP-Sitzung ist an das Konto gebunden, das sie geöffnet hat; ein Grant für ein Postfach kann also nicht durch eine ausgeliehene Sitzungs-ID auf ein anderes einwirken.
Scope-Minimalismus.
gmail.modifydeckt Lesen, Senden, Labels und Papierkorb ab. Ausgenommen sind der dauerhafte Löschung und alles ausgmail.settings.*. Damit bleiben Auto-Forwardingregeln und Filter-Exfiltration – die klassischen Postfach-Hintertüren – außerhalb dessen, was ein gestohlener Grant tun könnte. Zwei Nur-Lese-Scopes werden dazu angefordert,userinfo.emailunduserinfo.profile: Sie sind dafür da, dass die Allowlist und die Sitzungsbindung erkennen, welches Konto sich angemeldet hat, und sie erreichen keine E-Mails.Header können nicht eingeschleust werden. Jeder ausgehende Header-Wert wird abgewiesen, wenn er CR, LF oder NUL enthält. Kein Argument kann also aus seinem eigenen Feld ausbrechen, um ein zusätzliches anzuhängen – etwa, indem ein
Bccin eine Betreffzeile platz. Medientypen werden validiert und der zitierte Verlauf wird HTML-escaped. Welche Argumente selbst überwacht werden, ist damit nicht möglich:bccist ein echter Parameter, ein Modell, das einer in einem Nachrichtentext versteckten Anweisung folgt, es also trotzdem ausfüllen – eine Genehmigungsabfrage des Kunden ist die Kontrollinstanz dafür.Zugriff kann entzogen werden. Wer den Umfang von
ALLOWED_EMAILSeinschränkt, unterbindet neue Anmeldungen. Ein einzelner Zugriff wird auf myaccount.google.com/connections widerrufen. Das Rotieren der Google-Client-Secret macht alle Grants schlagartig ungültig.
Der Worker entschlüsselt die Mail im Speicher, während eine Anfrage verarbeitet wird, wie es jeder gehostete Relay muss. Wenn das für ein bestimmtes Postfach nicht akzeptabel ist, betreib für dieses eineneinen ein lokalen MCP-Server.
Wie es getestet wurde
253 Unit-Tests decken ab: Nachrichtenkonstruktion (MIME-Verschachtelung, RFC-2047-Umbruch, RFC-2231-Dateinamen, CR/LF-Abweisung, Base64-Umbruch), Textkörper-Extraktion über Zeichensätze hinweg, das Verfassen von Antworten und Weiterleitungen, die Google-Token-Flüsse, die Anmelde-Allowlist, die CSRF- und State-Binding-Prüfungen, die die Browser-Seite der Anmeldung absichern, sowie die Werkzeuge selbst gegen eine Gmail-Attrapie – Sitzungsbesitz, Zusammenstellung der Empfänger, Anhangauswahl und was bei einem teils fehlgeschlagenen Lesevorgang zurückkehrt.
Darüber hinaus wurde jedes Tool gegen echte Gmail-Konten getestet, wobei ein separates Konto prüfte, was wirklich ankam:
Bereich | Ergebnis |
Encoding | Japanische Betreffe gefaltet über encoded words; Emoji, ZWJ-Sequenzen, RTL- العربية, kombinierende Zeichen und seltene CJK-Zeichen unverändert durch den Round-Trip |
Anhänge | Eine CSV namens |
Threading |
|
Zwei Konten | Beide gleichzeitig mit einem Deployment verbunden; eine Nachrichten-ID von einem Konto lieferte auf dem anderen |
Organisieren | Ein verschachteltes CJK-Label wurde erstellt, umbenannt, per Stapel angewendet und gelöscht; das Löschen des Verlaufs wurde in beide Richtungen prüft und der Thread wie die Nachricht wiederhergestellt |
Skalierung | Ein Postfach mit 15.000 Nachrichten durchsucht mit Gmail-Operatoren und Pagination alle durchsucht, ohne das Limit zu treffen |
Entwicklung
bun run dev # wrangler dev on :8788
bun run check # biome + tsc
bun test # 253 unit tests
bun run assets # regenerate the light and dark diagrams
bun run deployFragen und Fehler
Eröffne ein Issue.
Lizenz
Copyright © 2026 mkpoli. Veröffentlicht unter der MIT-Lizenz.
src/workers-oauth-utils.ts ist abgeleitet von der remote-mcp-github-oauth-Demo aus cloudflare/ai, Copyright © 2025 Cloudflare, Inc., bei der Nutzung im Fall der unter MIT-Lizenz. Siehe THIRD-PARTY.md.
This server cannot be installed
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Shipmail MCP server for AI agent custom-domain email inboxes with REST API and webhooks.
Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.
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/eubin-create/gmail-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server