Metadata-Version: 2.4
Name: gmail-attachments-mcp
Version: 0.1.0
Summary: A minimal MCP server and CLI for downloading Gmail attachments to disk.
Project-URL: Homepage, https://github.com/zayansalman/gmail-attachments-mcp
Project-URL: Repository, https://github.com/zayansalman/gmail-attachments-mcp
Project-URL: Issues, https://github.com/zayansalman/gmail-attachments-mcp/issues
Author: Zayan Khan
License-Expression: MIT
License-File: LICENSE
Keywords: anthropic,attachments,claude,gmail,mcp,model-context-protocol
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Requires-Dist: google-api-python-client>=2.100.0
Requires-Dist: google-auth-httplib2>=0.2.0
Requires-Dist: google-auth-oauthlib>=1.0.0
Requires-Dist: mcp>=1.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Description-Content-Type: text/markdown

# gmail-attachments-mcp

<!-- mcp-name: io.github.zayansalman/gmail-attachments-mcp -->

A focused [Model Context Protocol](https://modelcontextprotocol.io) server (and standalone CLI) for downloading Gmail attachments to disk. Three tools, read-only OAuth scope, no extra surface area.

Built because the hosted `claude.ai Gmail` connector in Claude Desktop returns attachment **IDs and metadata only** — not the actual bytes. This server fills that gap for any MCP client (Claude Code, Claude Desktop, Cursor, Cline, etc.), and also works as a plain CLI for cron jobs and shell scripts.

If you used [`@GongRzhe/Gmail-MCP-Server`](https://github.com/GongRzhe/Gmail-MCP-Server) (1.1k★, archived 2026-03-03) for its attachment-download workflow, this is a minimal successor focused on that single capability.

## Features

- **3 MCP tools** — `gmail_search`, `gmail_download_thread_attachments`, `gmail_download_latest_matching`. That's the whole API.
- **Read-only OAuth scope** (`gmail.readonly`) — can't send, delete, or modify mail.
- **Works as both an MCP server and a standalone CLI** — same code, same auth token, both surfaces.
- **Env-var-driven config** — `GMAIL_MCP_CREDENTIALS`, `GMAIL_MCP_TOKEN`, `GMAIL_MCP_DEFAULT_DEST_DIR`.
- **Cron-friendly** — once authorized, the cached refresh token lets headless jobs run indefinitely.

## Install

```bash
pip install gmail-attachments-mcp
# or, with uv:
uv tool install gmail-attachments-mcp
```

## One-time setup (~10 minutes)

You need a Google Cloud OAuth client. The server runs entirely on your machine; nothing leaves it.

1. Sign in to [Google Cloud Console](https://console.cloud.google.com/) with the Gmail account whose attachments you want to download.
2. Create a project (or pick an existing one).
3. Enable the Gmail API: [console.cloud.google.com/apis/library/gmail.googleapis.com](https://console.cloud.google.com/apis/library/gmail.googleapis.com).
4. Configure the OAuth consent screen under **APIs & Services → OAuth consent screen**:
   - **Google Workspace** users: User type = **Internal** (no app verification needed).
   - **Personal Gmail** users: User type = **External**. Add your own Gmail address as a test user under "Test users".
5. **APIs & Services → Credentials → + Create credentials → OAuth client ID**
   - Application type: **Desktop app**
   - Download the JSON.
6. Run setup:

```bash
gmail-attachments-mcp setup --import-credentials ~/Downloads/client_secret_*.json
```

A browser window opens for OAuth consent. After consent, a refresh token is cached at `~/.config/gmail-attachments-mcp/token.json` (or `$XDG_CONFIG_HOME/gmail-attachments-mcp/`).

Verify:
```bash
gmail-attachments-mcp status
gmail-attachments-mcp search "has:attachment newer_than:7d" --max 3
```

See [docs/setup-google-oauth.md](docs/setup-google-oauth.md) for screenshots and troubleshooting.

## Use it from Claude Code

```bash
claude mcp add --scope user gmail-attachments gmail-attachments-mcp -- serve
```

Then in any Claude Code session:

> Use the gmail-attachments MCP to download the latest CV from `careers@example.com` to `~/CVs`.

## Use it from Claude Desktop

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (Mac) or `%APPDATA%/Claude/claude_desktop_config.json` (Windows):

```json
{
  "mcpServers": {
    "gmail-attachments": {
      "command": "gmail-attachments-mcp",
      "args": ["serve"]
    }
  }
}
```

Restart Claude Desktop. See [docs/claude-desktop.md](docs/claude-desktop.md) for details.

## Use it from Cursor / Cline / Continue / others

Any MCP client that supports stdio servers. Point it at the same `gmail-attachments-mcp serve` command. See [docs/other-clients.md](docs/other-clients.md).

## Use it from the shell or cron

```bash
# Search
gmail-attachments-mcp search "from:noreply@stripe.com has:attachment newer_than:30d"

# Download every attachment from a specific thread
gmail-attachments-mcp thread 19db831fab15b507 --dest ~/Invoices

# Download from the latest match, only PDFs
gmail-attachments-mcp latest "from:hr@example.com has:attachment" --dest ~/CVs --ext .pdf,.docx
```

Cron example — pull CV attachments hourly:
```cron
0 * * * * /usr/local/bin/gmail-attachments-mcp latest "to:careers@example.com has:attachment newer_than:2d" --dest ~/CVs --ext .pdf,.docx >> ~/.cache/gmail-attachments-mcp.log 2>&1
```

## The 3 MCP tools

### `gmail_search(query, max_results=10)`
Returns thread summaries with attachment filenames. Use Gmail's standard query syntax.

```json
[
  {
    "thread_id": "19db831fab15b507",
    "subject": "Folon Q3 2026 Quarterly Product Recap",
    "sender": "Manon Muhtasin Rahman <manon@example.com>",
    "date": "Thu, 23 Apr 2026 08:35:00 +0600",
    "snippet": "Hi everyone, Attached is...",
    "message_count": 1,
    "attachment_count": 1,
    "attachment_filenames": ["Folon Quarterly Report Q3 2026.pdf"]
  }
]
```

### `gmail_download_thread_attachments(thread_id, dest_dir?, extensions?)`
Downloads every attachment in a thread to disk. Returns `path`, `size_bytes`, `mime_type`, `original_filename` per file.

### `gmail_download_latest_matching(query, dest_dir?, extensions?)`
Convenience: search + download from the single most recent match, in one call.

## Configuration

All paths can be overridden via environment variables.

| Variable | Default | What |
|---|---|---|
| `GMAIL_MCP_CREDENTIALS` | `~/.config/gmail-attachments-mcp/credentials.json` | OAuth client secret JSON |
| `GMAIL_MCP_TOKEN` | `~/.config/gmail-attachments-mcp/token.json` | Cached refresh token |
| `GMAIL_MCP_DEFAULT_DEST_DIR` | `~/Downloads` | Default download destination |
| `GMAIL_MCP_SCOPES` | `https://www.googleapis.com/auth/gmail.readonly` | OAuth scopes (comma-separated) |
| `XDG_CONFIG_HOME` | `~/.config` | Standard XDG override |

## Security

- **Token storage**: refresh token is written to `~/.config/gmail-attachments-mcp/token.json` with mode `0600`. Anyone with shell access to your account can read your Gmail. Treat the file like a password.
- **OAuth scope**: default is `gmail.readonly`. Cannot send, delete, or modify mail. If you change `$GMAIL_MCP_SCOPES`, you're on the hook for the consequences.
- **Credential file**: your OAuth client secret JSON is *not* a password — it identifies your app to Google. But never commit it. The included `.gitignore` blocks the common filenames.
- **OAuth client**: your client lives in *your* Google Cloud project. There's no central server, no telemetry, nothing leaves your machine.

## Troubleshooting

**`No valid Gmail token` when invoked from Claude Desktop / cron**
The first OAuth flow requires a browser. Run `gmail-attachments-mcp setup` once in a terminal where a browser can open. Subsequent runs use the cached refresh token.

**`Token has been expired or revoked`**
Refresh tokens stay valid as long as you use them at least every 6 months and don't revoke them at [myaccount.google.com/permissions](https://myaccount.google.com/permissions). Re-auth:
```bash
gmail-attachments-mcp setup --reauth
```

**`Access blocked: This app's request is invalid`**
On personal Gmail, your OAuth consent screen needs your address listed under **Test users**. Workspace users should select **Internal** audience to avoid this.

**`HttpError 403: Request had insufficient authentication scopes`**
You changed `$GMAIL_MCP_SCOPES` without re-authorizing. Run `gmail-attachments-mcp setup --reauth`.

## Comparison with other Gmail MCP servers

| Server | Scope | Tools | Maintenance |
|---|---|---|---|
| Anthropic hosted `claude.ai Gmail` | Read/write, hosted | many | Active, but **no attachment bytes** |
| [GongRzhe/Gmail-MCP-Server](https://github.com/GongRzhe/Gmail-MCP-Server) | Full mailbox | 19 | **Archived 2026-03-03** |
| [shinzo-labs/gmail-mcp](https://github.com/shinzo-labs/gmail-mcp) | Full mailbox | ~30 | Active |
| **gmail-attachments-mcp** (this) | **read-only** | **3** | Active |

Pick this one if you want a tiny, focused, read-only tool. Pick a fuller one if you also need to send mail, manage labels, drafts, threads, etc.

## Authentication — bring your own Google OAuth client

There are **no API keys and no shipped secrets**. The server authenticates to *your* Google account with an OAuth client *you* create, and caches a refresh token locally. The author has zero access to your data.

- **Why your own client?** Google's restricted scopes (here, `gmail.readonly`) can't be redistributed in a shared app, and an unverified shared app is capped at 100 users. "Bring your own OAuth client" is the standard pattern for personal-data MCP servers.
- **What you need:** a free Google Cloud project, the Gmail API enabled, an OAuth consent screen, and a Desktop OAuth client. Full walkthrough → [docs/setup-google-oauth.md](docs/setup-google-oauth.md).
- **Where your token lives:** `~/.config/gmail-attachments-mcp/token.json` (mode `0600`). Delete it to revoke locally; revoke fully at [myaccount.google.com/permissions](https://myaccount.google.com/permissions).
- **No hosted/SaaS option** — everything runs locally; your mail never touches a third-party server.

## Related tools

Part of a small family of focused, local MCP servers for Google Workspace data the hosted connectors don't expose:

- **gmail-attachments-mcp** — download Gmail attachment bytes to disk *(this repo)*
- **[google-drive-comments-mcp](https://github.com/zayansalman/google-drive-comments-mcp)** — read comment threads on Docs/Sheets/Slides
- **[google-drive-files-mcp](https://github.com/zayansalman/google-drive-files-mcp)** — move/organize Drive files

They can share one OAuth login or stay isolated — see each repo's setup.

## License

MIT. See [LICENSE](LICENSE).

## Contributing

Issues and PRs welcome. Run `pytest` and `ruff check src tests` before submitting.

```bash
git clone https://github.com/zayansalman/gmail-attachments-mcp
cd gmail-attachments-mcp
pip install -e ".[dev]"
pytest
```
