Gmail MCP
Provides tools for interacting with a Gmail inbox through the Gmail API — retrieving account profile and labels, searching messages with Gmail's search syntax, and reading full messages and threads with extracted plain-text bodies. At higher access levels it also enables draft management (list, get, create, update, delete), sending existing drafts or composing new mail, and organizing mail by adding/removing labels, archiving, trashing, and untrashing messages.
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 MCPFind unread emails from Sarah about the project deadline"
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 — Gmail Access for AI Clients
15 tools for the Gmail API — search, read, draft, send, and organize — gated behind three access levels, read-only by default.
For Claude Desktop, Claude Code, and any MCP client.
What is this?
Gmail MCP is a Model Context Protocol server that gives AI assistants structured access to a Gmail inbox — searching and reading mail, drafting replies, and, only at the highest access level, sending mail and organizing the inbox (labels, archive, trash).
Gmail has no service-account model for a personal @gmail.com inbox — there is no "share this
inbox with a robot" the way there is for a Google Doc or Sheet. Every call here is authorized on
behalf of a real Google account through the standard OAuth 2.0 "installed app" flow: you sign in
once in a browser, this server gets a long-lived refresh token, and every call after that happens
with no browser involved.
Supported platform: any MCP client on macOS, Linux, or Windows with Python 3.10+.
Related MCP server: Gmail MCP Server
Access Levels
GMAIL_ACCESS_LEVEL in .env controls what this server will actually do — independent of what
the OAuth consent screen technically allows (see Authentication: that consent
always grants the FULL ceiling, specifically so raising this later never sends you back to the
browser).
Level | Can it change your inbox? | Tools |
| No. List, search, and read messages and threads. | 5 |
| Drafts only. Create, edit, and delete drafts. Nothing is ever sent. | 10 |
| Yes. Everything in | 15 |
How it is enforced
Two independent gates, so a bug in one does not defeat the other:
Registration.
server.register_tiered_tools()only hands the model tools whose required level the configuredGMAIL_ACCESS_LEVELmeets. AtREADONLYthe model is never told thatsend_messageexists.Dispatch.
GmailClientchecks the level before building any request. A call to a level-gated method at an insufficient level raisesAccessDeniedand no HTTP request is made — there are tests for exactly that.
What FULL deliberately does not include
Gmail's broadest scope, https://mail.google.com/, additionally grants permanent deletion
(bypassing Trash) and the ability to change account settings — forwarding rules, filters,
IMAP/POP toggles. This server never requests that scope at any level. Those are account
configuration changes, not "read or send mail" operations, and unlike sending or trashing a
message, they are not something a person watching the inbox can easily notice and undo. There is
no tool here that needs it, at any access level.
⚠️ Disclaimer — read before raising the level
Setting
GMAIL_ACCESS_LEVELtoBASICorFULLallows an AI model to act on your real Gmail account.At
FULL, that includes sending email from your address with no human click in between. A sent message cannot be recalled — the recipient has it the instant the tool call succeeds.FULLcan also trash and relabel existing mail (recoverable via Trash for ~30 days, but not instant, and not something you'll necessarily notice happened).AI models make mistakes. They misread instructions, act on ambiguous requests, and can be influenced by content they read — including the content of an email they were asked to read before replying to it. A model with
FULLaccess to your Gmail account can send messages as you to anyone, about anything.If you raise this setting above
READONLY, you do so entirely at your own risk and you are solely responsible for anything sent, deleted, or reorganized as a result. The author and contributors accept no liability. This software is provided "as is", without warranty of any kind, as set out in the MIT License.Recommended: leave it at
READONLYfor searching and reading. Raise toBASICif you want drafts prepared for your own review and send. Raise toFULLonly for a session that specifically needs to send or reorganize mail on your behalf, and only if you are comfortable with that.
Tools
Level | Tools | What you can do |
| 5 | Get the account profile, list labels, search messages (Gmail's own search syntax), read a message, read a whole thread |
| 5 | List/get/create/update/delete drafts |
| 5 | Send a draft, compose-and-send directly, add/remove labels, trash, untrash |
Tool | Level | Description |
| READONLY | The authorized account's address and message/thread totals |
| READONLY | Every label (system + user), with the IDs other tools need |
| READONLY | Gmail search syntax ( |
| READONLY | One message in full: headers, labels, plain-text body |
| READONLY | An entire conversation as an ordered list of messages |
| BASIC | List drafts on the account |
| BASIC | One draft in full |
| BASIC | Create a draft — optionally as a reply within an existing thread |
| BASIC | Replace a draft's content |
| BASIC | Delete a draft (never touches sent mail) |
| FULL | Send an existing draft as-is — irreversible |
| FULL | Compose and send immediately, no draft step — irreversible |
| FULL | Add/remove labels — archive, mark read/unread, star |
| FULL | Move to Trash — reversible for ~30 days |
| FULL | Restore out of Trash |
Every message- and thread-reading tool returns the extracted plain-text body inline, not just a snippet — the same approach used in wordpress-mcp and google-cloud-services-mcp for reading a Doc: try the clean structured form first, fall back to a best-effort plain-text conversion for HTML-only mail.
Requirements
Requirement | Version |
Python | 3.10 or later |
Google Cloud project | with the Gmail API enabled |
OAuth 2.0 Client ID | type "Desktop app" |
Authentication
Gmail has no service-account option for a personal inbox (that only exists for a paid Google Workspace domain with admin-configured domain-wide delegation). Setup here is a one-time OAuth consent instead:
In Google Cloud Console, create or select a project and enable the Gmail API (APIs & Services → Library → search "Gmail API" → Enable).
Configure the OAuth consent screen (APIs & Services → OAuth consent screen). Choose External, keep it in Testing mode, and add the Google account you'll use as a test user. Testing mode is enough for your own account — you do not need Google's app-verification review for a single-user tool like this one.
Create an OAuth 2.0 Client ID of type Desktop app (APIs & Services → Credentials → Create Credentials → OAuth client ID → Desktop app). Note its Client ID and Client Secret.
Run the one-time consent flow:
./.venv/bin/gmail-mcp-authorizeIt asks for the Client ID and Secret from step 3 (or reads
GMAIL_CLIENT_ID/GMAIL_CLIENT_SECRETfrom your environment if already set), opens your browser to Google's sign-in and consent screen, and printsGMAIL_CLIENT_ID,GMAIL_CLIENT_SECRET, andGMAIL_REFRESH_TOKEN— put all three in.env.This always requests the
FULLscope ceiling (read + drafts + send/organize), regardless of whatGMAIL_ACCESS_LEVELyou'll actually run at. That's deliberate:GMAIL_ACCESS_LEVELis a second, independent gate on top (see Access Levels) — raising it later is an.envedit, not a trip back to this step.If you ever need to revoke access entirely, do it at myaccount.google.com/permissions — that invalidates the refresh token immediately, and
gmail-mcp-authorizegets you a new one.
Installation
git clone git@github.com:jimsimoy/gmail-mcp.git
cd gmail-mcp
python3 -m venv .venv && ./.venv/bin/pip install -e ".[dev]"
cp .env.example .env
# then follow Authentication above to fill in .envVerify before wiring up a client
./.venv/bin/python -m pytest -q # no credentials or network needed
./.venv/bin/gmail-mcp # starts the stdio server; prints the tool count to stderrClient Setup
{
"mcpServers": {
"gmail": {
"command": "/path/to/gmail-mcp/.venv/bin/python",
"args": ["-m", "gmail_mcp"],
"env": {
"GMAIL_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
"GMAIL_CLIENT_SECRET": "your-client-secret",
"GMAIL_REFRESH_TOKEN": "your-refresh-token",
"GMAIL_ACCESS_LEVEL": "READONLY"
}
}
}
}With uv:
{
"mcpServers": {
"gmail": {
"command": "uv",
"args": ["--directory", "/path/to/gmail-mcp", "run", "gmail-mcp"],
"env": {
"GMAIL_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
"GMAIL_CLIENT_SECRET": "your-client-secret",
"GMAIL_REFRESH_TOKEN": "your-refresh-token",
"GMAIL_ACCESS_LEVEL": "READONLY"
}
}
}
}Restart your MCP client after saving.
Usage Examples
Find something from years ago, without knowing the exact wording:
"Search my Gmail for anything from IdeaSpace Foundation around July 2016."
search_messages(query="from:ideaspacefoundation.org after:2016/06/01 before:2016/08/01")
Draft a reply for you to review and send yourself (safe at BASIC):
"Draft a reply to the latest message in this thread saying I can make the Tuesday slot."
create_draft(to=..., subject="Re: ...", body_text=..., thread_id=..., in_reply_to=...) — the draft
sits in Gmail's Drafts folder until you send it.
Let it send directly (needs FULL, and means what it says):
"Send that reply now."
send_draft(draft_id=...) — no further confirmation step inside this server. If you want a human
checkpoint before anything goes out, stay at BASIC and send from the Gmail app yourself.
Security
This project is meant to be read before it is run. The design notes that matter:
Read-only by default, enforced twice. At
READONLY— the default — nothing that changes your inbox is even registered as a tool, andGmailClientrefuses the underlying operation independently if it's somehow reached anyway. Tests cover both gates, including that a denied call never reaches the network.The OAuth scope is a second, outer fence. Even if
GMAIL_ACCESS_LEVELwere somehow bypassed, the access token itself is scoped by what you granted during consent — and this server never requestshttps://mail.google.com/, the one scope that permits permanent deletion and account settings changes, at any level.Refresh tokens and client secrets are environment-only.
.env,.env.*(except.env.example), andtoken.jsonare gitignored. Every credential is stripped from any error message this server produces, including Gmail's own error bodies.A pre-push scan runs before every commit and push (
git-guard.sh, invoked bygit-commit.sh/git-push-current.sh) — it specifically pattern-matches Google OAuth client IDs, client secrets, and refresh/access token formats, on top of the generic credential patterns used across this author's other MCP servers. This repo is private, but the scan runs regardless — see the comment at the top ofgit-guard.shfor why "it's private" is not treated as a sufficient control on its own.Sending is never retried. A
send_message/send_draftcall that times out or fails ambiguously is not silently replayed — a duplicate send is worse than a visible error.Three runtime dependencies, no vendor SDK.
mcp,httpx,python-dotenv. Gmail's REST API is called directly; there is nogoogle-api-python-clientdependency to audit.No telemetry. This server makes no network call other than the Gmail API request a tool asks for, and the OAuth token refresh that requires.
Your refresh token carries whatever scope you granted at consent (the FULL ceiling, by design —
see Authentication). Revoke it at
myaccount.google.com/permissions if it is ever exposed,
then run gmail-mcp-authorize again for a new one.
Project Structure
gmail-mcp/
├── src/gmail_mcp/
│ ├── access.py # AccessLevel enum, per-level Gmail scopes, the require() gate
│ ├── auth.py # Refresh token -> short-lived access token
│ ├── authorize.py # One-time interactive browser consent flow (gmail-mcp-authorize)
│ ├── client.py # Gmail REST wrapper: MIME building, message parsing, dispatch gate
│ ├── config.py # .env loading into a Settings dataclass
│ └── server.py # MCP tool definitions and tiered registration
├── tests/
│ ├── test_access.py # Both enforcement gates
│ ├── test_message_parsing.py # MIME/text-extraction pure-function tests
│ └── test_rate_limiting.py # Retry-on-rate-limit and per-item fetch pacing
├── .env.example
└── pyproject.tomlDevelopment
./.venv/bin/pip install -e ".[dev]"
./.venv/bin/python -m pytest -q51 tests, run entirely offline against httpx.MockTransport and a fake token provider — no real
Gmail account or network access is needed to verify the access-level gates, the MIME/parsing logic,
or the rate-limit backoff and pacing (see AGENTS.md — this was
hit for real once, not added speculatively).
License
MIT — see LICENSE.
Available Tools
5 toolsget_messageBRead-onlyIdempotent
Get one message in full: headers, labels, and its plain-text body.
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so the safety profile is covered. The description adds that the body is returned as plain text, which is mild extra context, but says nothing about permissions, missing-message behavior, or why a full fetch differs from search results.
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 naming the verb, cardinality ('one'), and return contents. No padding.
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?
An output schema exists, so return values need no elaboration, and annotations cover safety. However, the description never positions the tool against the sibling tools that also retrieve or enumerate messages, leaving selection ambiguity.
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% and the description says nothing about message_id, but there is only one required parameter with a self-explanatory name. That keeps it at the baseline rather than penalizing heavily — no format or provenance hints are added.
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 gives a specific verb and resource (get one message) and enumerates the returned parts: headers, labels, and plain-text body. It does not explicitly distinguish itself from siblings like get_thread or search_messages, so it stops short of a 5.
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?
There is no guidance on when to use this versus get_thread or search_messages, nor any prerequisites (e.g., an ID must come from search_messages). Usage is only implied by the verb 'get'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_profileARead-onlyIdempotent
Get the authorized Gmail account's address and message/thread totals.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=true, so the safety profile is fully covered. The description adds only that the result contains the account address plus message/thread totals, which is largely restated by the existing output schema.
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 sentence that front-loads the action and the returned data with no filler. Nothing is padded or repeated.
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 profile tool with an output schema covering the return shape and annotations covering the safety profile, the description supplies everything an agent needs to call it correctly.
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?
The tool takes zero parameters, so the baseline of 4 applies. The description correctly signals there is nothing to configure by describing a fixed, account-scoped lookup.
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?
States a specific verb ('Get') and a precisely scoped resource (the authorized Gmail account's address and message/thread totals). This is clearly distinguishable from the sibling list/search/get-message/get-thread tools, none of which return account-level profile data.
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?
Usage is implied rather than stated: the description makes clear this is the account-identity/totals lookup, but it never says when to prefer it or notes that no parameters or filters are accepted. No alternatives or exclusions are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_threadBRead-onlyIdempotent
Get an entire conversation thread as an ordered list of messages.
| Name | Required | Description | Default |
|---|---|---|---|
| thread_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is covered. The description adds one genuine behavioral detail beyond the annotations — that results are returned as an ordered list — but says nothing about pagination, limits, or behavior on a missing thread.
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; the verb, resource, and return shape all appear immediately.
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?
An output schema exists (so return values needn't be described) and annotations cover the safety profile, making the description nearly sufficient. The only real gap is the undocumented thread_id parameter.
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% for the single required thread_id parameter, so the description carries the full burden — but it says nothing about the id's format, where it comes from, or what happens if it's invalid.
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?
States a specific verb (get) and resource (an entire conversation thread) plus the return shape (ordered list of messages). It implicitly distinguishes itself from get_message and search_messages by scoping to a whole thread, though it never names those siblings explicitly.
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?
No when-to-use, when-not-to-use, or alternative is given. An agent must infer that this is the tool for retrieving a full thread versus a single message, with no explicit routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_labelsARead-onlyIdempotent
List every label on this account (system labels like INBOX/SENT/TRASH plus user labels), with their IDs.
Label IDs from here are what modify_message_labels and search_messages' label_ids argument expect.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds genuinely useful behavior context: the result is a complete enumeration including system labels, and its IDs are the currency expected by other tools — a cross-tool contract not captured in structured fields.
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?
Two short sentences, front-loaded with what is returned, followed by the interoperability note. No filler or restated boilerplate.
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 scope of labels, the presence of IDs, and the downstream consumers of those IDs are all covered; since an output schema exists, return-value formatting need not be explained. Nothing an agent needs in order to call this correctly is missing.
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?
The tool takes zero parameters, so per the rubric the baseline is 4. There is nothing for the description to clarify about argument syntax.
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?
States a specific verb (list) and resource (labels) with explicit scope: every label on the account, system plus user, with IDs. An agent can immediately distinguish this from message- or thread-oriented siblings like get_message and get_thread.
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?
It explains the downstream purpose of the returned IDs — they feed modify_message_labels and search_messages' label_ids argument — which tells the agent why and when to call it. It does not name an explicit alternative for enumerating labels, but no plausible sibling competes for that job.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_messagesARead-onlyIdempotent
Search messages using Gmail's own search syntax.
query accepts exactly what you'd type into the Gmail search box: from:,
to:, subject:, after:YYYY/MM/DD, before:YYYY/MM/DD, has:attachment,
is:unread, is:starred, label:name, and boolean operators (OR, -exclude,
quoted "exact phrases"). Leave query empty to list recent mail instead.
Each result includes the extracted plain-text body, not just a snippet.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | ||
| label_ids | No | ||
| page_token | No | ||
| max_results | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent and non-destructive, so the safety profile is covered. The description adds genuinely non-obvious behavior: results include the extracted plain-text body rather than just a snippet, which shapes how the agent should treat the output.
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 purpose and the query-syntax contract are front-loaded, and every clause adds usable information (syntax examples, empty-query fallback, body extraction) with no filler.
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?
An output schema exists, so return values need no explanation, and the safety profile is annotation-covered. The one gap is pagination semantics for page_token, which the description never addresses for a result-capped search.
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 carry parameter meaning, and it documents only `query` (with extensive syntax help). label_ids, page_token and max_results remain undocumented in both places, so the coverage gap is only partly compensated.
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?
States a specific verb (search) and resource (messages) and immediately scopes it to Gmail's own query syntax, which distinguishes it from the ID-based siblings get_message and get_thread.
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?
Gives clear context for the main input, including the fallback behavior ('Leave query empty to list recent mail instead'), which tells the agent how to enumerate rather than search. It does not name siblings or state when to prefer get_message/get_thread, so it stops short of full routing guidance.
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
get_message - First observed
get_profile - First observed
get_thread - First observed
list_labels - First observed
search_messages
TDQS
Scored across 5 tools
The five tools cover distinct operations: account info (get_profile), label enumeration (list_labels), search (search_messages), single-message retrieval (get_message), and thread retrieval (get_thread). The only wrinkle is that list_labels' description points at a modify_message_labels tool that does not exist, which could send an agent hunting for a phantom tool.
Every tool follows a clean verb_noun snake_case pattern (get_profile, list_labels, search_messages, get_message, get_thread). No mixed conventions or stray casing.
Five tools is a coherent, tightly scoped read-only surface with no redundant entries. It is on the lean side for a full Gmail integration, but nothing feels padded or wasteful.
The surface is read-only: no send, draft, reply, trash, archive, or label-modification operations, and Gmail's primary action (sending mail) is entirely absent. Worse, list_labels references a modify_message_labels tool that is not exposed, a dead end an agent will hit.
Related MCP Connectors
Multiple Gmail accounts, editable Google Sheets & Docs for AI agents. Deny-by-default access rules.
Manage Gmail end-to-end: search, read, send, draft, label, and organize threads. Automate workflow…
Stateful email for AI agents — read inboxes, reply in-thread, draft with approval.
- alfred_OAuthai.get-alfred
Your real Gmail, Outlook and calendars, worked as you: read, draft, send, schedule, organize.
Related MCP Servers
- 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.-
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Gmail through OAuth2 authentication, allowing users to list, search, read emails, and create drafts with a safety-first design that prevents accidental sends by default.62 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage Gmail through natural language interactions, including sending, reading, searching emails, and managing labels with auto authentication support.13,749 npm1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage Gmail through natural language, including sending, reading, searching, labeling emails, managing attachments, and performing thread operations.3MIT