gmail-mcp-server
Provides tools to search, read, and draft emails in Gmail, including fetching messages, threads, labels, and creating drafts.
Click on "Deploy 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 unread emails from my manager this week"
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 self-hosted MCP server for Gmail, built on the official Gmail API. No third-party relay, no data leaving your own infrastructure, your Google OAuth token and email data stay on whatever machine you run this on.
Works with any MCP-compatible client: Claude Code over local stdio, or a hosted client like ChatGPT's custom connectors over HTTP with a built-in OAuth 2.1 authorization server.
Why
Most "Gmail for AI" integrations are either a paid SaaS connector or require handing a third party your inbox. This is neither: it's a small server you run yourself, talking directly to Google's API with your own OAuth client.
Related MCP server: Gmail MCP
Tools
Tool | Description |
| Search messages with Gmail's query syntax ( |
| Fetch one message in full: headers, plain-text and HTML body, attachment metadata |
| Fetch every message in a thread |
| Create a draft (optionally as a threaded reply). Never sends anything |
| List labels, with per-label message/thread counts |
Every response includes to/cc/bcc, labelIds, and (for get_message/get_thread)
attachment filenames and sizes. This server requests gmail.readonly and gmail.compose,
enough to read mail and create drafts, and never anything more: there is no send, modify, or
delete tool, and it never returns the contents of credentials.json or any token through a
tool. gmail_create_draft only ever leaves a draft sitting in Drafts, a human has to open Gmail
and hit send themselves.
Quickstart: local use with Claude Code
Requirements: Python 3.10+, a Google Cloud project with the Gmail API enabled.
git clone https://github.com/<you>/gmail-mcp-server.git
cd gmail-mcp-server
python -m venv .venv && source .venv/bin/activate
pip install -e .In the Google Cloud Console, enable the Gmail API, then go to APIs & Services → Credentials → Create Credentials → OAuth client ID, choose Desktop app, and download the JSON as
secrets/credentials.json.Add yourself as a test user under OAuth consent screen → Test users if the app is in Testing mode.
Authorize once:
python authorize.pyThis opens a browser, and writes
secrets/token.json.Add it to Claude Code's MCP config:
{ "mcpServers": { "gmail": { "command": "python", "args": ["-m", "gmail_mcp.server"], "cwd": "/path/to/gmail-mcp-server" } } }
That's it for local, stdio-based use, no auth server, no network exposure.
Deploying for a hosted client (e.g. ChatGPT connectors)
Hosted MCP clients need a real HTTPS endpoint and typically support only None or OAuth authentication, not a plain bearer header. This project ships a minimal OAuth 2.1 authorization server for exactly that case: a standard authorization-code + PKCE flow, gated by a single consent screen that asks for a passphrase you set yourself, so a token is only ever issued after you personally approve it.
Copy
.env.exampleto.envand fill it in (see the comments in that file).Put this behind a reverse proxy that terminates HTTPS (Caddy, Nginx, Traefik, your load balancer of choice) and point a real domain at it.
docker compose up -d --buildIn your MCP client, add a custom connector:
Server URL:
https://your-domain/mcpAuthentication: OAuth, with your own client ID (from
.env), no client secret, token endpoint auth methodnoneIt should auto-discover the authorization/token endpoints from
https://your-domain/.well-known/oauth-authorization-server
On first connect you'll land on a small consent page on your own server, enter the passphrase from
.envto approve.
Access tokens are short-lived (1 hour) with long-lived refresh tokens, both persisted to
secrets/oauth_state.json so a container restart doesn't force re-authorization.
Security notes
Only
gmail.readonlyandgmail.composeare ever requested, nothing broader.credentials.json,token.json,.env, andsecrets/are git-ignored, never commit them.The OAuth flow's consent step requires a passphrase only you know, so a leaked connector URL alone can't silently mint a token.
DNS-rebinding protection (
GMAIL_MCP_ALLOWED_HOSTS) locks the server to the hostname(s) you configure.There is no
send,modify, ordeletetool, by construction: the only write path isgmail_create_draft, and a draft is inert until a human opens it in Gmail and sends it.This is single-tenant: it authenticates as one Gmail account (yours), not a per-user login. Anyone who reaches your deployed instance and gets past the consent passphrase reads and drafts as you, not as themselves, don't share the deployed URL and passphrase together.
Project layout
gmail_mcp/
auth.py Google OAuth (installed-app flow) for the Gmail API itself
gmail_client.py Thin wrapper around the Gmail API for the four tools
server.py MCP tool definitions
http_app.py HTTP transport entrypoint (used for Docker/hosted deployments)
oauth_provider.py Minimal OAuth 2.1 authorization server (auth code + PKCE + refresh)
consent.py The passphrase-gated consent page
authorize.py One-time local script to obtain secrets/token.jsonLicense
MIT, see LICENSE.
Available Tools
5 toolsgmail_create_draftA
Create a Gmail draft. Never sends anything, the draft sits in Drafts for the user to review and send themselves. Set reply_to_message_id to draft a reply within an existing thread (sets In-Reply-To/References/threadId correctly).
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | ||
| to | Yes | ||
| bcc | No | ||
| body | Yes | ||
| subject | Yes | ||
| reply_to_message_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It clearly states the tool never sends anything, which is a critical safety behavior. It also explains the reply_to_message_id side-effect on In-Reply-To/References/threadId. It does not cover auth requirements, error handling, or return values, but for a draft creation tool, the primary behavioral trait (non-sending) is well disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, with the most important information (purpose and non-sending) front-loaded. Every sentence earns its place: the first establishes the core behavior, the second explains the reply use-case. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (6 params, no output schema, no annotations), the description covers the essential context: what it does, what it does not do, and how to use the reply feature. It does not describe return values or error scenarios, but for a draft-creation tool, an agent can infer that the draft is created successfully without explicit return details. The description is adequate for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must add meaning to parameters. It does this for reply_to_message_id by explaining its function, which is a meaningful addition. The other parameters (to, subject, body, cc, bcc) are self-explanatory given their names and types, so they need no elaboration. The description adds value where needed but does not comprehensively document all parameters, hence a baseline of 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb-resource pair ('Create a Gmail draft') and immediately clarifies the key distinction: 'Never sends anything, the draft sits in Drafts.' This makes the tool's purpose unambiguous and separates it from sending actions. It also hints at a specific use case (replying in a thread) without naming siblings, but the core purpose is explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a concrete usage guideline for the reply_to_message_id parameter, explaining that it sets the draft as a reply in an existing thread. It implicitly tells the agent when to use this tool (when a draft is needed) versus sending, but does not explicitly name alternatives or state when not to use it. The non-sending behavior is a strong contextual cue.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gmail_get_messageA
Fetch a single Gmail message by id, including its plain-text body.
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It reveals that the operation is a read ('Fetch') and that the output includes the plain-text body, which is useful. However, it omits error behavior, what else is returned beyond the body, and whether authentication scopes are needed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence with no filler. Every word contributes to conveying the operation and its output scope.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter get operation, the description covers the core action and one key output aspect (plain-text body). However, with no output schema, it should more fully describe the returned object and handle common edge cases (e.g., message not found, auth requirements). It is minimally sufficient but not thorough.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. The phrase 'by id' clarifies that message_id is a Gmail message identifier, distinguishing it from a thread id. Yet it does not explain the expected format of the id or how to obtain it, leaving some ambiguity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Fetch'), a clear resource ('a single Gmail message by id'), and a scoping detail ('including its plain-text body'). This distinguishes it from siblings like gmail_search (which returns multiple messages) and gmail_get_thread (which operates on threads, not individual messages).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool should be used when you have a message_id and need the message's plain-text body, but it does not explicitly contrast with siblings or state when not to use it. No alternative tools or exclusions are mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gmail_get_threadA
Fetch every message in a Gmail thread by thread id.
| Name | Required | Description | Default |
|---|---|---|---|
| thread_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. 'Fetch every message' accurately conveys a read-only operation, but the description does not disclose error behavior, authentication needs, response structure, or ordering of messages. For a simple getter this is adequate but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no filler. It states the action, resource, and required input efficiently.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with one required parameter and no output schema, the description covers the essential invocation. However, it omits details about return format, error cases, and how thread_id relates to results from sibling tools like gmail_search, leaving some ambiguity for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It only mentions 'thread id' without adding format, source, or usage detail beyond the parameter name. The phrase 'Gmail thread' gives minimal context but does not meaningfully expand on the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Fetch') and resource ('every message in a Gmail thread') and identifies the required identifier ('thread id'). It clearly distinguishes this tool from gmail_get_message by emphasizing that it returns the whole thread rather than a single message.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage when an agent needs all messages in a thread and has a thread_id, but it does not explicitly state when to use this tool versus alternatives such as gmail_get_message. No when-not or alternative guidance is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gmail_list_labelsA
List all Gmail labels on the account.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of behavioral disclosure. 'List' implies a read-only action and 'all' defines scope, but it does not mention whether system labels are included, potential pagination, or authentication requirements. The risk is low, but transparency is minimal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The entire description is one tight, front-loaded sentence with no filler. Every word contributes meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, read-only listing operation with an output schema available, the description is nearly complete. It could be improved only by a note on label scope (e.g., system vs user labels) or an explicit read-only guarantee.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, so the schema fully covers invocation needs. The description adds useful scope context by specifying all account labels.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List') and resource ('Gmail labels') with explicit scope ('all ... on the account'), making it easy to distinguish from siblings that target messages, threads, or drafts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended use is implied by the resource name, but the description does not explicitly state when to prefer this tool, nor does it name alternatives or exclusions. Sibling tools are clearly different, so guidance is not misleading, just absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gmail_searchB
Search Gmail messages using the Gmail search syntax (e.g. 'from:x@y.com is:unread').
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| max_results | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. The description mentions it uses Gmail search syntax, which is helpful, but it doesn't disclose what the tool returns (message list, metadata, snippets?), whether it's read-only, pagination behavior, or how max_results affects results. For a search tool, the return format and result structure are important behavioral details that are missing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that is concise and front-loaded with the core purpose. The example is useful and doesn't add excessive length. It earns its place by clarifying the query syntax. No wasted words, though it could add a bit more behavioral context without becoming verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, which likely describes the return structure, so the description doesn't need to explain return values. However, with no annotations and 0% schema description coverage, the description should provide more context about how the search works, what results look like, and how max_results behaves. The example query is helpful, but the description is minimal for a tool with two parameters and no annotation safety profile.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. The description explains the 'query' parameter by giving an example of Gmail search syntax, which adds meaning beyond the schema's bare 'Query' label. However, it doesn't explain 'max_results' at all, and the schema only says 'default: 10' without further context. The description partially compensates for the query parameter but leaves max_results undocumented.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: searching Gmail messages using Gmail's search syntax. It provides a concrete example ('from:x@y.com is:unread') that helps an agent understand the query format. However, it doesn't explicitly distinguish itself from sibling tools like gmail_get_message or gmail_get_thread, though the verb 'search' and the mention of Gmail search syntax make the purpose reasonably clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool: when you need to find messages matching a search query. It doesn't explicitly state when not to use it or mention alternatives like gmail_get_message for retrieving a specific message by ID. The example query provides some guidance on usage, but there's no explicit routing to siblings or exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
gmail_create_draft - First observed
gmail_get_message - First observed
gmail_get_thread - First observed
gmail_list_labels - First observed
gmail_search
TDQS
Scored across 5 tools
Each tool targets a distinct Gmail resource and action: searching, fetching a message, fetching a thread, creating a draft, and listing labels. There is no overlap or ambiguity between them.
All tool names follow a uniform `gmail_<verb>_<noun>` pattern (search, get_message, get_thread, create_draft, list_labels). The naming is fully consistent and predictable.
Five tools is a well-scoped size for a focused Gmail integration covering search, read, drafts, and labels. The count feels intentional rather than sparse or bloated.
The set covers search, retrieval, thread viewing, draft creation, and label listing, but lacks common Gmail operations like sending, updating/deleting drafts, modifying labels on messages, or marking read/unread. The read-and-draft focus is coherent, but the domain is only partially covered.
Maintenance
Related MCP Connectors
Manage Gmail end-to-end: search, read, send, draft, label, and organize threads. Automate workflow…
Permissioned access to Gmail, Drive and Calendar via the user's own Google account
Manage Gmail messages, threads, labels, drafts, and settings from your workflows. Send and organiz…
Your mailboxes in ChatGPT and Claude: Gmail, iCloud, Fastmail, any IMAP. Passwords stay yours.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables interaction with Gmail through the Gmail API with OAuth2 authentication. Supports reading, sending, searching emails, and managing read status through natural language.-
- AlicenseCqualityDmaintenanceEnables comprehensive Gmail management through the Gmail API, including sending/receiving emails, organizing labels and threads, managing drafts, and configuring account settings with secure OAuth2 authentication.64695 npm1MIT
- AlicenseNot gradedqualityCmaintenanceEnables reading, sending, archiving, and managing Gmail emails and labels through Google OAuth authentication, acting as an OAuth proxy to the Gmail API.89 npm11MIT
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to interact with Gmail through natural language, supporting email sending/reading, searching, draft management, label organization, and batch operations with secure OAuth authentication.-