Gmail MCP Server
Provides tools for reading, sending, searching, labeling, and filtering emails through Gmail API, including attachment support and structured JSON responses.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Gmail MCP Servershow me my unread emails from yesterday"
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 Model Context Protocol server for Gmail. Lets AI assistants read, send, search, label, and filter Gmail through natural language, with OAuth2 auto-authentication and full attachment support.
Built with TypeScript, Bun, and the googleapis client.
Highlights
Structured JSON responses.
read_emailandsearch_emailsreturn parseable JSON objects, not pre-formatted text. Easier for downstream tools to consume without fragile string parsing. (See Structured responses below.)Full attachment support. Send files, read attachment metadata, and download attachments to disk. Path traversal is blocked at the download boundary.
HTML-first email reading. When a message has both plain text and HTML parts, both are returned so the client can pick.
Comprehensive label management. Create, update, delete, list, and get-or-create labels. System labels are protected from deletion.
Gmail filter management. Full CRUD on filters plus six templates (
fromSender,withSubject,withAttachments,largeEmails,containingText,mailingList).Batch operations. Modify or delete many messages in one call, with graceful per-item fallback if a batch fails.
RFC 2047 subject encoding for international characters.
Typed input validation via Zod schemas on every tool.
Error responses set
isError: trueso MCP clients can distinguish failures from successes.Automated releases via semantic-release on every push to
main.
Installation
1. Clone and build
git clone https://github.com/simiancraft/Gmail-MCP-Server.git
cd Gmail-MCP-Server
bun install
bun run build2. Create Google Cloud OAuth credentials
Go to the Google Cloud Console and create (or select) a project.
Enable the Gmail API for the project.
Under APIs & Services → Credentials, click Create Credentials → OAuth client ID.
Choose Desktop app or Web application. For Web application, add
http://localhost:3000/oauth2callbackto the authorized redirect URIs.Download the JSON, rename it to
gcp-oauth.keys.json.
3. Authenticate
mkdir -p ~/.gmail-mcp
mv gcp-oauth.keys.json ~/.gmail-mcp/
bun dist/index.js authThe auth command:
Looks for
gcp-oauth.keys.jsonin the current directory or~/.gmail-mcp/.Opens your browser to the Google consent screen.
Saves the resulting token to
~/.gmail-mcp/credentials.json.
Credentials can be overridden with environment variables:
GMAIL_OAUTH_PATH— path to the client keys JSONGMAIL_CREDENTIALS_PATH— path to the stored user token JSON
4. Wire it into your MCP client
Example for Claude Desktop:
{
"mcpServers": {
"gmail": {
"command": "bun",
"args": ["/absolute/path/to/Gmail-MCP-Server/dist/index.js"]
}
}
}With custom credential paths:
{
"mcpServers": {
"gmail": {
"command": "bun",
"args": ["/absolute/path/to/Gmail-MCP-Server/dist/index.js"],
"env": {
"GMAIL_OAUTH_PATH": "/path/to/gcp-oauth.keys.json",
"GMAIL_CREDENTIALS_PATH": "/path/to/credentials.json"
}
}
}
}Structured responses
This is the most important behavioral difference worth calling out: read_email and search_emails return structured JSON rather than pre-formatted text blobs. The JSON is embedded in the MCP content[0].text field, so clients can JSON.parse it directly.
read_email response
{
"messageId": "182ab45cd67ef",
"threadId": "182ab45cd67ef",
"subject": "Project Files",
"from": "sender@example.com",
"to": "recipient@example.com",
"date": "Thu, 19 Jun 2025 10:30:00 -0400",
"body": {
"text": "Plain text version of the email...",
"html": "<html>Rich HTML version...</html>"
},
"attachments": [
{
"id": "ANGjdJ9fkTs...",
"filename": "document.pdf",
"mimeType": "application/pdf",
"size": 250880
}
]
}body.text and body.html are independently null when the message does not contain that part. Most transactional/vendor email is HTML-only; some plain-text-only senders only populate text.
search_emails response
[
{
"id": "182ab45cd67ef",
"subject": "Project Files",
"from": "sender@example.com",
"date": "Thu, 19 Jun 2025 10:30:00 -0400"
}
]All other tools return human-readable status text in content[0].text (e.g. "Email sent successfully with ID: ...").
Tool reference
All 19 tools accept validated JSON input. Required fields are called out explicitly; everything else is optional.
send_email
Sends a new email. Supports plain text, HTML, multipart, attachments, and threading.
{
"to": ["recipient@example.com"],
"subject": "Meeting Tomorrow",
"body": "Hi, reminder about our meeting.",
"mimeType": "text/plain",
"cc": ["cc@example.com"],
"bcc": ["bcc@example.com"],
"attachments": ["/path/to/file.pdf"],
"threadId": "182ab45cd67ef",
"inReplyTo": "<message-id@example.com>"
}mimeTypedefaults totext/plain. Usetext/htmlfor HTML-only, ormultipart/alternativewith bothbodyandhtmlBodyfor clients that can render either.Attachments are validated for existence before send.
draft_email
Same input as send_email but creates a draft instead of sending.
read_email
Retrieves full content of a message. See Structured responses.
{ "messageId": "182ab45cd67ef" }search_emails
Searches using Gmail search syntax. Returns an array of metadata (see Structured responses).
{
"query": "from:sender@example.com after:2024/01/01 has:attachment",
"maxResults": 10
}modify_email
Adds or removes labels on a single message. If both addLabelIds and labelIds are provided, addLabelIds takes precedence.
{
"messageId": "182ab45cd67ef",
"addLabelIds": ["IMPORTANT"],
"removeLabelIds": ["INBOX"]
}delete_email
Permanently deletes an email. Irreversible.
{ "messageId": "182ab45cd67ef" }download_attachment
Downloads an attachment to disk. Filenames are sanitized (path.basename) and the resolved output path is verified to stay inside savePath to prevent traversal.
{
"messageId": "182ab45cd67ef",
"attachmentId": "ANGjdJ9fkTs...",
"savePath": "/path/to/downloads",
"filename": "custom-name.pdf"
}savePath defaults to the current working directory. filename defaults to the original filename from the message.
Batch
batch_modify_emails
Adds/removes labels on many messages at once. Falls back to per-item retry if a batch fails.
{
"messageIds": ["id1", "id2", "id3"],
"addLabelIds": ["IMPORTANT"],
"removeLabelIds": ["INBOX"],
"batchSize": 50
}batch_delete_emails
Permanently deletes many messages in batches.
{
"messageIds": ["id1", "id2", "id3"],
"batchSize": 50
}Labels
list_email_labels
Lists all labels, split into system and user groups.
{}create_label
{
"name": "Important Projects",
"messageListVisibility": "show",
"labelListVisibility": "labelShow"
}update_label
{
"id": "Label_1234567890",
"name": "Urgent Projects"
}delete_label
Refuses to delete system labels.
{ "id": "Label_1234567890" }get_or_create_label
Idempotent. Returns the existing label if one with that name exists; otherwise creates it. The response tells you which happened.
{
"name": "Project XYZ",
"messageListVisibility": "show",
"labelListVisibility": "labelShow"
}Filters
create_filter
{
"criteria": {
"from": "newsletter@company.com",
"hasAttachment": false
},
"action": {
"addLabelIds": ["Label_Newsletter"],
"removeLabelIds": ["INBOX"]
}
}list_filters, get_filter, delete_filter
{}{ "filterId": "ANe1Bmj..." }create_filter_from_template
Six templates: fromSender, withSubject, withAttachments, largeEmails, containingText, mailingList.
{
"template": "fromSender",
"parameters": {
"senderEmail": "notifications@github.com",
"labelIds": ["Label_GitHub"],
"archive": true
}
}Gmail search syntax
search_emails accepts any standard Gmail search operator:
Operator | Example | Description |
|
| Emails from a specific sender |
|
| Emails to a specific recipient |
|
| Subject match |
|
| Has attachments |
|
| After a date |
|
| Before a date |
|
| Message state |
|
| Has a specific label |
Combine freely: from:john@example.com after:2024/01/01 has:attachment.
Security
OAuth credentials are stored locally in
~/.gmail-mcp/(or the paths set in env vars). Never commit them.Attachment downloads validate the resolved output path against
savePathto block path traversal via crafted filenames.The server requests
gmail.modifyandgmail.settings.basicscopes — enough to read/send/label/filter, but not to change account settings beyond filters.Offline access is used so the token refreshes without re-consent. Revoke in your Google Account → Security → Third-party access if you want to kill it.
Error responses set
isError: trueso clients can distinguish failures from successes rather than pattern-matching on text.
Development
bun install # install dependencies
bun run build # compile TypeScript to dist/
bun test # run the test suite (53 tests)
bun run lint # biome check
bun run lint:fix # biome auto-fix
bun run format # biome formatTests live alongside source as src/*.test.ts and use Bun's built-in test runner. Running bun test discovers them automatically — no extra config.
Commit style
This project uses Conventional Commits and semantic-release. Pushes to main with the right prefix automatically bump the version and publish a GitHub Release.
Prefix | Bump | Example |
| patch |
|
| minor |
|
| major |
|
| no release |
|
Troubleshooting
OAuth keys not found. Make sure
gcp-oauth.keys.jsonis in~/.gmail-mcp/(or in your current working directory at auth time).Invalid credentials format. The keys file must contain either a
weborinstalledblock. For web apps, verifyhttp://localhost:3000/oauth2callbackis in the authorized redirect URIs.Port 3000 already in use. Free it before running
bun dist/index.js auth— the OAuth callback server listens there.Batch operation failures. Batches automatically retry per-item; check the returned failure list. If you're hitting rate limits, lower
batchSize.Attachment send fails. Verify paths exist and are readable. Gmail's per-message attachment cap is 25 MB.
License
MIT. See LICENSE.
History
This project started as a clone of gongrzhe/server-gmail-autoauth-mcp in 2025. It has since diverged substantially — rewritten build/runtime to Bun, added semantic-release, restructured source into separate schemas/label/filter modules, added a full test suite, changed read_email and search_emails to return structured JSON, and tightened security, error handling, and type safety. The LICENSE file preserves the original MIT copyright, per the license's requirements.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/simiancraft/Gmail-MCP-Server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server