About Mail Shadow MCP
Mail Shadow MCP is an MCP server in the Search category: mCP server for structured, read-only email access. Exposes a minimal, auditable API surface — AI agents can search and read emails, but cannot send, delete, or modify your mailbox.
Install
git clone https://github.com/dryas/mail-shadow-mcpThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Tools (8)
delete_mailSoft-delete an email by moving it to a configured trash folder (IMAP MOVE, no permanent deletion)
Parameters not published.
download_attachmentsFetch attachment files from IMAP and save them to disk
Parameters not published.
get_download_linkGenerate a temporary HTTP download URL for attachments (optional fallback)
Parameters not published.
get_email_contentFull body text, read/replied status, and attachment list for a single email
Parameters not published.
get_recent_activityN most recent emails with optional filters (`is_read`, `has_attachments`, pagination)
Parameters not published.
get_threadAll emails in the same thread as a given email, sorted by date ascending
Parameters not published.
list_accounts_and_foldersList all synced accounts and their folders
Parameters not published.
search_emailsFTS5 full-text search with subject/sender/date/folder/`is_read`/`sent_by` filters
Parameters not published.
Ask AI
Ask AI about Mail Shadow MCP
Powered by Claude · Grounded in docs
Security checks
- ✓README presentThe repository ships documentation.
5 checks have not been run yet.
README
Structured, read-only email access for AI agents.
mail-shadow-mcp is a Model Context Protocol (MCP) server that creates a local shadow copy of your IMAP mailboxes in a SQLite database. AI agents query the local database through well-defined MCP tools instead of connecting directly to your IMAP server.
[Remote IMAP Server] ──IMAP──▶ [Sync Engine] ──▶ [SQLite FTS5] ◀──▶ [MCP Server] ◀──▶ [AI Agent]
Features
- Local shadow database — emails are synced into a local SQLite database; the AI agent never connects to your IMAP server directly
- Read-only — no
STORE,APPEND, orEXPUNGEcommands; your mailbox is never modified - Incremental sync — only fetches messages newer than the last known UID
- Full-text search — SQLite FTS5 index for fast body-text queries
- Multi-account — sync any number of IMAP accounts simultaneously
- IMAP IDLE — optional real-time push notifications; new mail detected within seconds instead of waiting for the next poll interval
- Read/replied status —
is_readandis_repliedflags synced from IMAP and exposed as filters - Thread view —
get_threadwalks full email conversations viaMessage-ID/In-Reply-Toheaders - Paginated results — all list tools return
total_countso agents can page through large result sets - On-demand attachments — attachment files are fetched from IMAP only when explicitly requested
MCP Tools
| Tool | Description |
|---|---|
list_accounts_and_folders |
List all synced accounts and their folders |
get_recent_activity |
N most recent emails with optional filters (is_read, has_attachments, pagination) |
get_email_content |
Full body text, read/replied status, and attachment list for a single email |
search_emails |
FTS5 full-text search with subject/sender/date/folder/is_read/sent_by filters |
get_thread |
All emails in the same thread as a given email, sorted by date ascending |
download_attachments |
Fetch attachment files from IMAP and save them to disk |
get_download_link |
Generate a temporary HTTP download URL for attachments (optional fallback) |
Quick Start
1. Build
make build # current platform
make release # cross-compile for all platforms into dist/
Requires Go 1.25+.
2. Configure
Copy the example config and fill in your IMAP credentials:
cp config.example.yaml config.yaml
sync_interval_min: 15
database:
path: "data/mail.db"
attachment_dir: "data/attachments"
# Optional: structured JSON logs for Loki / Elasticsearch pipelines.
# log_format: json # json | text (default: text)
# log_level: info # debug | info | warn | error (default: info)
# log_file: "/var/log/mail-shadow-mcp.log" # omit to use stderr
# Optional: lightweight HTTP server for temporary attachment download links.
# Only enable this if you need the get_download_link MCP tool (e.g. as a
# fallback when the AI agent cannot transfer files via its normal channels).
fileserver_port: 8787 # TCP port to listen on (disabled if omitted)
fileserver_ttl_min: 15 # minutes before a link expires (default: 15)
fileserver_host: "localhost" # hostname/IP shown in generated URLs
accounts:
- id: "work@example.com"
host: "imap.example.com"
port: 993
username: "work@example.com"
password: "$WORK_IMAP_PASS" # or plain text
folders: ["INBOX", "Archive"] # only sync the mentioned folders
# idle_folders: ["INBOX"] # optional: IMAP IDLE for real-time push on these folders
- id: "private@example.com"
host: "imap.example.com"
port: 993
username: "private@example.com"
password: "$PRIVATE_IMAP_PASS" # or plain text
Credentials can be stored as plain text or as $ENV_VAR references that are resolved at runtime.
3. Run
# Start the MCP server (syncs on startup, then every sync_interval_min minutes)
./mail-shadow-mcp serve
# One-shot sync without starting the server
./mail-shadow-mcp sync
# Query from the command line (output is JSON)
./mail-shadow-mcp query --subject "invoice" --body "Q1"
./mail-shadow-mcp query -q "budget" --attachments only # only emails with attachments
./mail-shadow-mcp query --recent --attachments none # recent emails without attachments
./mail-shadow-mcp query --recent --limit 10 --offset 10 # page 2
# Download attachments for a specific email
./mail-shadow-mcp attachments --id "work@example.com:INBOX:42"
Integrating with an AI Agent
Configure your MCP client to launch the server via stdio.
Example for Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"mail_shadow": {
"command": "/path/to/mail-shadow-mcp",
"args": ["serve", "--config", "/path/to/config.yaml"]
}
}
}
Example for Hermes Agent (config.yaml):
mcp_servers:
mail_shadow:
command: "/path/to/mail-shadow-mcp"
args: ["serve", "--config", "/path/to/config.yaml"]
Example for OpenClaw (~/.openclaw/openclaw.json):
{
"mcpServers": {
"mail_shadow": {
"command": "/path/to/mail-shadow-mcp",
"args": ["serve", "--config", "/path/to/config.yaml"],
"transport": "stdio"
}
}
}
TLS Modes
tls_mode |
Port | Description |
|---|---|---|
tls |
993 | Implicit TLS (default) |
starttls |
143 | STARTTLS upgrade |
none |
143 | No encryption — localhost/testing only |
Set tls_skip_verify: true to accept self-signed certificates.
IMAP IDLE (Real-time Push)
By default, mail-shadow-mcp polls for new messages every sync_interval_min minutes. For folders where you want near-instant notifications, enable IMAP IDLE:
accounts:
- id: "work@example.com"
# ...
idle_folders: ["INBOX"] # IDLE runs on top of regular polling
- One dedicated IMAP connection is opened per entry in
idle_folders - When the server sends an
EXISTSnotification, a sync is triggered immediately - Regular polling continues unchanged for all other folders
- Falls back to polling automatically if the server does not support IDLE
- Exponential backoff (30 s → 5 min) on persistent connection errors
Attachment Download Server
The optional built-in HTTP server lets the AI agent generate temporary, single-use download links for attachment files — useful as a fallback when the agent cannot transfer files through its normal communication channels (e.g. WhatsApp, email).
Enable it in config.yaml:
fileserver_port: 8787 # TCP port to listen on
fileserver_ttl_min: 15 # minutes before a link expires (default: 15)
fileserver_host: "localhost" # hostname/IP shown in generated URLs
When enabled, the get_download_link MCP tool becomes available. It downloads the attachments, saves them to attachment_dir, and returns one temporary URL per file:
[
{
"file": "data/attachments/work@example.com/INBOX/42/invoice.pdf",
"url": "http://localhost:8787/dl/3f8a1c.../invoice.pdf"
}
]
Each link is single-use and expires after fileserver_ttl_min minutes. The tool description instructs the AI agent to prefer direct file transfer and only fall back to this mechanism when necessary.
License
Apache 2.0 — see LICENSE for details.
Copyright (c) 2026 Benjamin Kaiser.
README copy captured when this server was indexed; it may lag the repository. The original is authoritative.