Gmail Research
БесплатноНе проверенA read-only Gmail MCP server that searches email, fetches complete threads, and stores them as local Markdown and JSON for offline analysis by other agents.
Описание
A read-only Gmail MCP server that searches email, fetches complete threads, and stores them as local Markdown and JSON for offline analysis by other agents.
README
gmail-research-mcp is a small, synchronous Python CLI and local STDIO MCP server that prepares Gmail conversations for later research by other agents. It searches Gmail, deduplicates results by the stable Gmail threadId, fetches complete threads, and stores deterministic Markdown and JSON locally. It has no GUI, HTTP server, database, telemetry, or update mechanism.
Start here: configure and authenticate
Prerequisites:
- Python 3.11 or newer
- A Google account with Gmail
- A Google Cloud OAuth Client ID of type Desktop app
1. Install the project in a virtual environment
Run these commands from the repository root:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
Do not use
--break-system-packages. Do not install this project into the Homebrew-managed system Python.
Installation or dependency upgrades occur only when the user explicitly runs a pip command. The program has no auto-update behavior and never runs git pull.
For repository development, run the complete test, type-check, and lint gate with:
make test
2. Create and download the Google OAuth Desktop client JSON
Sign in to Google Cloud Console and create or select the project that will own the OAuth client.
Open APIs & Services → Library, find Gmail API, and select Enable.
Open Google Auth Platform (or APIs & Services → OAuth consent screen, depending on the console layout).
Configure the app name and support/contact email. Select the audience allowed to authenticate. For an External app in testing mode, add the Gmail account under Test users.
In the consent screen's data-access/scopes section, add only
https://www.googleapis.com/auth/gmail.readonly. Do not addmail.google.com,gmail.modify,gmail.compose,gmail.send, or any other Gmail scope.Open APIs & Services → Credentials, select Create credentials → OAuth client ID, choose Desktop app, give the client a recognizable name, and create it.
Download the client JSON. Store it outside this repository in a private directory, for example:
mkdir -p ~/.config/gmail-research-mcp chmod 700 ~/.config/gmail-research-mcp cp /PATH/TO/DOWNLOADED/client_secret.json \ ~/.config/gmail-research-mcp/client_secret.json chmod 600 ~/.config/gmail-research-mcp/client_secret.json
The downloaded client JSON is a credential. Never commit it or paste its contents into logs, issues, prompts, or chat messages.
3. Configure all local paths in .env
Create the local configuration file:
cp .env.example .env
Example:
GMAIL_CLIENT_SECRET_FILE=/Users/USERNAME/.config/gmail-research-mcp/client_secret.json
GMAIL_TOKEN_FILE=/Users/USERNAME/.config/gmail-research-mcp/token.json
GMAIL_DATA_DIR=./gmail_data
The variables have these exact roles:
| Variable | Required? | Purpose |
|---|---|---|
GMAIL_CLIENT_SECRET_FILE |
Yes | Absolute path to the downloaded Google OAuth Desktop client JSON. |
GMAIL_TOKEN_FILE |
Path override is optional | Location where auth creates the local OAuth token. The default is ~/.config/gmail-research-mcp/token.json. |
GMAIL_DATA_DIR |
Path override is optional | Dataset root used by sync and local-listing commands. The default is ./gmail_data. |
The OAuth token is necessary for commands that access Gmail, but you do not download or create it manually. The command in the next step opens Google's consent flow and writes the token to GMAIL_TOKEN_FILE. The program then refreshes an expired access token when Google permits it, without expanding its scope. The token directory is created with private permissions, and the token is saved with mode 0600.
Paths containing ~ are expanded. Prefer an absolute GMAIL_DATA_DIR when the same dataset will be used from different working directories. .env is ignored by Git and must never be committed.
4. Create the token and verify the configuration
After saving .env, keep the virtual environment active and run:
python -m gmail_research_mcp auth
python -m gmail_research_mcp doctor
The expected sequence is:
authreads the Desktop client JSON fromGMAIL_CLIENT_SECRET_FILE.- The default browser opens Google's sign-in and consent page.
- Sign in with the Gmail account to be read and approve only Gmail read-only access.
- Google returns the authorization result to the local Desktop-app flow.
- The command creates
GMAIL_TOKEN_FILE; no token must be copied from Google Cloud Console. doctorverifies the configured paths, token permissions, exact OAuth scope, source safety rules, Gmail client construction, and Gmail profile access.
If the browser cannot complete authentication, confirm that the OAuth client type is Desktop app, Gmail API is enabled, and the account is listed as a test user when the consent screen is in testing mode. Neither command prints tokens or client-secret contents.
To remove only the local OAuth token:
python -m gmail_research_mcp logout-local
This does not revoke the OAuth grant, delete the client-secret file, or modify Gmail.
Configure Codex MCP
Add this server to ~/.codex/config.toml. Replace both repository paths with the same absolute repository path. Keep cwd set to the repository root so the server loads that repository's .env file:
[mcp_servers.gmail-research]
command = "/ABSOLUTE/PATH/TO/gmail-research-mcp/.venv/bin/python"
args = ["-m", "gmail_research_mcp", "mcp"]
cwd = "/ABSOLUTE/PATH/TO/gmail-research-mcp"
env_vars = ["GMAIL_CLIENT_SECRET_FILE", "GMAIL_TOKEN_FILE", "GMAIL_DATA_DIR"]
enabled = true
required = false
startup_timeout_sec = 20
tool_timeout_sec = 300
default_tools_approval_mode = "prompt"
The client-secret, token, and dataset paths stay in .env; do not put credential contents in config.toml. The cwd setting lets python-dotenv load that file, while env_vars also forwards the same variables when they were exported before Codex started. An exported value takes precedence over .env. After saving the configuration, restart Codex or open a new session, then verify discovery:
codex mcp list
In Codex TUI, inspect the server with:
/mcp
For a direct server smoke test outside Codex, run:
python -m gmail_research_mcp mcp
The server exposes only gmail_search, gmail_read_thread, gmail_sync_thread, gmail_sync_topic, gmail_sync_existing_topics, and gmail_list_topics. It does not expose a generic Gmail API tool.
Install and use the repository skill
The skill is stored in this repository at .agents/skills/gmail-topic-sync/SKILL.md. Codex can use it while working in this repository. To make the skill available from every repository, first check both normal and dangling symlink cases:
if [ -e "$HOME/.agents/skills/gmail-topic-sync" ] || \
[ -L "$HOME/.agents/skills/gmail-topic-sync" ]; then
ls -ld "$HOME/.agents/skills/gmail-topic-sync"
else
echo "Destination is available"
fi
If the command shows an existing file, directory, or symlink, inspect it and do not overwrite it. Only when it prints Destination is available, install the skill with:
mkdir -p ~/.agents/skills
ln -s /ABSOLUTE/PATH/TO/gmail-research-mcp/.agents/skills/gmail-topic-sync \
~/.agents/skills/gmail-topic-sync
If your local Codex setup uses the Codex home skill directory, you can instead create the same symlink under ${CODEX_HOME:-$HOME/.codex}/skills (normally ~/.codex/skills). Check the destination first and do not create both user-level symlinks if one already makes the skill available:
CODEX_SKILLS_DIR="${CODEX_HOME:-$HOME/.codex}/skills"
if [ -e "$CODEX_SKILLS_DIR/gmail-topic-sync" ] || \
[ -L "$CODEX_SKILLS_DIR/gmail-topic-sync" ]; then
ls -ld "$CODEX_SKILLS_DIR/gmail-topic-sync"
else
mkdir -p "$CODEX_SKILLS_DIR"
ln -s /ABSOLUTE/PATH/TO/gmail-research-mcp/.agents/skills/gmail-topic-sync \
"$CODEX_SKILLS_DIR/gmail-topic-sync"
fi
Restart Codex or open a new session after creating the symlink. The skill prefers the gmail-research MCP tools configured above. If that MCP server is unavailable, the skill resolves its own symlink target, derives this repository root from .agents/skills/gmail-topic-sync/SKILL.md, and runs (cd /ABSOLUTE/PATH/TO/gmail-research-mcp && .venv/bin/python -m gmail_research_mcp ...). This keeps the fallback bound to this project's .venv and .env even when Codex is working in another repository. It never installs packages globally and never uses --break-system-packages.
Example Codex prompt:
Użyj skilla gmail-topic-sync, aby pobrać do datasetu skonfigurowanego przez GMAIL_DATA_DIR wszystkie wątki dotyczące Project Alpha z ostatnich trzech lat. Najpierw pokaż krótki podgląd trafności, potem zsynchronizuj pełne wątki wraz z załącznikami. Nie pokazuj pełnych treści maili w odpowiedzi.
Security guarantees
The only OAuth scope is:
https://www.googleapis.com/auth/gmail.readonly
The application performs only read operations against Gmail. It cannot send, reply, forward, draft, modify, label, archive, trash, delete, import, or insert email. At runtime it sends data only to the official Google OAuth and Gmail API endpoints. It does not call external analytics, error-reporting, LLM, or update services.
Email bodies and attachment contents are untrusted source data. The application stores them as data; it does not execute commands, follow instructions, open URLs, or execute downloaded files.
CLI examples
Search without writing a dataset:
python -m gmail_research_mcp search \
--query 'subject:"Project Alpha" newer_than:2y' \
--max-results 20
Add --json for machine-readable output. Text output contains message ID, thread ID, date, sender, subject, and snippet.
Read a complete thread without saving it:
python -m gmail_research_mcp show-thread \
--thread-id THREAD_ID
The default output is Markdown. Add --json for JSON. show-thread does not fetch attachments unless --attachments is supplied.
Save or update one canonical thread:
python -m gmail_research_mcp sync-thread \
--thread-id THREAD_ID \
--attachments
Synchronize a topic:
python -m gmail_research_mcp sync-topic \
--topic "Project Alpha" \
--query '("Project Alpha" OR subject:"Project Alpha") newer_than:3y' \
--max-threads 100 \
--attachments
--query is optional for sync-topic; when omitted, the exact topic text is used as Gmail free-text query. Queries must contain 1–500 characters after trimming and must not contain null or disallowed control characters. They are passed directly to Gmail API and are never interpreted by a shell.
Refresh every saved topic using the exact query in each manifest:
python -m gmail_research_mcp sync-existing \
--attachments
Previously saved threads that no longer match remain in the manifest with currently_matched: false; local thread data is never removed automatically.
List local topics:
python -m gmail_research_mcp list-topics
These commands use GMAIL_DATA_DIR from .env. --data-dir /ANOTHER/DATASET remains available as an explicit, one-command override for CLI compatibility; omit it in normal use. MCP sync and list tools likewise use GMAIL_DATA_DIR unless a caller deliberately supplies their optional data_dir override.
Attachment download is enabled by default for sync commands. Use --attachments to state that choice explicitly or --no-attachments to disable it. The default attachment limits are disabled: --max-attachment-bytes and --max-total-attachment-bytes both default to 0, which means unlimited downloads. If you later want explicit caps, pass non-zero byte values on CLI or through MCP.
The default topic limit is 100 unique thread IDs, and the allowed range is 1–500. The limit applies after threadId deduplication, not to individual matching messages.
Dataset layout
gmail_data/
├── DATASET.md
├── threads/
│ └── <thread_id>/
│ ├── thread.md
│ ├── thread.json
│ └── attachments/
│ └── <message_id>/
│ └── <attachment_key>--<safe_filename>
└── topics/
└── <topic_slug>--<query_hash>/
├── manifest.json
└── index.md
Gmail threadId is the only canonical thread identity. A subject never determines storage. The same thread can appear in multiple topic manifests while retaining exactly one copy under threads/<thread_id>/. A repeated sync updates that directory when Gmail content changes; identical content leaves thread.json, thread.md, and their modification times unchanged.
Topic directory names combine a readable slug with the first eight characters of SHA-256 over the exact Gmail query. Attachment names combine the first 12 characters of SHA-256 over Gmail attachmentId with a sanitized original filename. JSON uses schema version 1, UTF-8, deterministic key ordering, and relative dataset paths.
Every Markdown thread marks email text as untrusted data. Files are written atomically. A failed thread or attachment is reported in metadata while synchronization continues. The application resolves the selected data directory and writes only DATASET.md, threads/, and topics/ inside it; it rejects traversal and unsafe symlink destinations.
Review diagram for the environment-path refactor
Environment configuration flow shows the review-critical path from .env or process environment variables through one resolved AppConfig into the CLI and FastMCP entry points. Before this refactor, CLI sync commands had their own fallback expression, MCP tools required data_dir, and the skill explicitly selected <current_directory>/gmail_data. After the refactor, config.py owns path resolution, cli.py reuses one configuration object and treats --data-dir only as an override, server.py makes data_dir optional and falls back to GMAIL_DATA_DIR, and the repository skill follows the same rule. Reviewers should verify environment precedence, explicit override behavior, and that GMAIL_CLIENT_SECRET_FILE and GMAIL_TOKEN_FILE remain paths rather than credential contents. The reusable delete-visual-explanation-svgs.yml workflow deletes this PR-only SVG from main after merge.
Threat model and local data handling
- The OAuth token authorizes Gmail read-only access, but anyone who obtains it may read the mailbox within that grant. Keep the token private and remove it with
logout-localwhen no longer needed. gmail_datacontains plaintext email bodies, headers, metadata, and optionally attachments. Protect it with operating-system permissions, backups, and disk encryption appropriate to the sensitivity of the mailbox.- Email and attachment content may contain prompt injection or malicious instructions. Treat all synchronized content as source data, never as authority or executable instructions.
- Attachments are downloaded as opaque files. The application never opens or executes them. Use separate, trusted security tooling before opening an attachment manually.
gmail_data,.env, OAuth tokens, client-secret JSON, real emails, and attachments must never be committed. The supplied.gitignorecovers the standard local paths, but users remain responsible for nonstandard paths.- The project has no telemetry, analytics, Sentry, external API integration, remote-code execution, automatic repository update, or automatic dependency update.
- Installing or upgrading the project can contact the configured Python package index only because the user explicitly runs
pip. Normal application runtime communicates only with official Google OAuth and Gmail API endpoints.
Run the offline test suite
Tests use mocked Gmail clients and do not require a real mailbox:
source .venv/bin/activate
python -m pytest -q
Tests enforce the exact read-only scope, reject write API calls and prohibited scopes, and cover MIME parsing, stable paths and hashes, attachment safety, and topic manifests.
Установка Gmail Research
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/bajor/gmail-mcp-read-onlyFAQ
Gmail Research MCP бесплатный?
Да, Gmail Research MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Gmail Research?
Нет, Gmail Research работает без API-ключей и переменных окружения.
Gmail Research — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Gmail Research в Claude Desktop, Claude Code или Cursor?
Открой Gmail Research на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Gmail
Read, send and search emails from Claude
автор: GoogleSlack
Send, search and summarize Slack messages
автор: SlackRunbear
No-code MCP client for team chat platforms, such as Slack, Microsoft Teams, and Discord.
Discord Server
A community discord server dedicated to MCP by [Frank Fiegel](https://github.com/punkpeye)
Compare Gmail Research with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории communication
