Google Mail MCP
A mock Gmail MCP (Model Context Protocol) server for testing and RL environment training. It simulates a complete email system without requiring any network connectivity - all state is loaded from and persisted to a JSON file.
Overview
This MCP server provides 20 email tools that operate on a "closed-world" simulation:
- Closed-world contacts: Only predefined email addresses can receive messages
- Bounce simulation: Emails to invalid addresses generate realistic bounce notifications
- Group support: Sending to a group delivers copies to members (including yourself if you're a member)
- State persistence: All changes are saved back to the JSON file
- No network required: Everything runs locally from a JSON file
Project Structure
packages/google_mail/
├── google_mail.py # Entry point for container environment
├── utils.py # Utilities for data path computation
├── __init__.py # Package exports
├── src/mail_mcp/ # Core MCP server implementation
│ ├── server.py # FastMCP server with tool definitions
│ ├── models/ # Pydantic schemas
│ └── services/ # Mailbox business logic
├── examples/
│ └── sample_mailbox.json
└── tests/
Installation
Local Development
cd packages/google_mail
uv sync
Container Environment
The MCP server is pre-installed in the DAT container. Data is stored in external_services/mailbox.json next to the agent workspace (outside the agent's filesystem access).
Usage
Running Locally
# Using environment variable
MAIL_MCP_DATA_PATH=/path/to/mailbox.json uv run mail-mcp
# Using CLI argument
uv run mail-mcp --data-path /path/to/mailbox.json
# With debug logging
uv run mail-mcp --data-path /path/to/mailbox.json --debug
Container Usage (via MCP Config)
The server is configured in configs/mcp_servers/google_mail.yaml:
type: stdio
name: google_mail
params:
command: uv
args:
- "run"
- "--project"
- "/workspace/packages/google_mail"
- "python"
- "/workspace/packages/google_mail/google_mail.py"
- "--agent-workspace"
- "${agent_workspace}"
Task Preprocessing
To set up mailbox data for a task, use the utility functions:
from google_mail import create_mail_data
from pathlib import Path
# Copy mailbox.json to external_services location
create_mail_data(
agent_workspace="/workspace/dumps/workspace",
source_mailbox_path=Path("initial_workspace/mailbox.json"),
)
MCP Client Configuration
For direct MCP client usage:
{
"mcpServers": {
"mail": {
"command": "uv",
"args": ["run", "--project", "/path/to/google_mail", "mail-mcp"],
"env": {
"MAIL_MCP_DATA_PATH": "/path/to/mailbox.json"
}
}
}
}
Tools
Email Operations
| Tool | Description |
|---|---|
mail_get_emails |
Get paginated emails from a folder |
mail_read_email |
Read a single email (marks as read) |
mail_search_emails |
Search emails by query string, including Gmail-style operators such as from:, subject:, has:attachment, filename:, is:unread, and in: |
mail_send_email |
Send an email |
mail_reply_email |
Reply to an email |
mail_forward_email |
Forward an email with attachments |
mail_delete_emails |
Delete one or more emails (moves to Trash or permanent) |
mail_move_emails |
Move one or more emails to a different folder |
mail_mark_emails |
Mark emails as read/unread/important |
Folder Operations
| Tool | Description |
|---|---|
mail_get_folders |
List all folders with message counts |
mail_create_folder |
Create a new folder |
mail_delete_folder |
Delete a folder (system folders protected) |
mail_get_unread_count |
Get unread counts per folder |
mail_get_mailbox_stats |
Get statistics for all folders |
Draft Operations
| Tool | Description |
|---|---|
mail_save_draft |
Save a new draft |
mail_get_drafts |
Get paginated list of drafts |
mail_update_draft |
Update an existing draft |
mail_delete_draft |
Delete a draft |
Other
| Tool | Description |
|---|---|
mail_get_contacts |
List all valid contacts (closed-world) |
mail_download_attachment |
Download an attachment as base64 |
Threading
Emails are linked into threads via the in_reply_to field, which references the parent email's message_id.
When using mail_reply_email:
- The reply's
in_reply_tois automatically set to the original'smessage_id - The reply body includes a quoted copy of the original message:
Your reply here...
--- Original Message ---
From: alice@example.com
Date: 2024-01-15 10:30
Subject: Meeting Tomorrow
Original message content...
This provides both programmatic thread linking (via in_reply_to) and human-readable context (via quoted original).
JSON Schema
The mailbox data file follows this schema:
Root Structure
{
"mailbox": { ... },
"contacts": [ ... ],
"folders": [ ... ],
"emails": [ ... ],
"drafts": [ ... ],
"next_email_id": 1
}
Fields
mailbox (required)
The identity of the mailbox owner. This is the "From" address when sending emails.
{
"email": "user@example.com",
"name": "Display Name"
}
contacts (required)
List of valid email recipients. Only these addresses (plus the mailbox owner) can receive emails. Sending to any other address will generate a bounce notification.
[
{"email": "alice@example.com", "name": "Alice Smith"},
{"email": "team@example.com", "name": "Engineering Team", "members": [
"user@example.com",
"alice@example.com"
]}
]
Groups have a members array. When you send to a group and you're a member, you receive a copy in your INBOX.
folders (optional)
Custom folders beyond the system defaults. System folders (INBOX, Sent, Drafts, Trash) always exist implicitly.
[
{"name": "Work"},
{"name": "Archive/2024"}
]
emails (optional)
List of emails in the mailbox.
[
{
"email_id": "1",
"folder": "INBOX",
"subject": "Meeting Tomorrow",
"from_addr": "alice@example.com",
"to_addr": "user@example.com",
"cc_addr": null,
"bcc_addr": null,
"date": "2024-01-15T10:30:00Z",
"message_id": "<msg001@example.com>",
"in_reply_to": null,
"body_text": "Plain text content here",
"body_html": "<p>Optional HTML content</p>",
"is_read": false,
"is_important": false,
"attachments": [
{
"filename": "document.pdf",
"content_type": "application/pdf",
"content_base64": "JVBERi0xLjQK..."
}
]
}
]
The in_reply_to field links replies to their parent email via message_id. This enables thread tracking.
drafts (optional)
List of draft emails.
[
{
"draft_id": "draft_1",
"subject": "Draft Subject",
"body": "Draft content",
"html_body": null,
"to": "alice@example.com",
"cc": null,
"bcc": null,
"created_at": "2024-01-15T09:00:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
next_email_id (optional)
Counter for generating new email IDs. Defaults to 1 if not specified.
Examples
Minimal Empty Mailbox
{
"mailbox": {
"email": "user@example.com",
"name": "Test User"
},
"contacts": [],
"folders": [],
"emails": [],
"drafts": [],
"next_email_id": 1
}
Populated Mailbox
See examples/sample_mailbox.json for a complete example with contacts, emails, groups, drafts, and attachments.
Development
Running Tests
cd packages/google_mail
uv run pytest
Code Quality
uv run ruff check .
uv run mypy .