Skip to main content
Glama
gmail-mcp

gmail-mcp

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
GMAIL_MCP_CONFIG_DIRNoOverrides where credentials.json, token.json, and gmail-mcp.log live. Defaults to OS-specific config directory: Linux: ~/.config/gmail-mcp/, macOS: ~/Library/Application Support/gmail-mcp/, Windows: %APPDATA%\gmail-mcp\

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
list_emailsA
Search inbox for emails matching a query string.

Returns a list of emails with their IDs, subjects, from addresses, dates,
snippets, and labels. IDs can be passed to read_email or reply_email.

Required: none — both params have defaults.
Optional:
  query (str, default="") — Gmail search syntax.
    Examples: "from:alice@example.com", "subject:invoice is:unread",
    "after:2026/01/01 before:2026/01/31", "has:attachment".
    Leave empty to get most recent inbox emails.
  max_results (int, default=5) — how many emails to return. Max 500.

Returns on success:
  {"total": N, "emails": [{"id": "...", "subject": "...", "from": "...",
     "date": "...", "snippet": "...", "labels": [...]}]}

Workflow note: The "id" field in each email is a Gmail message ID —
  pass it to read_email, reply_email, or get_thread_messages.
  Leave query empty to get recent inbox. Use Gmail search syntax
  to filter: from:, subject:, after:, before:, is:unread, has:attachment.
get_thread_messagesA
List all messages in a thread by thread ID.

Returns message IDs, subjects, from addresses, dates, and snippets.
Use this to find the Gmail message ID needed by reply_email.

Required:
  thread_id (str) — the Gmail thread ID. Get this from list_emails
    or read_email (look for "thread_id" in responses).

Returns on success:
  {"thread_id": "...", "total": N, "messages": [
    {"id": "...", "subject": "...", "from": "...", "date": "...", "snippet": "..."}
  ]}

Workflow note: reply_email requires a Gmail message ID in the in_reply_to
  parameter — NOT an email Message-ID header. Use get_thread_messages
  to find the right message_id first. Example flow:
    1. list_emails(query="subject:my thread") → get thread_id
    2. get_thread_messages(thread_id) → get message_id
    3. reply_email(thread_id=..., in_reply_to=message_id, ...)
read_emailA
Fetch the full content of an email by its Gmail message ID.

Returns subject, from, to, date, body (plain text), html_body, and labels.

Required:
  message_id (str) — the Gmail message ID from list_emails or
    get_thread_messages. NOT an email Message-ID header.

Returns on success:
  {"id": "...", "subject": "...", "from": "...", "to": "...",
   "date": "...", "body": "plain text...", "html_body": "HTML...",
   "labels": ["INBOX", "IMPORTANT"]}

Workflow note: body may be None if the email is HTML-only.
  html_body will be present for HTML emails. Labels include system
  labels like INBOX, SENT, TRASH, UNREAD and custom labels.
  Use list_attachments(message_id) to find downloadable files.
send_emailA
Send a new email. Can thread into an existing conversation by including
thread_id and in_reply_to/references headers. Supports CC, BCC, and
file attachments.

Required:
  to (str) — recipient email address.
  subject (str) — email subject line.
  body (str) — email body text.

Optional:
  cc (str, default="") — CC recipients, comma-separated.
  bcc (str, default="") — BCC recipients, comma-separated.
  thread_id (str, default="") — Gmail thread ID to reply within.
    If provided with in_reply_to and references, the email threads
    into the existing conversation.
  in_reply_to (str, default="") — the Message-ID header of the
    message being replied to. Required for threading.
  references (str, default="") — References header for threading.
    Usually same as in_reply_to.
  attachments (list[str] | None, default=None) — absolute file paths
    to files to attach. Paths must be absolute or relative to cwd.

Returns on success:
  {"message_id": "...", "thread_id": "...", "to": "...", "subject": "..."}

Workflow note: For threading, you need both thread_id and in_reply_to.
  If you only have a thread_id but not in_reply_to, use
  get_thread_messages(thread_id) first to find a message_id.
  Attachments: paths must exist and be under 25MB.
  The body parameter is the email text — not a file path.
reply_emailA
Convenience wrapper to reply to an existing thread.

Automatically prepends "Re: " to the subject if missing.
Can CC all original recipients with reply_all=True.

Required:
  to (str) — recipient address.
  body (str) — reply text.
  thread_id (str) — Gmail thread ID to reply within.
  in_reply_to (str) — Gmail message ID being replied to.
    GET THIS FROM get_thread_messages(thread_id) — do not guess.

Optional:
  subject (str, default="") — if empty, "Re: " is prepended to the
    original message's subject.
  cc (str, default="") — additional CC recipients.
  bcc (str, default="") — BCC recipients.
  reply_all (bool, default=False) — if True, auto-CCs all other
    recipients from the original message (To and CC headers).

Returns on success:
  {"message_id": "...", "thread_id": "...", "to": "...", "subject": "..."}

Workflow note: CRITICAL — in_reply_to must be a Gmail message ID
  (e.g. "19e09c7f2e8d487d"), NOT an email Message-ID header
  (e.g. "<CAC4dBmc...@mail.gmail.com>"). To find the right ID:
    1. Call get_thread_messages(thread_id)
    2. Pick the message ID from the "messages" array
    3. Pass that to reply_email's in_reply_to parameter
archive_emailA
Archive an email — removes it from INBOX without deleting it.
Archived emails are still searchable and accessible via search.

Required:
  message_id (str) — Gmail message ID from list_emails.

Returns on success:
  {"message_id": "...", "labels": ["IMPORTANT", "SENT"]}}
  (INBOX is removed from labels)

Workflow note: This is non-destructive. The email stays in Gmail
  with all other labels intact. Use list_emails(query="is:inbox")
  to confirm it's gone from the inbox view.
trash_emailA
Move an email to trash. Emails in trash are auto-deleted after 30 days.

Required:
  message_id (str) — Gmail message ID from list_emails.

Returns on success:
  {"message_id": "...", "labels": [..., "TRASH"]}}

Workflow note: To permanently delete, trash the email first —
  Gmail auto-purges trash after 30 days.
mark_readA
Mark an email as read — removes the UNREAD label.

Required:
  message_id (str) — Gmail message ID from list_emails.

Returns on success:
  {"message_id": "...", "labels": ["INBOX", "IMPORTANT"]}}
  (UNREAD is removed from labels)

Workflow note: Use this after reading an important email to
  clear the unread indicator.
add_labelA
Add a label (system or custom) to an email.

Required:
  message_id (str) — Gmail message ID.
  label (str) — label name. System labels: STARRED, IMPORTANT,
    SENT, DRAFT, TRASH, SPAM. Custom labels: any name you've
    created in Gmail settings.

Returns on success:
  {"message_id": "...", "labels": ["INBOX", "IMPORTANT", "..."]}}

Workflow note: Label names are case-sensitive in Gmail.
  "STARRED" works, "starred" may not. Custom label names
  must exactly match how they appear in Gmail.
remove_labelA
Remove a label from an email.

Required:
  message_id (str) — Gmail message ID.
  label (str) — label name to remove.

Returns on success:
  {"message_id": "...", "labels": ["INBOX", "IMPORTANT"]}}
  (the label is removed from labels array)

Workflow note: Removes the label from the message's label set.
  No error if the label was not present.
create_draftA
Create a draft email saved in Gmail's Drafts folder — not sent immediately.
Review it in Gmail before sending manually.

Required:
  to (str) — recipient email address.
  subject (str) — email subject line.
  body (str) — email body text.

Optional:
  cc (str, default="") — CC recipients.
  bcc (str, default="") — BCC recipients.
  attachments (list[str] | None, default=None) — file paths to attach.

Returns on success:
  {"draft_id": "...", "message_id": "..."}

Workflow note: Drafts are saved to Gmail, not stored locally.
  Use list_drafts() to see all drafts. Use update_draft(draft_id, ...)
  to modify a draft. Use delete_draft(draft_id) to remove.
  The draft stays in Gmail until manually sent or deleted.
list_draftsA
List the user's draft emails from Gmail's Drafts folder.

Optional:
  max_results (int, default=5) — max drafts to return.

Returns on success:
  {"total": N, "drafts": [
    {"id": "...", "subject": "...", "from": "...", "to": "...",
     "date": "...", "snippet": "..."}
  ]}

Workflow note: Each draft has a "id" (draft_id) used by update_draft
  and delete_draft. The "subject" field shows the draft's subject line.
  Use update_draft(draft_id, body="new content") to edit a draft.
update_draftA

Update a draft body, preserving omitted headers, threading and attachments.

body is required. Empty to/subject/cc/bcc retain existing values.
attachments=None preserves existing files; [] explicitly removes them.
delete_draftA
Delete a draft from Gmail's Drafts folder.

Required:
  draft_id (str) — draft ID from list_drafts.

Returns on success:
  {"draft_id": "..."}

Workflow note: This permanently removes the draft. No undo.
  Call list_drafts() first to confirm the draft_id before deleting.
list_attachmentsA
List all file attachments in an email with their IDs, filenames,
MIME types, and sizes.

Required:
  message_id (str) — Gmail message ID from list_emails.

Returns on success:
  {"attachments": [
    {"id": "...", "filename": "report.pdf",
     "mime_type": "application/pdf", "size": 204800}
  ]}

Workflow note: The attachment "id" field is a Gmail attachment ID —
  pass it to download_attachment along with the message_id and
  a save_path to download the file. Returns empty list if the
  email has no attachments.
download_attachmentA
Download a file attachment from an email and save it to a local path.

Required:
  message_id (str) — Gmail message ID from list_emails.
  attachment_id (str) — attachment ID from list_attachments.
  save_path (str) — local file path to save to. Must be inside
    your home directory or the gmail-mcp config directory.
    Parent directories are created automatically.
    If the file already exists, a counter suffix is added
    (e.g. "report (1).pdf") to avoid overwriting.

Returns on success:
  {"filename": "report.pdf", "path": "C:/Users/.../report.pdf",
   "size": 204800}

Workflow note: Paths are validated — path traversal attempts
  (e.g. "../../etc/passwd") are rejected. Use absolute paths
  or paths relative to your home directory. Supported file
  types: any MIME type. Max attachment size: 25MB.
read_emailsA
CHOICE HINT: When the user asks to "read", "show", or "fetch" content from
multiple emails (e.g. "read these 5 emails", "show me the latest 3 emails"),
ALWAYS prefer this tool over making N calls to read_email(). It bundles all
Gmail API calls into bounded HTTP batches.

Fetch full content of multiple emails in a single MCP request.

Uses googleapiclient.http.BatchHttpRequest — calls are bundled
into batches of up to 100 per HTTP round-trip.
Handles up to 100 messages per call automatically.

Optional:
  save_to_file (bool, default=False) — force save all results to a
    .md file regardless of size. Useful for large fetches.
  max_chars (int, default=30000) — if estimated output exceeds this,
    auto-saves to .md and returns a compact summary with the file path.

Returns on success (small):
  {"ok": true, "data": {
    "requested": N, "succeeded": N, "failed": 0,
    "results": [{"id": "...", "ok": true, "data": {...}}, ...]
  }}

Returns on success (large / save_to_file):
  {"ok": true, "data": {
    "saved": true,
    "path": "C:\Users\...\gmail-mcp\emails\2026-05-11-piraeus-49.md",
    "count": 49,
    "size_bytes": 184523,
    "summary_table": "## Summary

| # | Date | From | Subject | ...|", "requested": 49, "succeeded": 49, "failed": 0, "results": [{"id": "...", "ok": true, "data": {"date": "...", "from": "...", "subject": "...", "snippet": "...", "labels": [...]}} ...] }}

Workflow note: Use this instead of N calls to read_email() to bundle
  all fetches into a single MCP request. Each result has the same
  shape as a read_email() response.
mark_emails_readA
CHOICE HINT: When the user asks to "mark as read" or "mark read" multiple
emails, ALWAYS prefer this tool over making N calls to mark_read(). It uses
Gmail's batchModify API in chunks of at most 1000 message IDs.

Mark multiple emails as read in a single MCP request.

Uses messages().batchModify() with up to 1000 IDs per Gmail API call.

Required:
  message_ids (list[str]) — Gmail message IDs.

Returns on success:
  {"ok": true, "data": {
    "requested": N, "succeeded": N, "failed": 0,
    "results": [{"id": "...", "ok": true}, ...]
  }}

Workflow note: Use this instead of N calls to mark_read() to bundle
  all operations into a single MCP request.
archive_emailsA
CHOICE HINT: When the user asks to "archive" or "remove from inbox" multiple
emails, ALWAYS prefer this tool over making N calls to archive_email(). It uses
Gmail's batchModify API in chunks of at most 1000 message IDs.

Archive multiple emails in a single MCP request.

Uses messages().batchModify() with up to 1000 IDs per Gmail API call.

Required:
  message_ids (list[str]) — Gmail message IDs.

Returns on success:
  {"ok": true, "data": {
    "requested": N, "succeeded": N, "failed": 0,
    "results": [{"id": "...", "ok": true}, ...]
  }}

Workflow note: Non-destructive. Use this instead of N archive_email() calls.
trash_emailsA
CHOICE HINT: When the user asks to "trash" or "delete" multiple emails,
ALWAYS prefer this tool over making N calls to trash_email(). It uses
Gmail's batchModify API in chunks of at most 1000 message IDs.

Move multiple emails to trash in a single MCP request.

Uses messages().batchModify() with up to 1000 IDs per Gmail API call.

Required:
  message_ids (list[str]) — Gmail message IDs.

Returns on success:
  {"ok": true, "data": {
    "requested": N, "succeeded": N, "failed": 0,
    "results": [{"id": "...", "ok": true}, ...]
  }}

Workflow note: Use this instead of N trash_email() calls.
add_labelsA
CHOICE HINT: When the user asks to "add a label" to multiple emails,
ALWAYS prefer this tool over making N calls to add_label(). It uses
Gmail's batchModify API in chunks of at most 1000 message IDs.

Add a label to multiple emails in a single MCP request.

Uses messages().batchModify() with up to 1000 IDs per Gmail API call.

Required:
  message_ids (list[str]) — Gmail message IDs.
  label (str) — label name. System labels: STARRED, IMPORTANT, etc.
    Custom labels must exactly match how they appear in Gmail.

Returns on success:
  {"ok": true, "data": {
    "requested": N, "succeeded": N, "failed": 0,
    "results": [{"id": "...", "ok": true}, ...]
  }}

Workflow note: Use this instead of N add_label() calls.
  Label names are case-sensitive.
download_attachmentsC

Download attachments in batches of 100, preserving input order and unique files.

read_emails_fullA
Read multiple emails and always save the full results to a file.

Unlike read_emails() which returns data inline, this tool always writes
to disk and returns only a compact confirmation — making it safe to use
even for hundreds of emails without hitting MCP output limits.

Required:
  message_ids (list[str]) — Gmail message IDs to fetch.
  save_path (str) — local path to save the file. Must be inside your
    home directory (path traversal is rejected).

Optional:
  format (str, default="md") — output format. One of:
    "md"   — Markdown with summary table + full body per email
    "json" — pretty-printed JSON
    "jsonl" — one JSON object per line
    "csv"  — complete fields, text/HTML bodies, identifiers and errors

Returns on success:
  {"ok": true, "data": {
    "saved": true,
    "path": "C:\Users\...\my-emails.md",
    "count": 49,
    "format": "md",
    "total_size_bytes": 184523
  }}

Workflow note: Use this instead of read_emails() when you know the
  result will be large. Always saves — never returns data inline.
search_and_saveA
One-shot search + save: search Gmail and write results directly to a file.

Combines list_emails + read_emails_full into a single tool call.
No data is returned inline — just a compact summary + file path.

Required:
  query (str) — Gmail search syntax
    (e.g. "from:PiraeusBank after:2026/03/01 has:attachment").

Optional:
  max_results (int, default=100) — max emails to fetch.
  save_path (str) — local file path. If empty, auto-generates one in
    the configured gmail-mcp directory under emails/.  Overwrite is rejected — use a fresh
    path or let the tool auto-generate.
  format (str, default="md") — "md", "json", "jsonl", or "csv".

Returns on success:
  {"ok": true, "data": {
    "saved": true,
    "path": "C:\Users\...\emails\2026-05-11-piraeus-47.md",
    "count": 47,
    "format": "md",
    "total_size_bytes": 184523,
    "query": "from:PiraeusBank after:2026/03/01",
    "search_summary": "47 emails matched your search query"
  }}

Workflow note: Use this when you want to search Gmail and immediately
  persist results to a file without worrying about MCP output limits.
append_emailsA
Append more emails to an existing .md, .json, or .jsonl file.

Use this for pagination — fetch 50 emails, save them, then call this
tool to append the next 50 to the same file. Works with .md, .json,
and .jsonl files created by read_emails_full or search_and_save.

Required:
  message_ids (list[str]) — Gmail message IDs to fetch and append.
  save_path (str) — path to the existing file. File must exist.
    Supported extensions: .md, .json, .jsonl

Returns on success:
  {"ok": true, "data": {
    "appended": true,
    "path": "C:\Users\...\my-emails.md",
    "count": 50,
    "total_size_bytes": 320000
  }}

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A3.6/5.0

Scored across 25 tools

Disambiguation3/5

The singular/batch pairs (read_email vs read_emails, archive_email vs archive_emails, etc.) are mostly distinguishable through descriptions and choice hints, but the read/search/save cluster is crowded: list_emails, read_email, read_emails, read_emails_full, search_and_save, and append_emails overlap conceptually. An agent can usually choose correctly, but several tools require careful reading to avoid misselection.

Naming Consistency4/5

Most tool names follow a predictable snake_case verb_noun pattern, with clear singular/plural batch variants. Minor deviations exist, such as mark_emails_read (awkward ordering) and read_emails_full, but the convention is still largely consistent.

Tool Count3/5

25 tools is at the heavy end for a Gmail server. Many batch variants earn their place, but some duplication (multiple read/save tools plus singular/batch pairs) suggests the surface could be consolidated.

Completeness4/5

The server covers core email workflows: search/list, read, send, reply, draft CRUD, archiving, trashing, labels, mark-read, attachment listing/downloading, and batch operations. Minor gaps include no batch remove_label, no create/list custom labels, and no mark-unread or permanent-delete operation, but these are workable around.

Maintenance

ActivityMaintained
ResponsivenessOutdated data