imap-mcp
IMAP client MCP. Read mail from a Dovecot / Synology MailPlus mailbox, and optionally fire webhooks when new matching messages arrive — replaces fragile Gmail OAuth for automation triggers.
Tools
| Tool | Description |
|---|---|
list_unread(mailbox, limit) | Unread message summaries |
search(criteria, mailbox, limit) | Raw IMAP SEARCH |
fetch(uid, mailbox) | Full message (headers + text + html) |
mark_read(uid, mailbox) | Set \Seen flag |
move(uid, source, dest) | Move to another folder |
list_folders() | All folders |
get_status() | IMAP ping + watcher rules + fire count |
Environment
| Variable | Required | Description |
|---|---|---|
IMAP_HOST | ✓ | Server (e.g. 192.168.68.61) |
IMAP_PORT | Default 993 | |
IMAP_SSL | true (default) or false | |
IMAP_USERNAME | ✓ | Synology account name, not email |
IMAP_PASSWORD | ✓ | |
IMAP_DEFAULT_MAILBOX | Default INBOX | |
WATCHES_JSON | Inline JSON array of watch rules | |
WATCHES_FILE | Path to JSON file (default /data/watches.json) | |
POLL_INTERVAL_SECS | Default 30 | |
PORT | MCP server port (default 38105) |
Watch rules
[
{
"name": "garmin-livetrack",
"mailbox": "INBOX",
"criteria": "FROM \"noreply@garmin.com\" SUBJECT \"LiveTrack\" UNSEEN",
"webhook_url": "http://host.docker.internal:5678/webhook/livetrack-mail",
"mark_read": true,
"move_to": null
}
]
On startup the watcher "primes" each rule with existing matching UIDs, so
only new mail after boot fires. Every POLL_INTERVAL_SECS it re-runs
each rule's criteria and POSTs matching messages (full body) to webhook_url
as { "rule": "...", "mailbox": "...", "message": {...} }. After a
successful POST it either moves the message to move_to, or marks it read
if mark_read.