Gmail MCP Server
Provides least-privilege access to a Gmail inbox for searching emails, reading messages and threads as plain text, and creating draft replies in the original thread without sending them.
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 ServerSearch my inbox for the latest email from Stripe and draft a reply asking for an invoice copy"
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
Least-privilege Gmail access for AI agents over the Model Context Protocol: search, read and draft replies. It never sends.
Contents
Related MCP server: Gmail MCP Server
What it is
A small Model Context Protocol (MCP) server, written in TypeScript, that gives an AI agent least-privilege access to one Gmail inbox. The agent can search mail, read messages and threads as clean plain text, and save draft replies in the correct thread. It cannot send, delete, label or archive mail, or change settings. The server runs locally as a stdio subprocess of the MCP client. It uses OAuth credentials that the mailbox owner creates and keeps, and it has no backend, database or third-party service in between.
Architecture
flowchart LR
A["MCP client<br/>Claude Desktop, Claude Code or an agent"] -- "JSON-RPC over stdio" --> B["gmail-mcp-server<br/>local Node.js process"]
B -- "HTTPS + OAuth 2.0" --> C["Gmail API"]
B -. "reads and refreshes" .-> D[("token.json<br/>local disk")]The client starts the server as a child process and talks to it over stdin and stdout. No network port is opened.
The server calls the Gmail REST API directly with the user's OAuth token, which never leaves the machine.
Every Gmail response is parsed and rendered as plain text before it reaches the model.
Module | Responsibility |
| Entry point: stdio transport, protection of the stdout stream |
|
|
| Authenticated Gmail client, token persistence and refresh, retry policy |
| MIME tree walking, base64url and charset decoding, HTML-to-text, output formatting |
| RFC 2822 reply builder: recipients, subject, threading headers, encoding |
| Classification of Gmail API errors into readable messages |
| One-time OAuth sign-in ( |
| Scopes, environment variables and file paths |
Tools
Tool | What it does | Read-only |
| Searches the mailbox with Gmail query syntax and returns a summary per message | Yes |
| Reads one message: headers, plain-text body, attachment metadata | Yes |
| Reads every message in a thread, oldest first | Yes |
| Saves a plain-text reply as a draft in the original thread. Never sends. | No (creates drafts only) |
All inputs are validated with zod before any Gmail call. Invalid input returns a validation error to the model; Gmail is never called with it. Each tool declares MCP annotations: readOnlyHint: true on the three read tools, and readOnlyHint: false, destructiveHint: false, idempotentHint: false on create_draft_reply.
search_emails
Parameter | Type | Default | Constraints |
| string |
| Gmail search syntax, 1 to 500 characters |
| integer |
| 1 to 25 |
Returns id, threadId, from, to, subject, date, snippet and labels for each match, newest first.
1 message(s) matching "in:inbox":
1. Ticket #123
id: m-meta
threadId: t-200
from: Support <support@vendor.example>
to: me@example.com
date: Sun, 1 Nov 2026 18:00:00 +0000
labels: INBOX, CATEGORY_UPDATES
snippet: We've received your request & will reply soonget_email
Parameter | Type | Constraints |
| string | Gmail id: letters, digits, |
Returns From, To, Cc, Subject, Date and Message-ID; the body as plain text; and each attachment's name, type and size. Attachment content is never downloaded.
Message ID: m-nested
Thread ID: t-100
From: Alice Example <alice@example.com>
To: me@example.com
Cc: Carol <carol@example.com>
Subject: Quarterly invoice
Date: Mon, 2 Nov 2026 09:15:00 +0000
Message-ID header: <CAF1234@mail.example.com>
Attachments (metadata only):
- logo.png (image/png, 2.0 KB)
- invoice-2026-11.pdf (application/pdf, 179.2 KB)
See the attached invoice. Total: 1 200 €. 👍Body extraction:
Walks the full MIME tree, including nested
multipart/*parts.Decodes base64url and the declared charset (for example ISO-8859-1).
Prefers
text/plain. Falls back totext/html, converted with a light tag strip.Truncates bodies over 20,000 characters and says so in the output.
get_thread
Parameter | Type | Constraints |
| string | Gmail id, same rules as |
Returns every message in the thread, oldest first, each in the get_email format.
create_draft_reply
Parameter | Type | Constraints |
| string | The message being replied to |
| string | Plain text, 1 to 50,000 characters, not whitespace-only. Kept exactly as written. |
The draft is built as follows:
Field | Rule |
Recipient | The original's |
Subject | Prefixed with |
Threading |
|
Encoding | RFC 2047 for non-ASCII subjects and display names; UTF-8 body with base64 transfer encoding; |
Draft reply created. It has not been sent.
Draft ID: <id assigned by Gmail>
Thread ID: 18c2e9f8a7b6c5d4
To: Billing Team <billing@example.com>
Subject: Re: Invoice #4711 follow-up
Review and send it from Gmail Drafts.Security model
Scopes
The server requests exactly two OAuth scopes:
Scope | Used for |
| Searching and reading messages and threads |
| Creating drafts |
Gmail has no scope that allows creating drafts without also allowing sending: gmail.compose permits both. Least privilege is therefore enforced in two layers:
The narrowest scopes Gmail offers for this feature set. No
gmail.modifyand no fullmail.google.comaccess, so the token cannot delete mail, change labels or change settings.No send tool. The only write operation in the code is
users.drafts.create, and a person reviews and sends each draft from Gmail.
The second layer is a property of this code, not of the token. Anyone who obtains token.json could send mail as the user, so treat it like a password.
Controls
Risk | Control |
The agent sends mail in the user's name | No send tool. Replies are saved as drafts for a person to review and send. |
The agent deletes or alters mail | No |
Prompt injection through email content | Email is untrusted input to the model. With this tool set, the worst outcome is an unwanted draft, never a sent or deleted message. |
Header injection through a crafted original | CR/LF is stripped from every header value copied from the original message, so |
Malicious attachments | Attachment content is never downloaded; only name, type and size are returned |
Token leakage |
|
Sensitive data in logs | Logs contain the tool name, outcome and duration only, never queries, addresses or message content |
Third-party data exposure | Local stdio process. The mailbox owner creates the OAuth client in their own Google Cloud project, and no intermediary service holds tokens. |
Access can be revoked at any time at myaccount.google.com/permissions.
Setup
Requirements
Node.js 22.12 or later
A Google account
A Google Cloud project you control (free)
1. Create the OAuth client in Google Cloud
In Google Cloud Console, create a project, or select an existing one.
Enable the Gmail API: APIs & Services > Library > Gmail API > Enable.
Configure the OAuth consent screen (Google Auth Platform):
User type: External.
Publishing status: Testing.
Add the Gmail address you will use under Test users.
Create credentials: Clients > Create client, application type Desktop app.
Download the client JSON and save it as
credentials.jsonin the project root.
Note: while the project is in Testing status, Google expires refresh tokens after 7 days, and the tools then ask you to run
npm run authagain. Removing that limit requires publishing the app. Both scopes are classed as restricted by Google, so a public app needs Google's verification, which can include a third-party security assessment. For a single internal mailbox, Testing status or a Google Workspace internal app is the practical option.
2. Install, sign in and build
git clone https://github.com/AlexisG1993/mcp_gmail.git
cd mcp_gmail
npm install
npm run auth # builds, opens the browser, saves token.json
npm run buildnpm run auth:
uses the OAuth loopback flow with PKCE and a
statecheck;verifies that both scopes were granted;
makes one read-only call to confirm access, and prints the signed-in address.
Configuration
Variable | Default | Purpose |
|
| OAuth client file downloaded from Google Cloud |
|
| Saved token, written by |
Relative paths are resolved against the project root, not the working directory, because MCP clients start servers from arbitrary directories.
Connect to Claude
Use the absolute path to dist/index.js. On Windows, forward slashes work (C:/Users/you/mcp_gmail/dist/index.js).
Claude Desktop
Edit claude_desktop_config.json:
OS | Location |
macOS |
|
Windows |
|
{
"mcpServers": {
"gmail": {
"command": "node",
"args": ["/absolute/path/to/mcp_gmail/dist/index.js"]
}
}
}Add an "env" object with GMAIL_CREDENTIALS_PATH and GMAIL_TOKEN_PATH only if the files are not in the project root. Restart Claude Desktop afterwards.
Claude Code
claude mcp add --transport stdio gmail -- node /absolute/path/to/mcp_gmail/dist/index.jsTo keep the files elsewhere, add --env GMAIL_TOKEN_PATH=/secure/path/token.json (and likewise for credentials) before the server name.
Triage demo
examples/triage-demo.ts shows the server used by an agent pipeline instead of a chat client.
It starts the server over stdio with the official MCP client.
It reads the 10 most recent inbox emails through
search_emailsandget_email.It asks Claude to classify each one, using structured JSON output validated against a zod schema:
type:
customer,vendor,adminorotherpriority:
high,normalorlow
It prints a table with a one-line reason for each classification.
export ANTHROPIC_API_KEY=... # PowerShell: $env:ANTHROPIC_API_KEY = "..."
npm run demoThe demo also reads a git-ignored .env file in the project root; variables already set in the shell take precedence.
Variable | Default | Purpose |
| (required) | Claude API key |
|
| Claude model used for classification |
The model is a setting, not a code change. Classification is a small, high-volume task, so the default is the lowest-cost current model. Set TRIAGE_MODEL=claude-sonnet-5-5 or claude-opus-5-5 to compare quality against cost on the same inbox. For models that support it, a request declined by a safety classifier is automatically retried on a fallback model. With other models, a declined email is shown as such in the table.
The demo calls only read tools. It passes the server only the Gmail path variables, never the API key. It also tells the model to treat email content as untrusted data, never as instructions.
Design decisions
stdio transport. The server is a child process of the MCP client on the user's machine. It opens no network port, so there is no listener to authenticate or expose. The OAuth token stays on the same machine as the user. stdout carries only the MCP protocol: all logging goes to stderr, and console.log is redirected to stderr so a dependency cannot corrupt the stream.
Plain-text output. Tools return labelled plain text, not raw Gmail JSON. Models read it reliably, it costs far fewer tokens than the API's nested MIME structure, and every tool presents emails in the same shape. Decoding, charset handling, HTML stripping and truncation happen once, in tested code, instead of being left to the model.
Drafts instead of sending. Sending is irreversible and acts in the user's name. A draft keeps a person in the loop at the one step where a mistake is costly, while still doing the bulk of the work.
Failure handling.
Gmail errors become tool results with
isError: trueand a specific message, never a crash. Examples: not found, rate limited, Gmail API not enabled, sign-in expired.429s, 403 rate-limit errors and 5xx responses are retried with exponential backoff and jitter, at most 3 attempts.
Retry-Afteris honoured, capped at 8 seconds.The Google client library's own retry is switched off, so this is the only retry policy. Left on, a single failing call can make 12 HTTP requests.
Creating a draft is not retried on 5xx, because Gmail may already have saved it and a retry would create a duplicate.
An expired or revoked sign-in is detected, and the cached client is dropped. Running
npm run auththen takes effect without restarting the server.
Minimal dependencies.
Runtime:
@modelcontextprotocol/server(MCP TypeScript SDK v2),googleapis,google-auth-libraryandzod.No HTML parsing library, no framework, no database.
Limitations
One mailbox per server instance. Each instance runs with one token; multiple mailboxes need multiple configured instances.
Plain-text drafts only. Drafts have no HTML formatting and no attachments, and replies go to the sender only (no reply-all).
No attachment content. Attachments are reported by name, type and size only, by design.
Bounded output. Bodies are truncated at 20,000 characters, and search returns at most 25 results with no pagination.
Light HTML conversion. It suits typical email but is not a renderer; complex layouts lose some structure.
Testing-mode tokens. Unpublished Google Cloud projects expire refresh tokens after 7 days.
From demo to production
This server lets an agent work an inbox on request. A production triage system that processes every incoming email unattended needs more:
Capability | Purpose |
Push notifications | Call |
historyId checkpoints | Each notification carries a |
Idempotent ticket ledger | Pub/Sub delivers at least once. Record each Gmail message id before acting on it, so a redelivered notification never creates a second ticket or draft. |
Dead-letter queue | Messages that keep failing (parse errors, model errors, downstream outages) move to a DLQ after a bounded number of attempts, for inspection and replay, without blocking the stream. |
Daily reconciliation sweep | A scheduled job compares recent inbox messages with the ledger and catches anything a dropped notification or outage missed. |
Watch renewal | A watch expires after 7 days. Renew it on a schedule; Google recommends daily, which leaves a wide safety margin. |
Deployment | Run as a service with secrets in a secret manager. For a Google Workspace domain, use a service account with domain-wide delegation instead of a personal OAuth token. Add metrics and alerting on queue depth, error rate and watch expiry. |
Troubleshooting
Message or symptom | Cause and fix |
|
|
| The client was created as a Web application. Create a Desktop app client instead. |
Google shows "Access blocked" or "has not completed the Google verification process" | Your address is not a test user. Add it under Google Auth Platform > Audience > Test users. |
| A permission was unticked on the consent screen. Run |
| Sign-in has not been done for this path. Run |
| Usually the 7-day Testing-mode expiry. Run |
| Enable the Gmail API under APIs & Services > Library. |
| Gmail is throttling the account. Wait a minute and retry. |
The client shows no Gmail tools | Check that the config path points to |
Development
Script | What it does |
| Compiles TypeScript to |
| Runs the server on stdio (normally started by the MCP client instead) |
| Builds, then runs the one-time OAuth sign-in |
| Runs the test suite |
| Strict type-check of source, tests and examples |
| Builds, then runs the triage demo |
src/
index.ts entry point, stdio transport
server.ts McpServer setup and tool registration
auth.ts one-time OAuth flow (npm run auth)
config.ts scopes, env vars and paths
log.ts stderr logger
gmail/
client.ts authenticated Gmail client, retries
parse.ts MIME and body parsing, output formatting
draft.ts RFC 2822 reply builder
errors.ts Gmail error classification
tests/
fixtures/ Gmail-shaped JSON responses
parse.test.ts MIME parsing
draft.test.ts reply building
errors.test.ts error handling and retries
server.test.ts input validation and tool results
examples/
triage-demo.ts MCP client + Claude API classificationTests
npm test # vitest, no network access
npm run typecheck # strict TypeScript, source, tests and examplesThe tests run without network access, using small JSON fixtures shaped like real Gmail API responses.
Area | Coverage |
MIME parsing | Plain-only, HTML-only, |
Draft building | Recipient selection, |
Reliability | Error classification and messages, auth-failure detection, retry behaviour (what is retried, the attempt cap, backoff ranges, the |
Input validation | Defaults, bounds and rejection cases for every tool's schema, and an assertion that nothing is ever written to stdout |
License
MIT. See LICENSE. Release notes are in CHANGELOG.md, and security reports are handled as described in SECURITY.md.
Available Tools
4 toolscreate_draft_replyCreate a draft replyA
Save a plain-text reply to an email as a Gmail draft, in the same thread, addressed to the original sender (its Reply-To if set). Nothing is sent: a person reviews and sends the draft from Gmail.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Plain-text body of the reply. It is saved as a draft and never sent. | |
| message_id | Yes | Id of the email being replied to, as returned by search_emails or get_email. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, destructiveHint=false, idempotentHint=false, openWorldHint=true), the description discloses the important behavioral facts: the reply lands in the same thread, the recipient is derived from Reply-To, and nothing is transmitted externally until a human sends it. It does not address whether repeated calls create duplicate drafts, which is relevant given idempotentHint=false.
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 tight sentences with no waste; the operation and its key constraint (nothing is sent) are front-loaded, and the parenthetical Reply-To detail is compactly integrated.
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 two-parameter tool with full schema coverage and annotations, the description covers purpose, thread/recipient behavior, and the no-send guarantee. The one gap is the return value: with no output schema, an agent cannot tell whether it receives a draft id or thread id from the call.
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 coverage is 100%, so the baseline is 3, but the description adds meaningful semantics: the body is plain-text only, and message_id implicitly determines both the thread and the recipient (no separate recipient parameter exists). That explains a non-obvious consequence of a parameter beyond its schema text.
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 and resource ('Save a plain-text reply ... as a Gmail draft') plus the scope details (same thread, addressed to original sender/Reply-To). This is clearly a draft-creation write operation, unmistakable from the read-only siblings search_emails, get_email, 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?
The phrase 'Nothing is sent: a person reviews and sends the draft from Gmail' establishes the context in which this tool is appropriate (human-in-the-loop drafting) and implicitly rules out use as an auto-send mechanism. It does not name an alternative send tool or state exclusions explicitly, 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.
get_emailRead an emailARead-only
Read one email: headers, plain-text body (HTML converted to text if there is no plain part) and attachment names and sizes. Attachment contents are never returned.
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes | Message id, as returned by search_emails. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so safety is covered. The description adds genuinely useful behavioral facts beyond that: HTML bodies are converted to text when no plain part exists, and attachment contents are never returned, which prevents an agent from promising file contents it cannot get.
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 tight sentences with no filler. The most decision-relevant fact for an agent (what comes back, and that attachment contents do not) is front-loaded in the first sentence, and the negative constraint is isolated in the second.
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?
With no output schema, the description does the job of describing the return payload: headers, body in text form, attachment names and sizes. It falls just short of complete by omitting any notion of body size limits, truncation, or failure modes for invalid ids on a tool flagged openWorldHint.
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 coverage is 100% for the single message_id parameter, including a pattern and a note on where ids come from, so the schema carries the parameter burden. The description adds nothing further about the identifier format or what happens with a malformed or stale id, so the baseline 3 applies.
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?
"Read one email" states a specific verb and resource, and "one" distinguishes it from the sibling search_emails, which returns many. It doesn't explicitly name the siblings it competes with (get_thread, search_emails), so differentiation is implied rather than spelled out.
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 only implied: the schema note "as returned by search_emails" suggests the read-after-search flow, and "one email" signals this is the single-message path rather than the thread or search path. There is no explicit when-to-use/when-not statement and no mention of error behavior for unknown ids.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_threadRead a threadARead-only
Read every message in a thread, oldest first, each in the same format as get_email.
| Name | Required | Description | Default |
|---|---|---|---|
| thread_id | Yes | Thread id, as returned by search_emails or get_email. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds genuine behavior beyond that: deterministic oldest-first ordering, full-thread coverage ("every message"), and a per-message format identical to get_email, which lets an agent parse results without guessing.
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?
One sentence, front-loaded with the core action, with the ordering and format details packed in without waste. Nothing is redundant or padded.
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 simple read-only, one-parameter tool with full schema coverage and annotations, the description supplies what matters: ordering, completeness, and return format by reference to get_email. It does not address behavior on very large threads (truncation or limits), which is the only notable omission.
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 coverage is 100% and the single thread_id parameter is fully documented in the schema, including its pattern and where the id comes from. The description adds nothing about the parameter, which is acceptable given the schema already does that work.
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?
"Read every message in a thread" gives a specific verb (read) and resource (thread), and adds scope (all messages) and ordering (oldest first). It implicitly contrasts with get_email by pointing to that tool's format, though it never names search_emails as the tool for finding a thread id.
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: call it when you have a thread_id and want the whole conversation rather than a single message. There is no explicit when-not guidance, no mention that the thread_id comes from search_emails/get_email (that lives only in the schema), and no stated alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_emailsSearch emailsARead-only
Search the mailbox with Gmail search syntax. Returns id, threadId, from, to, subject, date, snippet and labels for each match, newest first.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Gmail search syntax, e.g. "from:alice is:unread newer_than:7d". Defaults to "in:inbox". | in:inbox |
| max_results | No | How many messages to return, 1 to 25. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only and open-world annotations, it discloses the exact fields returned for each match and the newest-first ordering. Listing snippet rather than body also helps set expectations that results are summaries, though no further operational behavior is described.
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 compact sentences front-load the operation and query syntax, then provide useful result and ordering details. There is no redundant or unnecessary wording.
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 simple search tool with two optional, fully documented parameters, the combined definition supplies the invocation model, defaults, result bounds, returned fields, and ordering. Explicit sibling routing would improve selection guidance but is not essential to invoking the tool 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?
Schema description coverage is 100%, and both parameters already document their syntax, defaults, and limits. The description repeats the Gmail-syntax point but adds no parameter meaning beyond the schema, so the baseline score applies.
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?
“Search the mailbox with Gmail search syntax” gives a specific verb, resource, and query model. The operation is clearly a search rather than a single-item retrieval or draft mutation, but the description does not explicitly differentiate itself from the named siblings.
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 Gmail-syntax query context makes it clear that this tool is for finding matching messages. It does not explicitly direct agents to get_email for full message content or get_thread for conversation context, nor state other exclusions.
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.
4 tool updates
v0.1.0- First observed
create_draft_reply - First observed
get_email - First observed
get_thread - First observed
search_emails
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: search messages, read a single email, read a thread, or create a draft reply. There is no ambiguous overlap; get_email and get_thread differ by message vs. thread scope and descriptions make that clear.
All names use consistent snake_case verb_noun phrasing. The pattern is predictable across search_emails, get_email, get_thread, and create_draft_reply.
Four tools is a reasonable, focused set for a read-and-draft-reply workflow. It is slightly thin for a Gmail server overall, but each included tool earns its place.
The set covers searching, reading, thread reading, and saving draft replies, but omits core Gmail operations such as sending, label management, deletion/trash, and attachment retrieval. These are notable gaps for an agent expecting general Gmail functionality.
Maintenance
Related MCP Connectors
Give AI agents their own email inboxes: list, read and send mail via scoped, revocable OAuth grants.
Email for AI agents: read, search and send from your Gmail, Outlook, Yahoo, iCloud or IMAP inbox.
Manage Gmail end-to-end: search, read, send, draft, label, and organize threads. Automate workflow…
Gmail, Outlook, Drive, OneDrive and calendars for AI agents. Many accounts, one endpoint, audit log.
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.208 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to read unread Gmail messages and create threaded draft replies, without ever sending email automatically.MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to manage Gmail accounts, including reading and searching emails, creating and sending drafts, and handling labels, blocks, and unsubscribes.MIT