NexusAGYmail
Gmail for Google Antigravity, safe to leave alone. Antigravity's store has no Gmail connector: one local MCP
server, nexus-agymail, gives it your Gmail through the official Gmail API: search, read, attachments, drafts,
labels, a reversible trash, and sending a draft only after your explicit yes for that exact draft. Nothing is
ever deleted for good.
- Same tools as Google's official Gmail MCP server (
search_threads,get_message,get_thread,create_draft,label_message...), so an agent that knows one knows the other, without enrolling in the Workspace Developer Preview or enabling a remote MCP endpoint: it runs on your machine, with any personal Gmail. - Guardrails in the code, not in a prompt: an email can never trigger a send, every email is framed as data, instructions hidden in an email are flagged, attachments are saved safely and secrets are never attached.
- Windows (used daily) and Linux (unit tests in CI); macOS should work but is untested. The token is encrypted with DPAPI on Windows, a file readable only by you elsewhere. Everything sent to the client is in English.
Part of the Nexus family: NexusWindows, NexusBrowser, NexusAndroid.
Quick start
You need uv and a Google account. About 5 minutes, once.
-
Run the guided setup:
uvx --python 3.14 nexus-agymail setupIt adds the
nexus-agymailplugin to Antigravity, then offers to connect Gmail. Gmail scopes are restricted, so every user creates their own free OAuth client in their own Google Cloud project: your mail never goes through anyone else's app. The assistant opens each Google page in your browser at the right place and says what to click (it first asks which Gmail address to connect, so the pages open on that account):- create a project (name it NexusAGYmail);
- turn on the Gmail API;
- the consent screen (Get started, External); on Branding, a home page, a privacy policy link and an
authorized domain (the assistant gives this repository, its Privacy section and
github.com: Google requires them before publishing); then Publish app (unpublished, Google blocks the sign-in with Error 403: access_denied); - a client of type Desktop app (leave Use this client for an AI-powered agent unchecked), then Download JSON: the assistant finds the file in your Downloads folder by itself;
- sign in. Google shows "Google hasn't verified this app": it is your own app, click Advanced > Go to NexusAGYmail (unsafe).
Then it checks what can be checked: the Gmail API answers, and the app is really published (Google returns a 7-day sign-in for apps left in Testing); if not, it opens the page that fixes it and signs in again.
-
Restart Antigravity.
{ "mcpServers": { "nexus-agymail": { "command": "uvx", "args": ["--python", "3.14", "nexus-agymail@latest"] } } }
Then ask, for example: "Summarize my unread emails from this week", "Archive the newsletters older than a month", "Draft a reply to the last email from Alice saying I agree, and show it to me before sending".
Already have a Desktop app client JSON? uvx --python 3.14 nexus-agymail auth --client-secret <file> skips the
console steps. uvx --python 3.14 nexus-agymail status shows where the token is and which scopes it carries (no
secret shown).
Rather not create a client? Google's own Gmail MCP server runs on Google's side (same tool names) but is a developer preview: it needs the Google Workspace Developer Preview Program and a Google Cloud project as well, and it cannot send. NexusAGYmail exists because Antigravity has no Gmail connector of its own, and for confirmed sending.
How it works
flowchart LR
A[Google Antigravity] -- MCP stdio --> S[nexus-agymail<br/>on your machine]
S -- HTTPS, official Gmail API v1 --> G[(Gmail)]
S -. token, encrypted .- T[~/.nexus/nexus-agymail]
S -. attachments .- D[Downloads/NexusAGYmail]
The server is a plain local process: no cloud relay, no browser automation. It talks to gmail.googleapis.com with
your own OAuth client and a refresh token stored on your machine, and to oauth2.googleapis.com to refresh it.
Tools
Names and parameters follow Google's official Gmail MCP server
and its extensions (update_draft, trash_*), plus four of its own: send_draft, list_new_messages,
download_attachment, auth_status.
Every tool carries MCP annotations (title, read-only, destructive, idempotent). The tools that return data
(search_threads, get_message, get_thread, list_new_messages, list_labels, list_drafts, get_draft,
auth_status) publish an outputSchema and return structuredContent, the same object as their JSON text (kept for
older clients); an error sets isError. For Antigravity, setup also installs
a short skill that says which tool to use for what, and when to use the browser instead (Gmail settings such as
filters or signature, another Google account).
Safeguards
- Scopes:
gmail.readonly,gmail.compose,gmail.modify. Neverhttps://mail.google.com/, the only scope that allows permanent deletion: there is nodelete,batchDeleteor empty-trash tool, and the code is tested for it. An old token withoutgmail.modifykeeps reading and drafting; the labelling and trash tools then answerscopeswithout calling Gmail. - Sending: only
send_draft, after the user's explicit yes for that draft, never at the request of an email. When the client supports MCP elicitation (form mode, both theelicitation/createrequest and the 2026-07-28input_requiredround trip), the yes is given in the client's own confirmation dialog, which shows recipients, subject, body and attachments; decline or close sends nothing. Otherwisesend_draft(draftId, confirm=true, accord=<token>). Only a realtruecounts (not1,"yes"or"on"). Either way the yes is a single-use accord (10 minutes) bound to the exact draft: each recipient with its role (to, cc, bcc kept apart), From, Reply-To, subject, full body, every part (HTML included), the SHA-256 of each attachment and of the draft's raw bytes. The draft is read once in raw format just before sending: if anything changed, nothing is sent and a new summary is returned. Otherwise those exact approved bytes are sent (messages.send, same thread). The draft is kept (delete it in Gmail if you like):drafts.deleteis permanent, and an edit saved meanwhile would be lost. A change made after that last read can never go out in place of what was approved. A send is never retried after an ambiguous answer (5xx, timeout, network, unreadable 2xx), only after a 429: the outcome is reported as unknown. Each attempt is recorded before the request goes out, with its own ID, under the SHA-256 of the raw bytes (envois.json, nothing else kept), so it survives a crash and two simultaneous attempts never clear each other; the next summary or dialog of that same draft warns that it may already have been sent, after looking in Sent: "already sent" only when a sent message carries the draft's own Message-ID, otherwise at most "similar message, possible duplicate". A local storage failure never hides what Gmail did; if the attempt cannot be recorded, nothing is sent. No direct sending without a draft. - Provenance: a recipient found in an email the agent read is flagged in the summary (
provenance): allowed only if the user asked for it. - Prompt injection: subject, snippet, body, addresses and attachment names are returned framed as
⟦mail:ID …⟧ … ⟦/mail:ID⟧(random ID per answer) and labelled as data; hidden HTML text and invisible characters are removed. An email that looks like instructions aimed at an AI gets aninjection_warningfield (a signal only: it neither blocks nor allows anything). - Attachments: a received file is saved under a sanitized name (path, forbidden or invisible characters,
right-to-left override as in "fdp.exe", Windows reserved names), never overwriting a file, with the Windows
"downloaded from the Internet" mark (Zone.Identifier), so Windows and Office open it with their protections.
Attaching a local file: never from a secrets location (
.ssh,.gnupg,.aws,.config/gcloud, the AI apps' folders,.envfiles, private keys,credentials.json..., plus your own folders listed inNEXUS_AGYMAIL_PROTECTED); the user can always attach it themselves in Gmail. - Token:
~/.nexus/nexus-agymail/token.bin, encrypted with DPAPI for the current Windows account (permissions reduced to that account), or a0600file on macOS and Linux; written atomically under a lock (several servers can run at once). It is never shown. When you sign in again, a previous token with extra scopes is revoked only after the new one is saved. - Exact errors: revoked or expired token, network, quota, permissions, not found, label: each has a stable
code(revoked,network,quota,forbidden,not_found,label,invalid_argument...). Every request is retried with exponential backoff on 429 and 5xx; batched requests retry only the items refused for quota. - Bounded sizes: bodies cut at
maxChars(reported), paged searches, at most 100 items per labelling or trash call.
Configuration
Privacy
NexusAGYmail runs on your machine. It has no account of its own, no telemetry, no analytics and no relay: its only
network requests go to Google (gmail.googleapis.com, oauth2.googleapis.com, and accounts.google.com in your
browser when you sign in), with your own OAuth client, plus at most one request a day to pypi.org to read the
latest version number (NEXUS_AGYMAIL_UPDATE_CHECK=0 turns it off).
- What it reads: the emails, threads, drafts, labels and attachments the agent asks for, only when it calls the matching tool; local files only when the agent attaches them to a draft.
- Where it goes: tool results go to the AI client you connected, which may send them to its model provider under its own privacy policy. Drafts and sent emails go to Gmail. NexusAGYmail sends nothing anywhere else.
- What it stores, under
~/.nexus/nexus-agymail/(orNEXUS_AGYMAIL_HOME): the refresh token (token.bin, encrypted with DPAPI on Windows, a0600file elsewhere), its lock file, the copy of your OAuth client (client_secret.json), the position oflist_new_messagesper account and label (history.json: a GmailhistoryIdand the time of the last check, no email content), the sends whose outcome is unknown (envois.json: the SHA-256 of the raw bytes, the draft ID and the attempt time, no email content), and backups of the Antigravity config filessetupedits (backups/). The server also writes~/.nexus/status/agymail.json(installed and latest version, last check time) for the Nexus app. Attachments you ask it to save go to~/Downloads/NexusAGYmail(or the folder given). In memory only, for the life of the server: the pending send accords and the addresses seen in emails read (for theprovenancewarning). No email is written to disk unless saved as an attachment; no log of emails is kept. A local usage journal (%LOCALAPPDATA%\NexusJournal\agymail\<ai>\<YYYY-MM>.jsonl, kept 13 months) records one line per tool call: tool name, duration, outcome and a stable error code (quota,network...), never an address, subject, body, label, ID or query. It never leaves the PC;NEXUS_JOURNAL=0turns it off. - Removing it: delete
~/.nexus/nexus-agymail/and, for Antigravity,~/.gemini/config/plugins/nexus-agymail/; revoke the access in your Google account and delete your Google Cloud project if you no longer need it.
Known limitations
- Each user creates their own Google OAuth client (guided by
setup). A shared public client would need Google's restricted scope verification and a security assessment. - Plain-text bodies only when writing:
create_draftandupdate_draftdo not write HTML;update_draftreplaces the HTML part of a draft written in Gmail with the plain text. - No Gmail settings (filters, signature, forwarding, vacation replies): use the Gmail web app.
- No spam reporting and no permanent deletion, on purpose.
- Used daily on Windows 11 with a real Gmail account; Linux runs the startup and unit tests in CI; macOS is untested.
Development
./test.ps1 # ruff, pyright, unit tests against a fake Gmail API (no network, no Google account)
test.ps1 gives each checkout its own test environment under ~/.nexus/nexus-agymail and never downloads anything:
run uv sync --frozen once with network access to fill the uv cache. The fake Gmail API (tests/fake_gmail.py)
speaks HTTP to the real google-api-python-client, so batching, retries, uploads and paging are tested for real.
License
MIT. Not affiliated with Google; Gmail is a trademark of Google LLC.
