Skip to main content
Glama
SfdcAnnu

Gmail MCP Server

by SfdcAnnu
README.md
# Gmail MCP Server

Public **Gmail** MCP server — Streamable HTTP + OAuth 2.1, same architecture
as the Salesforce and Outlook MCP Servers. One deployed URL works with:

- **Archon AI portal** (Managed MCP via Anthropic / OpenAI)
- **Claude.ai** custom connectors
- **ChatGPT** custom MCP
- Any standalone MCP client (n8n, Cursor, custom apps) via the PATH B flow

## Tools (11)

| Tool | Kind | Description |
|---|---|---|
| `getProfile` | read | Connected Gmail account (email, message counts) |
| `listEmails` | read | List messages by label, filters: unread, sender |
| `readEmail` | read | Full body (text + HTML) of one message |
| `searchEmails` | read | Gmail-syntax search across all mail |
| `listLabels` | read | All labels (Gmail's folders) |
| `getAttachments` | read | Attachment names/types/sizes |
| `sendEmail` | write | Send a new email |
| `replyEmail` | write | In-thread reply / reply-all (proper threading headers) |
| `createDraft` | write | Draft without sending |
| `moveEmail` | write | Archive / trash / apply label |
| `markEmail` | write | Read/unread + star |

## Setup

### 1. Google Cloud OAuth client (one-time)

1. https://console.cloud.google.com → create/select a project
2. **APIs & Services → Library** → enable **Gmail API**
3. **OAuth consent screen** → External → add scope
   `https://www.googleapis.com/auth/gmail.modify` (+ openid, email, profile).
   While the app is in *Testing* status, add your Gmail address under
   **Test users** — otherwise login fails with `access_denied`.
4. **Credentials → Create credentials → OAuth client ID → Web application**
   Authorized redirect URIs:
   - `https://claude.ai/api/mcp/auth_callback` (Claude connector)
   - `<BASE_URL>/auth/callback` (PATH B standalone)

### 2. Run

```bash
cp .env.example .env      # fill in GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET / BASE_URL
npm install
npm run dev               # http://localhost:3200
```

### 3. Deploy (Render)

- Build command: `npm install`
- Start command: `npm start`
- Env vars: `BASE_URL` (the Render URL), `GOOGLE_CLIENT_ID`,
  `GOOGLE_CLIENT_SECRET`, `GOOGLE_REDIRECT_URI=<BASE_URL>/auth/callback`
- After deploy, add `<BASE_URL>/auth/callback` to the Google OAuth client's
  redirect URIs.

## Auth paths

**PATH A — Bearer header (portals, Claude connector).** The client sends
`Authorization: Bearer <google access token>` on `/mcp`. Tokens acquired
through this server's `/token` proxy get vaulted, enabling server-side
refresh when Google returns 401 (Google access tokens live ~1 hour).

**PATH B — session flow (standalone clients).** Visit
`<BASE_URL>/auth?session=<id>` → Google login → tokens stored server-side
keyed by the stable Google account id.

The `/authorize` proxy forces `access_type=offline&prompt=consent` so Google
actually issues a refresh token, and both proxies force the real Google
client credentials so Dynamic Client Registration (Claude invents a random
client id) still works — the only requirement is the client's redirect URI
being whitelisted on the Google OAuth client.

## Gmail-specific notes

- Gmail message ids are opaque hex strings; always source them from
  `listEmails`/`searchEmails` in the same session.
- Gmail has **labels**, not folders. `moveEmail` maps the familiar folder
  actions: archive = remove `INBOX`, trash = the dedicated trash endpoint.
- `replyEmail` fetches the original's `Message-ID`/`References` headers and
  sends with `threadId`, so replies thread correctly in both Gmail and the
  recipient's client.