gmail-mcp-server

gmail-mcp-server

A secure MCP server that enables Claude to read, search, send, reply, forward, and manage Gmail messages and labels through natural language commands.

Category
Visit Server

README

Gmail MCP Server

A secure, production-ready Model Context Protocol server that gives Claude full Gmail integration — reading, searching, sending, replying, forwarding, managing labels, and more.

v2.0 — This release resolves all security findings from the audit:
encrypted token storage, CSRF protection, confirmation guards on destructive operations,
HTML sanitisation, attachment size caps, rate-limit backoff, and minimal OAuth scopes.


Features

Category Tools
Read list_emails, read_email, search_emails, get_attachments, download_attachment
Write send_email, reply_to_email, forward_email, save_draft
Manage delete_email, move_email, mark_email, create_label, delete_label, list_labels, batch_delete, empty_trash
Health ping

Prerequisites

  • Node.js 20+ (LTS recommended)
  • A Google Cloud Console project with the Gmail API enabled
  • OAuth 2.0 Desktop application credentials (credentials.json)

Google Cloud Console Setup

  1. Go to Google Cloud Console
  2. Create a new project (or select an existing one)
  3. Navigate to APIs & Services → Library and enable the Gmail API
  4. Go to APIs & Services → Credentials → Create Credentials → OAuth client ID
    • Application type: Desktop app
    • Name: Gmail MCP Server (or any name)
  5. Download the credentials JSON file — save it as credentials.json in the project root
  6. Go to APIs & Services → OAuth consent screen
    • Add your Google account as a Test user (required while the app is in testing mode)

Required OAuth Scopes

The server requests these minimal scopes (not the full https://mail.google.com/):

Scope Used for
gmail.readonly list_emails, read_email, search_emails, get_attachments
gmail.send send_email, reply_to_email, forward_email
gmail.compose save_draft
gmail.modify move_email, mark_email, delete_email, create_label, delete_label, batch_delete, empty_trash

Installation

git clone https://github.com/yourusername/gmail-mcp-server.git
cd gmail-mcp-server
npm install
npm run build

Configuration

1. Generate an encryption key

The server encrypts your OAuth tokens at rest using AES-256-GCM. Generate a 32-byte key:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Save the output — you will need it in every environment where the server runs.
If you lose the key, you must delete the token file and re-authenticate.

2. Set environment variables

# Required — 64 hex characters (32 bytes)
export GMAIL_MCP_TOKEN_KEY="your-64-char-hex-key-here"

# Optional
export GMAIL_MCP_LOG_LEVEL="info"          # debug | info | warn | error
export GMAIL_MCP_CONCURRENCY="5"           # parallel API fetch limit
export GMAIL_MCP_MAX_ATTACHMENT_BYTES="5242880"  # 5 MB inline attachment cap
export GMAIL_MCP_MAX_BODY_BYTES="5242880"        # 5 MB email body cap
export GMAIL_MCP_CONFIG_DIR="$HOME/.config/gmail-mcp"  # token storage dir
export GMAIL_MCP_CREDENTIALS_PATH="./credentials.json"  # credentials location
export GMAIL_MCP_REDIRECT_PORT="3000"      # OAuth callback port

Claude Desktop Configuration

Add the following to your Claude Desktop config file:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "gmail": {
      "command": "node",
      "args": ["/absolute/path/to/gmail-mcp-server/dist/index.js"],
      "env": {
        "GMAIL_MCP_TOKEN_KEY": "your-64-char-hex-key-here",
        "GMAIL_MCP_LOG_LEVEL": "info",
        "GMAIL_MCP_CREDENTIALS_PATH": "/absolute/path/to/credentials.json"
      }
    }
  }
}

Important: Use absolute paths. Claude Desktop may not inherit your shell's PATH or working directory.


First-Time Authentication

On first launch, the server will print an authorization URL to its log output (stderr).
Open it in your browser, sign in with your Google account, and grant the requested permissions.

The server will automatically:

  1. Complete the OAuth callback (on http://localhost:3000/oauth2callback)
  2. Exchange the authorization code for tokens
  3. Encrypt and save the tokens to ~/.config/gmail-mcp/token.enc

Subsequent launches will use the saved (encrypted) tokens and refresh them automatically.

To view the authorization URL when running through Claude Desktop, check the MCP server logs.


Security

Feature Implementation
Token encryption AES-256-GCM, key from environment variable
Token file permissions 0o600 (owner read/write only)
CSRF protection 16-byte random state parameter verified on OAuth callback
Minimal OAuth scopes Four granular scopes instead of full https://mail.google.com/
HTML sanitisation sanitize-html with strict allowlist before sending/drafting
Destructive operation guards permanent:true and empty_trash require confirmed:true
Attachment size cap Returns metadata-only above 5 MB; use download_attachment for individual files
Body size cap Emails and drafts capped at 5 MB at schema validation level
Rate-limit backoff Exponential backoff with jitter on 429/5xx responses
Concurrent fetch limit Configurable semaphore (default: 5 parallel requests)
Token refresh mutex Single refresh-at-a-time to prevent invalid_grant race condition
Safe error messages Raw API errors logged to stderr only; LLM receives whitelisted messages
From: header Always populated from authenticated user's profile
BCC in reply-all Filtered by actual email address; BCC never exposed to CC recipients
Subject deduplication Re: and Fwd: prefixes stripped before re-prepending

Tool Reference

ping

Health check. Returns server version, authenticated user, token expiry, and mailbox stats.

list_emails

Parameter Type Default Description
folder string "INBOX" Gmail label ID (e.g. "INBOX", "SENT", "Label_42")
maxResults number 20 1–500
query string — Gmail search query to filter results
pageToken string — Pagination token from previous response

read_email

Parameter Type Description
emailId string Gmail message ID

search_emails

Parameter Type Default Description
query string required Gmail search syntax (e.g. "from:alice is:unread")
maxResults number 20 1–500
pageToken string — Pagination token

get_attachments

Parameter Type Description
emailId string Gmail message ID

Returns inline base64 data if total size ≤ 5 MB; metadata-only otherwise.
Use download_attachment for individual files above the cap.

download_attachment

Parameter Type Description
emailId string Gmail message ID
attachmentId string Attachment ID (from get_attachments response)

send_email

Parameter Type Required Description
to string ✅ Recipient(s), comma-separated
cc string — CC recipients
bcc string — BCC recipients
subject string ✅ Subject line
body string ✅ Email body (max 5 MB)
isHtml boolean — Set true for HTML email (sanitised)

reply_to_email

Parameter Type Required Description
emailId string ✅ ID of email to reply to
threadId string ✅ Thread ID
body string ✅ Reply body (max 5 MB)
isHtml boolean — HTML reply
replyAll boolean — Include all CC recipients

forward_email

Parameter Type Required Description
emailId string ✅ ID of email to forward
to string ✅ Forward-to address(es)
additionalMessage string — Text/HTML prepended before forwarded content
isHtml boolean — HTML format

save_draft

All fields optional except body (default: empty string).

delete_email

Parameter Type Default Description
emailId string required Gmail message ID
permanent boolean false If true, permanently delete (irreversible)
confirmed boolean — Required when permanent:true

move_email

Parameter Type Description
emailId string Gmail message ID
targetLabel string Destination label ID

mark_email

Parameter Type Description
emailId string Gmail message ID
action enum read | unread | star | unstar | important | unimportant

create_label

Parameter Type Default Description
name string required Label name
visibility enum "show" show | hide | showIfUnread

delete_label

Parameter Type Description
labelId string Label ID (system labels cannot be deleted)

list_labels

No parameters. Returns systemLabels and userLabels arrays with message counts.

batch_delete

Parameter Type Default Description
emailIds string[] required 1–1000 message IDs
permanent boolean false Permanent delete if true (requires confirmed:true)
confirmed boolean — Required when permanent:true

Returns { succeeded: string[], failed: Array<{id, reason}> }.

empty_trash

Parameter Type Description
confirmed true Must be literal true — permanently deletes all Trash messages

Returns { deletedCount: number }.


Development

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Build TypeScript
npm run build

# Start server directly (after building)
npm start

Token Rotation

OAuth refresh tokens do not expire unless revoked, but periodic rotation is good practice.

# 1. Delete the encrypted token file
rm ~/.config/gmail-mcp/token.enc

# 2. Restart Claude Desktop (or the MCP server)
#    You will be prompted to re-authorize in your browser.

# 3. Revoke the old token (optional but recommended)
#    https://myaccount.google.com/permissions

Logs

All server logs are written to stderr as structured JSON (never stdout, which is reserved for the MCP protocol). To capture logs when running through Claude Desktop, check the MCP server log files:

  • macOS: ~/Library/Logs/Claude/mcp-server-gmail.log

Log levels: debug, info, warn, error — controlled by GMAIL_MCP_LOG_LEVEL.


Troubleshooting

Symptom Likely cause Fix
GMAIL_MCP_TOKEN_KEY must be set Missing env var Set the 64-char hex key
credentials.json not found Wrong path Set GMAIL_MCP_CREDENTIALS_PATH
Authentication failed Expired/revoked token Delete token.enc and re-authenticate
Permission denied Wrong OAuth scope Re-authenticate (scopes changed)
OAuth state mismatch Stale browser tab Restart the auth flow
Conflict — resource exists Duplicate label name Choose a different label name

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured