# Gmail MCP Server
An MCP (Model Context Protocol) server that provides Gmail access through OAuth 2.0 authentication.
## Prerequisites
- [Bun](https://bun.sh/) runtime
- Google Cloud project with Gmail API enabled
- OAuth 2.0 credentials from Google Cloud Console
## Setup
### 1. Google Cloud Configuration
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create a new project or select an existing one
3. Enable the Gmail API
4. Go to "Credentials" and create an OAuth 2.0 Client ID
5. Set the application type to "Web application"
6. Add `http://localhost:3000/callback` as an authorized redirect URI
7. Download the credentials and save as `credentials.json` in the project root
Note: You may need to add your testing email address to the list of Test users in the Audience tab on your project if you want to test the integration before publishing the project.
The `credentials.json` should have this structure:
```json
{
"web": {
"client_id": "your-client-id",
"client_secret": "your-client-secret",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"redirect_uris": ["http://localhost:3000/callback"]
}
}
```
### 2. Install Dependencies
```bash
bun install
```
### 3. Start the Servers
```bash
bun run start
```
This starts both:
- Auth server on `http://localhost:3000`
- MCP server on `http://localhost:3001`
### 4. Configure with Claude
#### Claude Code
Add the MCP server to Claude Code:
```bash
claude mcp add gmail --transport http http://localhost:3001/mcp
```
Make sure the servers are running before using the MCP in Claude Code.
#### Claude Desktop
Claude Desktop doesn't natively support streamable HTTP MCP servers, so you need to use the [mcp-remote](https://www.npmjs.com/package/mcp-remote) package as a bridge. For more details, see:
- [MCP discussion on HTTP+SSE transport support](https://github.com/orgs/modelcontextprotocol/discussions/16)
- [Cloudflare guide: Connect remote MCP server to Claude Desktop via local proxy](https://developers.cloudflare.com/agents/guides/test-remote-mcp-server/#connect-your-remote-mcp-server-to-claude-desktop-via-a-local-proxy)
Edit your Claude Desktop config file:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
Add the following configuration:
```json
{
"mcpServers": {
"gmail-mcp": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:3001/mcp",
"--allow-http"
]
}
}
}
```
**Important: Node.js Version Requirements**
The `mcp-remote` package requires Node.js >= 20.18.1. If you encounter errors like `ReferenceError: File is not defined`, your Claude Desktop is using an older Node.js version.
To fix this, specify the full path to a compatible Node.js installation and set the PATH explicitly:
```json
{
"mcpServers": {
"gmail-mcp": {
"command": "/path/to/node/v22/bin/npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:3001/mcp",
"--allow-http"
],
"env": {
"PATH": "/path/to/node/v22/bin:/usr/local/bin:/usr/bin:/bin"
}
}
}
}
```
For nvm users on macOS, replace `/path/to/node/v22/bin` with something like:
```
/Users/<username>/.nvm/versions/node/v22.21.1/bin
```
After updating the config, restart Claude Desktop completely (Cmd+Q on macOS, then reopen).
### 5. Authenticate the MCP in Claude
#### Claude Code
Once you have run Claude Code, authenticate the MCP by entering:
```bash
/mcp
```
to see your list of MCPs.
Select the Gmail MCP and follow the prompts to authenticate.
#### Claude Desktop
After restarting Claude Desktop with the configuration above, you'll be prompted to authenticate via the OAuth flow in your browser. Once authenticated, you can use the Gmail MCP tools.
## Available Tools
### get_unread_emails
Fetches unread emails from your Gmail account.
#### Example Prompts
```
please check to see if i have any emails
check my emails please
```
Claude Desktop


Claude Code

This should return a list of unread emails. You can then use the `create_draft_reply` tool to reply to an email.
### create_draft_reply
Creates a draft reply to an email. Properly threads the reply with the original conversation.
#### Example Prompts
```text
reply to the first one and say good to meet you too
please reply to the first email and say "Hello nice to meet you!"
```
Claude Desktop


Claude Code

### Success!
Draft Email

## Architecture
- `src/mcp-server.ts` - MCP server that exposes Gmail tools and proxies OAuth endpoints
The MCP server has two tools available to it for use with Gmail: `get_unread_emails` and `create_draft_reply`.
At the project outset, I chose to use the `Bun` runtime due to its ease of setup, simple compatibility with running TypeScript files and also because it was recently acquired by Anthropic, so I thought it would make a good fit.
However, during development, I discovered that it doesn't have good compatibility with the modelcontextprotocol SDK, and in particular the Streamable HTTP transport architecture due to the use of Node APIs. I found an [experiment pull request](https://github.com/modelcontextprotocol/typescript-sdk/pull/1209) raised by the maintainers which provides support for web standards which works with `Bun`. This is implemented in `src/fetch-streamable-http-transport.ts`.
Any requests to authentication endpoints on the MCP port are proxied to the auth server which needs to be running at the same time as the MCP server.
- `src/auth-server.ts` - OAuth 2.0 authorisation server that handles Google OAuth flow.
The auth server acts as an OAuth proxy between the MCP client (i.e. Claude) and Google. When Claude needs Gmail access, it sends a request to `/authorize`, which is proxied to the auth server. The auth server then redirects the user to Google's OAuth flow. After the user authenticates with Google, the `/callback` endpoint exchanges Google's code for a real Google token, stores it, and issues its own auth code back to Claude. When Claude exchanges that code at `/token`, it gets a proxy token that maps to the stored Google token. The `/introspect` endpoint lets the MCP server validate tokens and retrieve the actual Google access token for making Gmail API calls.
## Development
Run individual servers:
```bash
# MCP server only
bun run start:mcp
# Auth server only
bun run start:auth
```