Sponsored by Deepsite.site

Mail Shadow MCP

Created By
dryas21 days ago
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.
Overview

Structured email access for AI agents — with built-in safety guarantees.

Build Latest Release Go Version Go Report Card License

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, or EXPUNGE commands; 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 statusis_read and is_replied flags synced from IMAP and exposed as filters
  • Thread viewget_thread walks full email conversations via Message-ID / In-Reply-To headers
  • Paginated results — all list tools return total_count so agents can page through large result sets
  • On-demand attachments — attachment files are fetched from IMAP only when explicitly requested
  • Safe soft-delete — when an agent calls delete_mail, the MCP server performs an IMAP MOVE to a configurable trash folder; nothing is ever permanently deleted
  • Flexible transportstdio for local tools (Claude Desktop), http (StreamableHTTP) or sse for remote and Docker deployments
  • Docker-ready — official multi-arch image (linux/amd64, linux/arm64) published to ghcr.io on every release

Safety: Nothing Is Ever Really Deleted

mail-shadow-mcp gives AI agents a delete_mail tool, but this tool never issues a destructive IMAP command. Here is exactly what happens when an agent calls it:

  1. The MCP server looks up the email in the local database.
  2. It opens a short-lived IMAP connection and executes IMAP MOVE — moving the message to the trash_folder you specify in config.yaml (e.g. "llm_delete").
  3. The local database entry is removed so the agent can no longer see the mail in future queries.
  4. The email remains intact on the IMAP server, safely tucked away in the trash folder. You can inspect, restore, or permanently delete it yourself at any time.

The AI agent has no direct IMAP access. It cannot expunge messages, empty folders, or issue any write command other than this controlled move. If trash_folder is not configured for an account, delete_mail returns an error and does nothing.


MCP Tools

ToolDescription
list_accounts_and_foldersList all synced accounts and their folders
get_recent_activityN most recent emails with optional filters (is_read, has_attachments, pagination)
get_email_contentFull body text, read/replied status, and attachment list for a single email
search_emailsFTS5 full-text search with subject/sender/date/folder/is_read/sent_by filters
get_threadAll emails in the same thread as a given email, sorted by date ascending
download_attachmentsFetch attachment files from IMAP and save them to disk
get_download_linkGenerate a temporary HTTP download URL for attachments (optional fallback)
delete_mailSoft-delete an email by moving it to a configured trash folder (IMAP MOVE, no permanent deletion)

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
    # trash_folder: "llm_delete"  # optional: target for delete_mail (soft-delete via IMAP MOVE)
    
  - 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"

Docker

Pre-built multi-architecture images (linux/amd64, linux/arm64) are published to the GitHub Container Registry on every release:

docker pull ghcr.io/dryas/mail-shadow-mcp:latest

Required volumes

VolumePurpose
/configMust contain config.yaml. Mount read-only.
/dataPersistent storage for the SQLite database and downloaded attachments. Survives container restarts.

Quick Docker run

Step 1 — prepare a config.yaml with transport: http and paths pointing to /data:

transport: http
http_addr: ":8080"
http_bearer_token: "your-secret-token"   # see below for how to generate one

database:
  path: "/data/mail.db"

attachment_dir: "/data/attachments"

accounts:
  - id: "work@example.com"
    host: "imap.example.com"
    port: 993
    username: "work@example.com"
    password: "$WORK_IMAP_PASS"

Step 2 — run the container:

docker run -d \
  --name mail-shadow-mcp \
  -v ./config.yaml:/config/config.yaml:ro \
  -v mail-shadow-data:/data \
  -p 8080:8080 \
  ghcr.io/dryas/mail-shadow-mcp:latest

The MCP server is now reachable at http://localhost:8080/mcp.

docker-compose example

services:
  mail-shadow-mcp:
    image: ghcr.io/dryas/mail-shadow-mcp:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./config.yaml:/config/config.yaml:ro   # your config — mount read-only
      - mail-shadow-data:/data                 # persistent DB + attachments
    environment:
      - WORK_IMAP_PASS=your_password_here      # referenced as $WORK_IMAP_PASS in config

volumes:
  mail-shadow-data:

Passwords as environment variables: In config.yaml you can reference passwords as $ENV_VAR — the server resolves them at startup. Pass them via environment: in docker-compose or via -e with docker run. This way no plaintext password ends up in the config file.

Authentication (Bearer Token)

When using http or sse transport, always set http_bearer_token — otherwise the MCP endpoint is reachable by anyone who can access the port.

Generate a cryptographically secure token:

# Linux / macOS / WSL
openssl rand -hex 32

# PowerShell
[System.Convert]::ToBase64String((1..32 | ForEach-Object { [byte](Get-Random -Max 256) }))

Set it in your config.yaml:

http_bearer_token: "a3f1c2e8b4d9..."   # paste your generated token here

Every request to the MCP endpoint must then include the header:

Authorization: Bearer a3f1c2e8b4d9...

Most MCP clients (Claude Desktop, Cursor, etc.) support Bearer auth natively — see the connection example below.

Connecting an AI agent to the Docker container

Point your MCP client at http://localhost:8080/mcp using the StreamableHTTP transport:

{
  "mcpServers": {
    "mail_shadow": {
      "url": "http://localhost:8080/mcp",
      "headers": {
        "Authorization": "Bearer your-secret-token"
      }
    }
  }
}

Build the image yourself

docker build --build-arg VERSION=dev -t mail-shadow-mcp .

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_modePortDescription
tls993Implicit TLS (default)
starttls143STARTTLS upgrade
none143No 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 EXISTS notification, 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.

Server Config

{
  "mcpServers": {
    "mail_shadow": {
      "command": "/path/to/mail-shadow-mcp",
      "args": [
        "serve",
        "--config",
        "/path/to/config.yaml"
      ]
    }
  }
}
Recommend Servers
TraeBuild with Free GPT-4.1 & Claude 3.7. Fully MCP-Ready.
WindsurfThe new purpose-built IDE to harness magic
DeepChatYour AI Partner on Desktop
Tavily Mcp
ChatWiseThe second fastest AI chatbot™
Howtocook Mcp基于Anduin2017 / HowToCook (程序员在家做饭指南)的mcp server,帮你推荐菜谱、规划膳食,解决“今天吃什么“的世纪难题; Based on Anduin2017/HowToCook (Programmer's Guide to Cooking at Home), MCP Server helps you recommend recipes, plan meals, and solve the century old problem of "what to eat today"
Y GuiA web-based graphical interface for AI chat interactions with support for multiple AI models and MCP (Model Context Protocol) servers.
Serper MCP ServerA Serper MCP Server
CursorThe AI Code Editor
MCP AdvisorMCP Advisor & Installation - Use the right MCP server for your needs
Visual Studio Code - Open Source ("Code - OSS")Visual Studio Code
BlenderBlenderMCP connects Blender to Claude AI through the Model Context Protocol (MCP), allowing Claude to directly interact with and control Blender. This integration enables prompt assisted 3D modeling, scene creation, and manipulation.
Zhipu Web SearchZhipu Web Search MCP Server is a search engine specifically designed for large models. It integrates four search engines, allowing users to flexibly compare and switch between them. Building upon the web crawling and ranking capabilities of traditional search engines, it enhances intent recognition capabilities, returning results more suitable for large model processing (such as webpage titles, URLs, summaries, site names, site icons, etc.). This helps AI applications achieve "dynamic knowledge acquisition" and "precise scenario adaptation" capabilities.
Amap Maps高德地图官方 MCP Server
Jina AI MCP ToolsA Model Context Protocol (MCP) server that integrates with Jina AI Search Foundation APIs.
Playwright McpPlaywright MCP server
AiimagemultistyleA Model Context Protocol (MCP) server for image generation and manipulation using fal.ai's Stable Diffusion model.
Baidu Map百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
EdgeOne Pages MCPAn MCP service designed for deploying HTML content to EdgeOne Pages and obtaining an accessible public URL.
RedisA Model Context Protocol server that provides access to Redis databases. This server enables LLMs to interact with Redis key-value stores through a set of standardized tools.
MiniMax MCPOfficial MiniMax Model Context Protocol (MCP) server that enables interaction with powerful Text to Speech, image generation and video generation APIs.