imap-mcp

imap-mcp

Read-only MCP server that connects to multiple IMAP accounts, enabling cross-account email listing, search, and retrieval without modifying mailboxes.

Category
访问服务器

README

imap-mcp

All your mailboxes, one MCP server, read-only.

Point it at any number of IMAP accounts (Gmail, Fastmail, iCloud, Migadu, self-hosted, anything that speaks IMAP) and your MCP client can list, search, and read across every one of them in a single call. Ask "what's unread across all my accounts?" or "find the invoice from Hetzner" and get answers that span providers, not one inbox at a time.

Strictly read-only. No send, no delete, no flag changes, no folder moves. Every fetch uses BODY.PEEK, so reading a message never marks it as read. Your mailboxes look exactly the same after a session as before it.

No secrets on disk. The config file names an environment variable per account; passwords only ever exist in the server process environment. Bring your own secret manager, or just export a variable.

Why IMAP

Assistant mail integrations usually connect one Gmail or one Outlook account. IMAP is the protocol nearly every provider already speaks, so one small server covers your whole mail footprint with a single read-only code path, no OAuth apps to register, and nothing granted write access.

Quickstart

Requires Python 3.12+ and uv.

git clone https://github.com/LeeFlannery/imap-mcp
cd imap-mcp
cp accounts.example.toml accounts.toml
$EDITOR accounts.toml           # add your accounts
export PERSONAL_IMAP_PASSWORD='...'
uv run imap-mcp                 # starts the MCP server on stdio

That's it. Register it with your MCP client (below) and start asking about your mail.

Configure accounts

accounts.toml is gitignored and holds no secrets:

[[account]]
key = "personal"                        # short id used in tool calls
label = "you@example.com (Fastmail)"    # optional, defaults to email
email = "you@example.com"               # IMAP login
host = "imap.fastmail.com"
port = 993                              # optional, defaults to 993
password_env = "PERSONAL_IMAP_PASSWORD" # env var holding the password
enabled = true                          # optional, defaults to true

Add one [[account]] block per mailbox. enabled = false keeps an account listed but never logs into it. Set IMAP_MCP_ACCOUNTS=/path/to/accounts.toml to keep the config outside the repo.

Provider cheat sheet

Provider Host Password
Gmail / Google Workspace imap.gmail.com App password (requires 2FA; the spaces Google shows are stripped automatically)
Fastmail imap.fastmail.com App password
iCloud imap.mail.me.com App-specific password
Yahoo imap.mail.yahoo.com App password
Migadu imap.migadu.com Mailbox password
Outlook.com / Microsoft 365 not supported Microsoft has retired IMAP basic auth; OAuth is not implemented here

All standard providers use port 993 (implicit TLS), the default.

Passwords

Each account's password_env names an environment variable that must be set when the server runs. Any of these work:

# plain export in the shell that launches your MCP client
export PERSONAL_IMAP_PASSWORD='...'

# direnv, sops, pass, whatever you already use

# 1Password: put op:// references in an env file and wrap the command
op run --env-file=op.env -- uv run imap-mcp

Register with an MCP client

Claude Code

claude mcp add imap -- uv run --directory /path/to/imap-mcp imap-mcp

Or in .mcp.json / your user MCP config:

{
  "mcpServers": {
    "imap": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/imap-mcp", "imap-mcp"]
    }
  }
}

Claude Desktop and other clients

Same command and args in the client's MCP server config (claude_desktop_config.json, etc.). Any stdio MCP client works.

Either way, the password env vars must be visible to the spawned process: export them in the environment the client launches from, or wrap the command in your secret injector, e.g. "command": "op", "args": ["run", "--env-file=/path/to/op.env", "--", "uv", "run", ...].

Tools

list_accounts() configured accounts with live status. Run this first; it tells you which mailboxes are queryable and what to pass as account.

{"account": "personal", "email": "you@example.com", "enabled": true, "status": "ok"}

list_emails(account?, since?, unread_only?, limit?) recent mail, newest first. Omit account to merge all enabled accounts into one timeline.

search_emails(query, account?, since?, limit?) free-text search over sender, subject, and body. Also cross-account unless you name one.

Both return compact rows:

{"account": "personal", "id": "4711", "from": "billing@hetzner.com",
 "subject": "Invoice 2026-07", "date": "2026-07-03T09:12:44+00:00",
 "unread": true, "snippet": "Your invoice for July..."}

get_email(account, id) one full message by the id from a row, with plain-text body preferred over HTML. Reading it does not mark it read.

Dates are ISO (YYYY-MM-DD); since filters everywhere; limit applies per account when merging. If one account is down, its error comes back as a row and the other accounts still answer.

Troubleshooting

  • status: "no-credential": the account's password_env variable is not set in the server's environment. Remember the server inherits its env from whatever launched it (your MCP client), not from your interactive shell.
  • status: "unreachable: MailboxLoginError" on Gmail/iCloud/Yahoo: you're using the account password; these providers require an app password (see cheat sheet).
  • Config not found: the server looks for accounts.toml next to pyproject.toml, or wherever IMAP_MCP_ACCOUNTS points.

Development

uv run pytest

31 tests, no network: the IMAP layer is faked. The suite locks in the read-only contract (mark_seen=False on every fetch), per-account error isolation, and config handling.

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选