Mailwarden
Gmail MCP server for email triage: search, labels, archive, trash, unsubscribe, snooze.
Connector by csitte · GitHub account verified by the MCP Registry
Install
Works with Claude Code, Codex, VS Code, Cursor, Windsurf, Claude Desktop. Read the repository before you give any tool access to your data.
npx agentmarket install connector/csitte-mailwarden
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this server can do and what it asks for, from its tool list and install config. Checked Oct 25, 2026.
- Tools
- 11 read · 11 write · 7 delete
- Secrets
- 1 (API keys, tokens or passwords)
- Install scripts
- Not scanned yet
- Runs as
- Node.js package
Tools by what they do 29
Read from the source code; the running server may list different tools.
Read 11 · Look things up without changing anything.
follow_upsget_profileget_threadlist_filterslist_labelslist_snoozedlist_subscriptionslist_unsubscribesearchtriage_digestwhat_changed
Write 11 · Create, change, send or run things.
bulk_unsubscribecreate_labeldownload_attachmentexport_threadmark_readmark_unreadsnoozesweep_snoozedunsnoozeunsubscribeuntrash
Delete 7 · Delete, drop, revoke or wipe things.
archivebulk_modifycreate_filterdelete_filtermodify_labelstrashundo_bulk_modify
Secrets and settings it asks for
Secrets: values you paste in that let it act as you.
MAILWARDEN_CREDENTIALS
Other settings (environment variables or headers).
MAILWARDEN_AUTO_SWEEPMAILWARDEN_DIRMAILWARDEN_DOWNLOAD_DIR
Tools (29)
Read from the source code; the running server may differ. Descriptions are the server’s own words; hidden characters are shown as [U+…].
archiveArchive threadArchive a thread (remove it from the inbox). USE WHEN: inbox triage — the thread is handled and should leave the inbox. DO NOT USE: to delete (use trash) or to defer to a date (use snooze). SIDE EFFECTS: thread leaves the inbox; reversible via modify_labels add INBOX.
bulk_modifyBulk modify by querycan change or delete dataBulk-apply label changes to every message matching a Gmail query, batched at 1000 messages per API request. Labels may be given by name or by id: an unknown name in `add` is created automatically (use '/' for nested labels), an unknown name in `remove` is ignored. Returns matched/submitted counts, matched and submitted thread IDs (both lists capped at 500 — matchedThreadCount/submittedThreadCount hold the true totals), and per-chunk failures (partial success is reported, not hidden). IMPORTANT: `submittedMessages` is how many ids were handed to the API, NOT how many messages changed — `message…
bulk_unsubscribeUnsubscribe from several listsUnsubscribe from several mailing lists in one call, one thread id per list. Threads are processed SEQUENTIALLY, and at most ONE request is made per sender — a second thread from a sender whose request already went out is reported with `duplicateOf` and no request (and says so when it advertises a DIFFERENT endpoint, i.e. is probably a separate list from the same sender). The whole call shares a 60-second budget; threads left over when it runs out come back with `skippedOutOfTime` and a reason, so re-running with the remaining ids finishes the job. Like unsubscribe, there is no URL parameter: e…
create_filterCreate filtercan change or delete dataCreate a Gmail filter: matching incoming mail automatically gets the given label actions. Give at least one criterion and at least one action. Actions are label add/remove only (labels by name or id; an unknown name in addLabels is auto-created). Common recipes: skip the inbox → removeLabels ['INBOX']; auto-mark-read → removeLabels ['UNREAD']; auto-trash → addLabels ['TRASH']; star → addLabels ['STARRED']; file under a label → addLabels ['Receipts']. A filter only affects mail arriving AFTER it's created; set applyToExisting:true to ALSO apply the same actions once to mail already in the mailb…
create_labelCreate labelCreate a user label and return its id. Idempotent: if the name already exists (case-insensitive), its existing id is returned and nothing is created. Nested labels: separate levels with '/' (e.g. 'Clients/Acme') — each missing parent level is created too. Colour: pass backgroundColor AND textColor together as '#rrggbb' (Gmail rejects one without the other, and accepts only colours from its own palette). Giving a colour for a label that already exists RECOLOURS it — that is how an existing label, such as the snooze label, gets a colour. Gmail colours only labels you created yourself; system lab…
delete_filterDelete filterDelete a Gmail filter by id (get ids from list_filters). USE WHEN: removing an auto-triage rule. SIDE EFFECTS: removes the server-side rule; future mail is no longer auto-processed by it. Requires gmail.settings.basic.
download_attachmentDownload attachmentDownload an attachment to a local file path. If MAILWARDEN_DOWNLOAD_DIR is set, destPath is resolved inside (and restricted to) that directory. USE WHEN: the user wants an attachment saved to disk (IDs come from get_thread's attachment metadata). SIDE EFFECTS: writes a local file; never overwrites — an existing file gets a numeric suffix (file-1.pdf). The response's 'saved' field is the path actually used. Mailbox unchanged.
export_threadExport thread to fileWrite a whole thread to a local file instead of returning it — for keeping, sharing, or reading a long conversation without loading it into the context. `markdown` (default): one section per message with From/To/Date/Subject and attachment names as inline code (never rendered as a link or image), sender authentication and the attachment list, and the body in a code fence that the message text cannot close (HTML-only mail is reduced to text). `json`: the parsed messages as get_thread returns them, HTML included. Both formats strip the same hidden characters (zero-width, bidi controls) as every …
follow_upsFollow-upsread-onlyWho is waiting on whom. `waitingOnThem`: threads whose LAST message is yours (SENT) and has had no answer for at least nudgeAfterDays — candidates for a nudge; a note to yourself (every To and Cc address is the account's own primary address, in any spelling Gmail delivers to it: +tags, dots, googlemail.com) is left out; one other recipient keeps it. `waitingOnMe`: threads still in the inbox whose last message came from someone else — a person, not a newsletter or an automated notice by its own headers — oldest first. Decided on each thread's last message and its LIVE labels: the search index o…
get_profileGet profileread-onlyReturn the authorized account: email address plus total message/thread counts. USE WHEN: confirming WHICH mailbox is connected before a bulk or filter action, or as a cheap liveness check. DO NOT USE: to enumerate messages — this returns only counts, not a listing (use search). SIDE EFFECTS: none.
get_threadGet threadread-onlyFetch a thread by ID: headers, plaintext + HTML bodies, and attachment metadata. `full` defaults to true and should stay true whenever content matters. `full: false` is a headers-and-labels fetch for when a thread is too large to read or only its metadata is of interest — it does NOT fetch bodies or attachment metadata, and the result then omits `plaintextBody`, `htmlBody` and `attachments` entirely and sets `metadataOnly: true`. The fields are omitted rather than empty on purpose: an empty attachment list from a request that never looked is indistinguishable from a message that truly has none…
list_filtersList filtersread-onlyList all Gmail filters — the server-side rules that auto-apply label actions to incoming mail. Shows each filter's criteria and label actions, and (for auditing) any `forward` address an existing filter carries. USE WHEN: reviewing existing automation, or to get a filter's id before delete_filter. SIDE EFFECTS: none. Requires the gmail.settings.basic scope — re-run `mailwarden --auth` if you authorized an earlier version.
list_labelsList labelsread-onlyList all Gmail labels (system + user). USE WHEN: inspecting the mailbox structure, or to get exact label names/ids — though modify_labels/bulk_modify/create_label all accept a plain label name directly, so a lookup is rarely required. SIDE EFFECTS: none.
list_snoozedList snoozedread-onlyList all snoozed threads with their due dates. SIDE EFFECTS: none.
list_subscriptionsList subscriptions by senderread-onlyWho keeps writing, how often, and whether you can get off the list — a mailbox slice grouped by SENDER, each row carrying its opt-out options. Contacts nobody: opt-out options come from the List-Unsubscribe header of each sender's newest thread (one metadata fetch per sender, not per thread). `optOut` is 'one-click' (the unsubscribe tool can perform it), 'link' (a human opens it in a browser), 'mailto' (would need sending, which mailwarden never does), 'none', or 'unknown' when that sender's header fetch failed or was never made because Gmail's quota ran out mid-listing. `oldestDate`/`newestDa…
Show 14 more tools
list_unsubscribeList unsubscribe optionsread-onlyReport the opt-out options a thread advertises (List-Unsubscribe / RFC 8058), without contacting anyone. Reads the newest message that carries the header, so a reply threaded onto a newsletter does not hide it. `oneClick` means the sender supports the automatable one-click opt-out — the `unsubscribe` tool can perform it. `httpsUrls` without oneClick are links for a human to open in a browser; `mailtos` would require sending mail, which mailwarden never does. `bodyCandidates` appears only when the headers advertise nothing: unsubscribe links found in the message TEXT, which is written by the se…
mark_readMark readMark a thread as read. SIDE EFFECTS: removes UNREAD; reversible via mark_unread.
mark_unreadMark unreadMark a thread as unread. SIDE EFFECTS: adds UNREAD; reversible via mark_read.
modify_labelsModify labelsAdd/remove labels on a thread. Archive = remove 'INBOX'; mark read = remove 'UNREAD'. Labels may be given by name or by id: an unknown name in `add` is created automatically (use '/' for nested labels), an unknown name in `remove` is ignored. USE WHEN: applying custom labels or label combinations in one call. DO NOT USE: for plain archive/read/unread — the dedicated tools are clearer. SIDE EFFECTS: changes the thread's labels (and may create a label named in `add`); reversible by the inverse call.
searchSearch Gmailread-onlySearch Gmail with native query syntax (e.g. 'in:inbox from:foo@bar.com newer_than:7d'). Returns thread summaries; read-state/category predicates are re-verified against each hit's live labels. Each summary carries `signals` derived from the thread's first message headers/MIME — newsletter (List-Id/List-Unsubscribe/Precedence bulk, junk or list), automated (Auto-Submitted, auto-reply/suppress headers, no-reply-style senders), calendar (text/calendar or .ics part), replyToMismatch (a Reply-To on another domain than From — a subdomain of the same domain counts as the same); empty when nothing is …
snoozeSnooze threadSnooze a thread until a date or time: archives it now, resurfaces when it comes due and sweep_snoozed runs. `until` accepts an explicit date (YYYY-MM-DD), a date+time (YYYY-MM-DD HH:MM or e.g. '2026-06-20 9am'), OR a preset resolved server-side: today, tomorrow, weekend (next Saturday), next week (next Monday), a weekday name (monday–sunday, next occurrence), 'in N days', or 'in N hours'. A preset may carry a trailing time ('tomorrow 9am', 'monday 8:30'). A timed snooze wakes at the next sweep on/after that minute. USE WHEN: deferring a thread to a later date/time instead of leaving it in the …
sweep_snoozedSweep snoozedResurface all snoozed threads whose date is due (<= today), batched at 1000 messages per API request. Set dryRun:true to rehearse: reports the due labels and threads (dueLabels/dueThreads) as the sweep would find them (from the live label listing; a single snooze label with more than 5000 messages is under-counted in the rehearsal), and wakes nothing. USE WHEN: the user asks to process due snoozes, or as a scheduled maintenance call; dryRun to answer 'what is due right now?' without acting. SIDE EFFECTS: due threads return to the inbox marked unread (none with dryRun); safe to run repeatedly. …
trashTrash threadcan change or delete dataMove a thread to Trash. USE WHEN: the thread should be discarded. DO NOT USE: for inbox cleanup of mail worth keeping (use archive). SIDE EFFECTS: thread moves to Trash; recoverable via untrash for ~30 days, then Gmail deletes it permanently.
triage_digestTriage digestread-onlyStructured overview of a mailbox slice for triage DECISIONS — sender / label / age buckets, unread and attachment counts, and header-derived signals (newsletter / automated / calendar / replyToMismatch — thread counts overall, and per sender the set of signals its threads carry), instead of a raw thread list. USE WHEN: deciding what to bulk-archive/snooze/label, or summarizing inbox state ('what's in my inbox?'). DO NOT USE: to read a specific thread (use search/get_thread). Samples up to `max` most-recent matches; hasMore flags that more matched than were sampled. byAge buckets by each thread…
undo_bulk_modifyUndo a bulk modifycan change or delete dataRevert a bulk_modify exactly, from the `undo` plan it returned (bulk_modify with undo:true). Pass `steps` unchanged: each step adds back the labels its messages lost and takes off the labels they gained, so a message that was already in the target state before the bulk change is left alone. Steps name labels by id, as the plan does; a label name is refused, because an unknown name would be created rather than restored. The plan restores the state read just before the bulk change. A label changed by hand since then is changed again by the undo, and a label deleted since then makes its step fail…
unsnoozeUnsnooze threadCancel a snooze: return the thread to the inbox now. SIDE EFFECTS: removes the snooze label, restores INBOX.
unsubscribeUnsubscribe from mailing listUnsubscribe from the mailing list a thread came from, via the sender's RFC 8058 one-click endpoint. There is deliberately no URL parameter: the endpoint is taken from the message's own List-Unsubscribe header and nowhere else. Only https one-click endpoints are called (fixed request body, response body discarded); a plain link is reported for the user to open, and a mailto: opt-out is never performed because mailwarden cannot send mail. If the sender offers nothing automatable this returns unsubscribed:false with the alternatives in `options` — it is not an error. USE WHEN: the user wants off …
untrashUntrash threadRestore a thread from Trash. SIDE EFFECTS: removes the TRASH label; user labels are preserved, but INBOX is NOT re-added — use modify_labels (add INBOX) to return it to the inbox.
what_changedWhat changedread-onlyWhat happened in the mailbox since a point you already hold: messages that arrived or were removed, and labels applied or taken off — from Gmail's own event log, in one call. Pass the `historyId` a previous what_changed or get_profile returned; the reply carries the next one to keep. mailwarden stores NOTHING between calls, so the id lives with you. Reports EVENTS, not current state: a message that was marked unread and then read appears under both, and both are true. For how the mailbox looks NOW, use search or get_thread. Gmail keeps roughly a week of history. An id older than that is an ERR…
Signals
- Stars
- 0
- Forks
- 0
- Open issues
- 1
- Last commit
- Oct 23, 2026 (6 days ago)
- Last release
- Oct 13, 2026 (15 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- Registry name
io.github.csitte/mailwarden- Version
- 0.23.0
- Auth
- No auth
- Packages
- npm mailwarden
- License
- MIT
- Repository
- github.com/csitte/mailwarden
- First seen
- Oct 24, 2026
- Last checked
- Oct 25, 2026
Cite this page
Mailwarden MCP server. Agent Mart. https://agentmart.dev/connectors/csitte-mailwarden (last updated 2026-10-25)