gmail-mcp-server
Click on "Install 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., "@gmail-mcp-serverfind emails from John about the meeting"
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.
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 |
|
Write |
|
Manage |
|
Health |
|
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
Go to Google Cloud Console
Create a new project (or select an existing one)
Navigate to APIs & Services → Library and enable the Gmail API
Go to APIs & Services → Credentials → Create Credentials → OAuth client ID
Application type: Desktop app
Name:
Gmail MCP Server(or any name)
Download the credentials JSON file — save it as
credentials.jsonin the project rootGo 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 |
|
|
|
|
|
|
|
|
Installation
git clone https://github.com/yourusername/gmail-mcp-server.git
cd gmail-mcp-server
npm install
npm run buildConfiguration
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 portClaude 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
PATHor 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:
Complete the OAuth callback (on
http://localhost:3000/oauth2callback)Exchange the authorization code for tokens
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 |
|
CSRF protection | 16-byte random state parameter verified on OAuth callback |
Minimal OAuth scopes | Four granular scopes instead of full |
HTML sanitisation |
|
Destructive operation guards |
|
Attachment size cap | Returns metadata-only above 5 MB; use |
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 |
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 |
|
Tool Reference
ping
Health check. Returns server version, authenticated user, token expiry, and mailbox stats.
list_emails
Parameter | Type | Default | Description |
| string |
| Gmail label ID (e.g. |
| number |
| 1–500 |
| string | — | Gmail search query to filter results |
| string | — | Pagination token from previous response |
read_email
Parameter | Type | Description |
| string | Gmail message ID |
search_emails
Parameter | Type | Default | Description |
| string | required | Gmail search syntax (e.g. |
| number |
| 1–500 |
| string | — | Pagination token |
get_attachments
Parameter | Type | Description |
| 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 |
| string | Gmail message ID |
| string | Attachment ID (from |
send_email
Parameter | Type | Required | Description |
| string | ✅ | Recipient(s), comma-separated |
| string | — | CC recipients |
| string | — | BCC recipients |
| string | ✅ | Subject line |
| string | ✅ | Email body (max 5 MB) |
| boolean | — | Set |
reply_to_email
Parameter | Type | Required | Description |
| string | ✅ | ID of email to reply to |
| string | ✅ | Thread ID |
| string | ✅ | Reply body (max 5 MB) |
| boolean | — | HTML reply |
| boolean | — | Include all CC recipients |
forward_email
Parameter | Type | Required | Description |
| string | ✅ | ID of email to forward |
| string | ✅ | Forward-to address(es) |
| string | — | Text/HTML prepended before forwarded content |
| boolean | — | HTML format |
save_draft
All fields optional except body (default: empty string).
delete_email
Parameter | Type | Default | Description |
| string | required | Gmail message ID |
| boolean |
| If |
| boolean | — | Required when |
move_email
Parameter | Type | Description |
| string | Gmail message ID |
| string | Destination label ID |
mark_email
Parameter | Type | Description |
| string | Gmail message ID |
| enum |
|
create_label
Parameter | Type | Default | Description |
| string | required | Label name |
| enum |
|
|
delete_label
Parameter | Type | Description |
| 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 |
| string[] | required | 1–1000 message IDs |
| boolean |
| Permanent delete if |
| boolean | — | Required when |
Returns { succeeded: string[], failed: Array<{id, reason}> }.
empty_trash
Parameter | Type | Description |
|
| Must be literal |
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 startToken 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/permissionsLogs
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 |
| Missing env var | Set the 64-char hex key |
| Wrong path | Set |
| Expired/revoked token | Delete |
| Wrong OAuth scope | Re-authenticate (scopes changed) |
| Stale browser tab | Restart the auth flow |
| Duplicate label name | Choose a different label name |
License
MIT
This server cannot be installed
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/ndungukamami-sketch/gmail-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server