Skip to main content
Glama
JACKWULA123

mail-mcp

by JACKWULA123

mail-mcp

A local MCP server that lets AI coding agents (Claude Code and OpenAI Codex CLI) access your mailboxes: search, read messages/threads, read & download attachments, and create drafts — across multiple Gmail and personal Outlook accounts, routed by nickname.

Current capability: read-only + drafts. It never sends, deletes, or relabels mail. Sending/organizing are declared in the provider contract but gated off; enabling them later is a config change, not a rewrite (see Extending).

How safety is enforced

  • Outlook (Graph): we request Mail.Read + Mail.ReadWrite but not Mail.Send, so sending is impossible at the token level.

  • Gmail: there is no scope that grants drafts without also granting send (gmail.compose covers both). So for Gmail, "no send" is enforced at the application layer — no send tool is exposed and drafts.send/messages.send are never called. Keep this in mind before granting the send capability.

Related MCP server: Gmail MCP Server

Install

Requires Python ≥ 3.11.

uv venv --python 3.12 .venv
uv pip install --python .venv/bin/python -e ".[dev]"

Configure

.venv/bin/mail-mcp init            # creates ~/.config/mail-mcp/{config.toml,secrets,tokens,downloads}

Edit ~/.config/mail-mcp/config.toml (see config.example.toml). Each mailbox is one [accounts.<nickname>] block. Everything lives under $MAIL_MCP_HOME (default ~/.config/mail-mcp); set MAIL_MCP_HOME to relocate it.

Gmail OAuth (per Google account)

  1. Google Cloud Console → new project → enable the Gmail API.

  2. OAuth consent screen → User type External → add each Gmail address as a Test user (or publish to Production to avoid the 7-day refresh-token expiry in Testing mode).

  3. Credentials → Create OAuth client ID → Desktop app → download the JSON → save as ~/.config/mail-mcp/secrets/gmail_client_secret.json (the same client can serve multiple Gmail accounts).

  4. .venv/bin/mail-mcp auth gmail-personal

University / Workspace accounts (e.g. @g.ecc.u-tokyo.ac.jp): the admin may restrict third-party API access. If login fails with Error 400: admin_policy_enforced, your self-made client is blocked at the org level — Testing mode does not bypass this; only the Workspace admin can allowlist the client ID. Test a personal @gmail.com account first to confirm your setup, then try the university one.

Outlook OAuth (personal account)

  1. Azure PortalMicrosoft Entra ID → App registrations → New. Supported account types: Personal Microsoft accounts only.

  2. Authentication → Add platform Mobile and desktop applications → redirect http://localhost → mark as a public client.

  3. API permissions → Microsoft Graph → Delegated → add Mail.Read, Mail.ReadWrite, offline_access. Do not add Mail.Send.

  4. Put the Application (client) ID into the outlook block's client_id.

  5. .venv/bin/mail-mcp auth outlook

Check status any time: .venv/bin/mail-mcp accounts

Register with your AI client

Both launch the server over stdio. Use an absolute interpreter path and set MAIL_MCP_HOME explicitly so token discovery never depends on cwd or env forwarding.

Claude Code (user scope — available in every project):

claude mcp add --scope user mail \
  --env MAIL_MCP_HOME=/Users/<you>/.config/mail-mcp \
  -- /path/to/mail_mcp/.venv/bin/python -m mail_mcp

Codex CLI — add to ~/.codex/config.toml (Codex does not forward parent env by default, hence env_vars):

[mcp_servers.mail]
command = "/path/to/mail_mcp/.venv/bin/python"
args = ["-m", "mail_mcp"]
env_vars = ["HOME", "PATH"]

[mcp_servers.mail.env]
MAIL_MCP_HOME = "/Users/<you>/.config/mail-mcp"

Verify: claude mcp list (shows mail ✓ Connected) / Codex /mcp.

Tools

Tool

Purpose

list_accounts

list mailboxes, provider, capabilities, auth status

search_messages(account, query, limit=20)

search (Gmail operators for Gmail; free-text $search for Outlook)

read_message(account, message_id, format="text")

headers + body (text/html/full) + attachment list

read_thread(account, thread_id, format="text")

all messages in a thread/conversation

list_attachments(account, message_id)

attachment id/name/mime/size

download_attachment(account, message_id, attachment_id, dest_dir=None, include_base64=False)

save to disk, return path

create_draft(account, to, subject, body, cc, bcc, reply_to_message_id, body_is_html, attachments)

create an unsent draft

Extending

  • A new mailbox of an existing type → add an [accounts.<nick>] block + mail-mcp auth <nick>. No code.

  • A new mailbox type (e.g. IMAP) → implement MailProvider (src/mail_mcp/providers/base.py) and register it in providers/registry.py. The tool surface is unchanged.

  • Enable sending → add "send" to an account's capabilities. The send_message tool then registers automatically. For Graph, also add Mail.Send and re-run mail-mcp auth; Gmail needs no scope change. (Re-read the Gmail safety note first.)

Development

.venv/bin/pytest        # unit tests (no network)
.venv/bin/ruff check .
.venv/bin/mypy src
A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

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/JACKWULA123/mail-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server