A Python MCP server that gives AI assistants (Cursor, Claude Desktop, etc.) read-only access to Gmail: list labels, list messages, and fetch full message content. No send, delete, or modify operations.
| Tool | Description |
|---|---|
gmail_list_labels |
List all Gmail labels (INBOX, SENT, DRAFT, TRASH, SPAM, UNREAD, STARRED, custom labels, …) |
gmail_list_messages |
List message IDs filtered by labels, search query, and pagination |
gmail_get_message |
Fetch a single message by ID — full headers, plain text, and HTML body |
| Parameter | Type | Default | Description |
|---|---|---|---|
label_ids |
list[str] |
all mail | Filter by label IDs, e.g. ["INBOX"], ["SENT"]. Use gmail_list_labels to get IDs. |
query |
str |
— | Gmail search query, e.g. from:user@example.com, is:unread, newer_than:7d. Syntax reference |
max_results |
int |
50 |
Max messages to return (1–500) |
page_token |
str |
— | Page token from a previous call for pagination |
- Python 3.10+
- uv (recommended) or pip
cd mcp-gmail
uv synccp .env.example .env
# Edit .env: set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET- Go to Google Cloud Console → APIs & Services → Library.
- Search for Gmail API and click Enable.
- Go to Credentials → Create Credentials → OAuth 2.0 Client ID.
- Choose Desktop app as the application type; give it a name.
- Copy
client_idandclient_secretinto.env.
GOOGLE_CLIENT_ID=1234567890-abc.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-...
GMAIL_TOKEN_FILE=tokens/gmail_token.jsonScope used: https://www.googleapis.com/auth/gmail.readonly (read-only; no send/modify/delete).
On first run the server opens a browser tab for you to sign in. The token is saved to tokens/gmail_token.json (or GMAIL_TOKEN_FILE) and refreshed automatically.
Tip: You can reuse the same Google Cloud OAuth client as MCP Calendar. Just keep a separate
GMAIL_TOKEN_FILEso the Gmail token is scoped only togmail.readonly.
uv run mcp run src/mcp_gmail/server.pyOr via the installed entry point:
uv run mcp-gmailAdd to your Cursor MCP config (via Cursor → Settings → MCP):
{
"mcpServers": {
"mcp-gmail": {
"command": "uv",
"args": [
"run",
"--directory",
"C:/Users/Ryzen/Projects/mcp-servers/mcp-gmail",
"mcp",
"run",
"src/mcp_gmail/server.py"
],
"env": {}
}
}
}Or using the installed entry point:
{
"mcpServers": {
"mcp-gmail": {
"command": "uv",
"args": [
"run",
"--directory",
"C:/Users/Ryzen/Projects/mcp-servers/mcp-gmail",
"mcp-gmail"
]
}
}
}Edit %APPDATA%\Claude\claude_desktop_config.json (Windows) or ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"mcp-gmail": {
"command": "uv",
"args": [
"run",
"--directory",
"C:/Users/Ryzen/Projects/mcp-servers/mcp-gmail",
"mcp",
"run",
"src/mcp_gmail/server.py"
]
}
}
}mcp-gmail/
├── pyproject.toml
├── .env.example
├── .gitignore
├── tokens/ # OAuth token cache (gitignored)
└── src/
└── mcp_gmail/
├── server.py # FastMCP entry point — 3 read-only tools
├── config.py # Loads .env, builds Gmail client
├── models.py # GmailLabel, GmailMessageRef, GmailMessage
└── providers/
└── gmail.py # Gmail API (read-only)
- Never commit
.envor thetokens/directory (both are in.gitignore). - This server only requests
gmail.readonly— it cannot send, delete, or modify mail. - The OAuth token is stored locally in
tokens/and refreshed automatically.