MCP Servers

模型上下文协议服务器、框架、SDK 和模板的综合目录。

G
Gmail MCP Server

MCP server by simiancraft

创建于 4/8/2026
更新于 2 days ago
Repository documentation and setup instructions

Gmail MCP Server

CI License: MIT node semantic-release Checked with Biome

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_email and search_emails return 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: true so 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 build

2. Create Google Cloud OAuth credentials

  1. Go to the Google Cloud Console and create (or select) a project.
  2. Enable the Gmail API for the project.
  3. Under APIs & Services → Credentials, click Create Credentials → OAuth client ID.
  4. Choose Desktop app or Web application. For Web application, add http://localhost:3000/oauth2callback to the authorized redirect URIs.
  5. 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 auth

The auth command:

  • Looks for gcp-oauth.keys.json in 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 JSON
  • GMAIL_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.

Email

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>"
}
  • mimeType defaults to text/plain. Use text/html for HTML-only, or multipart/alternative with both body and htmlBody for 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 | |---|---|---| | from: | from:john@example.com | Emails from a specific sender | | to: | to:mary@example.com | Emails to a specific recipient | | subject: | subject:"meeting notes" | Subject match | | has:attachment | has:attachment | Has attachments | | after: | after:2024/01/01 | After a date | | before: | before:2024/02/01 | Before a date | | is: | is:unread | Message state | | label: | label:work | 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 savePath to block path traversal via crafted filenames.
  • The server requests gmail.modify and gmail.settings.basic scopes — 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: true so 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 format

Tests 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 | |---|---|---| | fix: | patch | fix: handle missing attachment header | | feat: | minor | feat: add batch label operations | | feat!: / BREAKING CHANGE: | major | feat!: change auth flow | | chore:, docs:, ci:, refactor:, test: | no release | chore: update biome config |

Troubleshooting

  1. OAuth keys not found. Make sure gcp-oauth.keys.json is in ~/.gmail-mcp/ (or in your current working directory at auth time).
  2. Invalid credentials format. The keys file must contain either a web or installed block. For web apps, verify http://localhost:3000/oauth2callback is in the authorized redirect URIs.
  3. Port 3000 already in use. Free it before running bun dist/index.js auth — the OAuth callback server listens there.
  4. Batch operation failures. Batches automatically retry per-item; check the returned failure list. If you're hitting rate limits, lower batchSize.
  5. 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.

快速设置
此服务器的安装指南

安装包 (如果需要)

npx @modelcontextprotocol/server-gmail-mcp-server

Cursor 配置 (mcp.json)

{ "mcpServers": { "simiancraft-gmail-mcp-server": { "command": "npx", "args": [ "simiancraft-gmail-mcp-server" ] } } }