mcp server
mu4e-mcp
Minimal, dependency-free MCP server exposing local mu (mu4e) email search to Claude. Pure Python stdlib.
Set up
Runs on your computer. Pick your agent and operating system.
This project does not publish an install method we can turn into a config. Follow the README instead.
README
synced Oct 23, 2026mu4e-mcp
A minimal MCP server that exposes local mu email search to Claude Code. Written in pure Python stdlib — no dependencies beyond mu itself.
What it does
Gives Claude two tools:
| Tool | Description |
|---|---|
search_email | Run any mu find query and get matching messages as JSON |
get_email | Fetch the full body and headers of a message by file path (must be inside the maildir) |
Example queries you can ask Claude:
- "Search for unread emails in my work inbox"
- "Find emails from alice@example.com in the last 7 days"
- "Show me the body of that email"
For a fuller, plain-language guide to asking Claude to search and read your mail (with example prompts), see USAGE.md.
Requirements
- Python 3.x (stdlib only)
muinstalled and indexed (mu init && mu index)- Claude Code
Installation
1. Place the server script
mkdir -p ~/.local/mcp
cp mu4e-mcp.py ~/.local/mcp/mu4e-mcp.py
chmod +x ~/.local/mcp/mu4e-mcp.py
2. Register with Claude Code
Add to ~/.claude/settings.json under mcpServers:
{
"mcpServers": {
"mu4e": {
"command": "python3",
"args": ["/home/<your-username>/.local/mcp/mu4e-mcp.py"]
}
}
}
Replace <your-username> with your actual username, or use an absolute path.
3. Restart Claude Code
The MCP server is picked up on startup. After restarting, the search_email and get_email tools will be available.
Query syntax
search_email accepts any mu find query string. Examples:
| Query | Meaning |
|---|---|
flag:unread AND NOT flag:trashed | All unread, non-trashed mail |
from:alice subject:invoice | From alice, subject contains "invoice" |
maildir:/work/INBOX date:7d..now | Work inbox, last 7 days |
flag:unread maildir:/personal/INBOX | Unread personal mail |
See the mu-find man page for full query syntax.
Notes
- Email bodies are capped at 8000 characters to avoid flooding context
- The server returns up to 20 results by default (configurable per query)
- Requires
muto already be indexed — runmu indexif results are stale get_emailonly reads files inside the maildir (MU_MCP_MAILDIR, default~/.maildir) after resolving symlinks and..; anything else is refused- Query words are passed to
mu findafter--, so a query can never smuggle inmuoptions (e.g.--exec)
Remote access (HTTP mode)
To reach your mail from a client that isn't on this machine — e.g. a claude.ai custom connector — run the server in HTTP mode behind an authenticating proxy:
python3 mu4e-mcp.py --http 127.0.0.1:8766
# MCP endpoint: http://127.0.0.1:8766/mcp
- Transport: stateless MCP Streamable HTTP —
POST /mcpwith a JSON-RPC message (or batch), JSON response; notifications get202. No server-initiated stream, soGETis405. Requests are handled one at a time. - Bind to loopback and put real authentication (e.g. an OAuth proxy) in front. The server warns on a non-loopback bind.
MU_MCP_HTTP_TOKEN— optional: requireAuthorization: Bearer <token>on every request, as a second lock behind the proxy.MU_MCP_HTTP_TOKEN_HEADER— optional: carry the token in this header instead (e.g.X-Upstream-Key: <token>, raw value, noBearer). For proxies that ownAuthorizationthemselves, such as Pomerium in MCP mode. A missing or wrong value gets403(not401, which would make an OAuth proxy try upstream OAuth).MU_MCP_ALLOWED_ORIGINS— comma-separated; requests carrying any otherOriginheader get403(DNS-rebinding guard). Requests withoutOrigin(server-to-server) are allowed.- In HTTP mode every
tools/callis logged to stderr (tool, argument names, ok, result size — never argument values or results).
Tests
python3 tests/test_mu4e_mcp.py # no mu needed: JSON-RPC, hardening, HTTP mode
Contributing
See CONTRIBUTING.md.
License
GPL-3.0-or-later © 2026 Kjetil Rohde Jakobsen. Contributions welcome.