mailhub-mcp
Connects one owner's Gmail mailboxes to provide inbox triage: searching and reading messages and threads across accounts, summarizing mail with an inbox overview, and applying reversible organization such as labels, archiving, marking read and starring, plus creating reply drafts. All changes are journaled and undoable, and the server never sends, trashes or deletes mail.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mailhub-mcpsummarize my unread emails across all accounts and flag anything important"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mailhub-mcp
An MCP server that exposes one person's mail accounts (say personal, work and a side project) to Claude as a custom connector in claude.ai. Gmail is supported today; other providers plug in through a small provider interface (see docs/architecture.md).
It is built for inbox triage: Claude can search, read and summarize mail across all your accounts, then tidy up with labels, archiving and drafts. Every organizing change is reversible, and the server has no way to send, trash or delete mail.
One instance serves one owner: ALLOWED_EMAILS holds only your own Google login, and every mailbox linked to the instance is yours. Someone else who wants the same setup runs their own instance (see More than one person).
Features
The server exposes 17 tools (10 read-only, 7 that change something); see docs/architecture.md for the list.
Multi-account: each mailbox gets an alias. Read tools take
accounts=Noneto mean "all accounts" and return{results, errors}, with at most one error per account.Search, read and triage signals:
search_emails,read_email,read_emails,read_thread,list_labels,list_drafts. Messages carry unread, starred, importance, category and newsletter flags.Inbox overview:
inbox_overviewgives per-account totals, unread counts, newsletters, categories and top senders.Reversible organization:
create_label,modify_emails,modify_by_query(labels, archive, mark read, star), each recorded in a journal,undo_changeto revert a batch,list_changesto find earlier changes and their change_ids across sessions, andundo_sinceas a panic button that undoes everything since a time.Triage preferences:
get_preferencesandset_preferenceskeep rules such as important and ignored senders or keywords, and the time of the last triage, so scheduled triage is consistent from one run to the next. Rules that raise attention apply immediately; rules that lower attention wait for your approval outside the chat (mailhub-admin).Change history: every label change and every preference change is journaled with its motivating request, listed by
list_changesand undoable.Content defenses: hidden text is removed from HTML bodies, invisible characters are removed from message text fields (sender, recipients, subject, date, snippet, body, attachment names), email text is delimited as untrusted, and likely injection attempts are flagged (see the safety model).
Prompts:
daily_triage,clean_newslettersandorganize_inboxare MCP prompts (reusable workflows you pick in Claude). The two that change mail preview first and ask for your explicit confirmation; none of them trashes or deletes. WithTOOLS=read-onlyonly a read-onlydaily_triageis offered.Unsubscribe info: messages carry
unsubscribe(url,mailto,one_click) parsed fromList-Unsubscribe, andinbox_overviewtop senders carry their most recent one. It is sender-controlled text: shown to you, wrapped as untrusted, never visited by Claude.Health:
GET /healthreturns{"status":"ok"}(no auth, nothing else), the Docker image has aHEALTHCHECK, andmailhub-admin accountschecks that every linked mailbox still answers.Drafts:
create_draftleaves a reply draft in the mailbox for you to review and send yourself. Replies only, addressed to people already in the thread.
Related MCP server: Gmail MCP Server
Safety model
The code never calls
messages.trash,messages.delete,batchDelete,messages.sendordrafts.send. A test scanssrc/to enforce this.The system labels
TRASH,SPAM,DRAFT,SENTandCHATare refused inadd_labelsandremove_labels, by name or by ID.modify_by_querypreviews by default (confirm=false: match count plus a sample). Applying (confirm=true) touches at most 500 messages per call.Every change is journaled to
changes.jsonlwith the labels each message had before.undo_changereverts exactly that batch and never removes labels a message already had.list_changesshows the journal (newest first, with label names).undo_sincereverts every change since a time, newest first so overlapping changes restore exactly; it previews by default (confirm=false) and handles at most 50 changes per call.Every message the server changes gets the
claude/organizedlabel (created automatically in each account), so you can always find what Claude touched.modify_emailsandmodify_by_queryrefuse to remove it; onlyundo_changeandundo_sincetake it off, together with the rest of the reverted change.Email content is treated as untrusted third-party text. Before Claude sees a message, hidden HTML (for example
display:noneor zero-size text, comments, scripts) and invisible or bidirectional control characters are removed.bodyandsnippetare wrapped in[untrusted:<nonce>]...[/untrusted:<nonce>]markers with a fresh random nonce per response (marker lookalikes inside the text are defanged), and tool descriptions tell the model that nothing inside is an instruction.Each message carries
suspiciousandsuspicious_reasons, from heuristics for injection attempts (mentions of tool names, "ignore previous instructions", addressing the assistant, requests to forward or draft, large amounts of hidden text). Claude is told to report flagged emails and not to act on them. This is an aid, not a guarantee.Drafts are replies only:
create_draftrequires a message to reply to, andtoandccmay only contain people already in that thread (plus your own address). Drafting is refused for a thread that contains a suspicious message.A daily cap (
MAX_CHANGES_PER_DAY, default 2000) limits how many messagesmodify_emailsandmodify_by_querycan change per account in a rolling 24 hours. Undo is never capped.TOOLS=read-onlystarts an instance that registers only the read tools, for routines that should report but never change anything.Preferences follow a direction rule: anything that raises attention (marking a sender important, un-ignoring) applies immediately, anything that lowers attention (ignoring a sender, un-marking important) becomes a proposal that no MCP tool can approve. You approve it with
mailhub-admin preferences approve <id>inside the container. As long as you only approve proposals you recognize, injected text cannot silently hide future alerts. Raising-attention changes apply without review, but are visible inlist_changesand can be undone; since undoing them lowers attention, that undo is itself a proposal you approve the same way. Undo entries cannot be undone (make the change again instead). Proposals expire after 14 days.These defenses have limits (heuristics can be evaded, the server cannot verify who motivated a call); see Limitations.
Access to the server requires a Google login, restricted to the addresses in
ALLOWED_EMAILS, and checked on every request. Only Claude's own OAuth redirect URIs can register as clients. Every allowed login sees every linked mailbox, soALLOWED_EMAILSshould hold only the owner's login; the server logs a warning at startup when it lists more than one address.
Note on scope: Gmail's gmail.modify scope technically also permits sending and trashing, and it is the minimum that covers label changes and drafts. The protections above are in this code, not in the token. Review src/ if that distinction matters to you.
Quickstart
Follow docs/tutorial.md for the Google Cloud setup, account linking, configuration and the claude.ai connector.
Copy
.env.exampleto.env, fill it in, and rundocker compose up -d --build. The server listens on127.0.0.1:8742(setHOST_PORTin.envto change the host port); it needs HTTPS at a public URL in front of it.examples/tailscale-funnel/ shows one complete way to publish it, including a firewall that isolates the container.
More than one person
Run a separate instance per person: its own directory, .env, linked accounts, data/, container name, local port and Compose project name, and its own public URL. Each person adds their own custom connector in claude.ai with their instance's URL and logs in with their own Google account. See docs/tutorial.md for the steps and examples/tailscale-funnel/ for a second instance on the same host.
Privacy
Anything Claude reads through this server (message text, headers, search results) becomes part of your conversation and is sent to Anthropic. See Anthropic's privacy policy.
The server stores locally, in
data/andsecrets/: OAuth tokens, the change journal (including thequeryanduser_requestof each change) and your preferences.Logs record each tool call with its arguments: tool names, accounts, message ids, search queries, label names, draft recipients and subject, and preference values. Draft bodies are replaced by their length and
user_requestis cut to 80 characters; every other value is capped at 200 characters. Set log retention on the host accordingly.Apart from the Google APIs, the server sends nothing anywhere else.
Development
uv sync
uv run pytest -qLayout and extension points are described in docs/architecture.md.
License
MIT, see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Connect any mailbox to Claude, ChatGPT & AI: read, send, reply, schedule & search emails.
Your mailboxes in ChatGPT and Claude: Gmail, iCloud, Fastmail, any IMAP. Passwords stay yours.
Manage Gmail end-to-end: search, read, send, draft, label, and organize threads. Automate workflow…
Search and triage all your mailboxes; draft replies and campaigns; send only as you allow.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables reading, sending, searching, and managing Gmail through Claude using the official Google Gmail API.92 npm3MIT
- AlicenseNot gradedqualityCmaintenanceEnables Claude to read, search, send, label, and trash emails in any Gmail account via Google's Gmail API, using OAuth2 authentication with automatic token refresh.67 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables Claude to read, search, send, and manage Gmail messages and threads through natural language.371 npmMIT
- FlicenseNot gradedqualityDmaintenanceEnables Claude to read and manage your Gmail account, including listing, searching, sending, drafting, replying to, archiving, labeling, and trashing emails via the Gmail API.-