tbird-mcp
README.md
# tbird-mcp — Thunderbird-aware Mail MCP
An MCP server that **reads/searches your mail from Thunderbird's local store**
and **sends mail over SMTP from any of your identities**, then files a copy in
the account's Sent folder so it shows up in Thunderbird normally.
Thunderbird has no programmatic send API, so "send through Thunderbird" really
means: read Thunderbird's on-disk mbox files, but put outgoing mail on the wire
ourselves via SMTP. Account and identity configuration is auto-discovered from
Thunderbird's `prefs.js` — you don't re-enter any of it.
## What v1 does
- **Read** — every account, from the local mbox store. Streams even
multi-gigabyte folders without loading them into memory, and skips messages
Thunderbird has flagged deleted-but-not-compacted.
- **Send** — any plain-SMTP identity (Migadu, Zoho, Fastmail, generic SMTP, …),
auto-discovered from Thunderbird.
- **Deferred to v2** — sending **as** Outlook/hotmail. Microsoft disabled basic
SMTP auth for personal accounts, so it needs a Microsoft Graph / OAuth2 app
registration. The transport seam is in place (`transports.GraphTransport`);
until then, `send_mail` from an Outlook identity returns a clear error.
## Tools
| Tool | Purpose |
|------|---------|
| `list_accounts` | Incoming accounts + their on-disk store dir |
| `list_folders(account)` | mbox folders for an account |
| `search_mail(...)` | Filter by account/folder/since/before/from/to/subject/body/has_attachment |
| `read_message(message_id)` | Headers + decoded body |
| `list_attachments(message_id)` | Attachment filenames |
| `extract_attachments(message_id, dest_dir)` | Save attachments (the PDFs) to disk |
| `list_identities` | Send-from addresses + whether each can send now |
| `send_mail(...)` | Send via SMTP, file a copy in Sent. **`dry_run=True` by default** |
| `reload_config` | Re-read prefs.js / credentials.toml after editing |
`search_mail` returns an opaque `id` per message; pass it to the read/extract
tools. **`send_mail` defaults to `dry_run=True`** and returns a preview — pass
`dry_run=False` to actually send.
## Install
```bash
cd ~/agents/personal/mcp-servers/tbird-mcp
uv sync # creates .venv with the mcp SDK
uv run python tests/make_fixture.py # (tests only) generate the sample mbox
uv run pytest -q # 20+ tests, no real mail sent
```
## 1. Register with Claude Code
Add to your MCP config (e.g. `~/.claude.json`, or via `claude mcp add`):
```json
{
"mcpServers": {
"tbird": {
"command": "uv",
"args": ["run", "--directory",
"/path/to/tbird-mcp",
"tbird-mcp"]
}
}
}
```
Optional environment overrides:
- `TBIRD_PROFILE` — absolute path to a specific Thunderbird profile dir
(default: the active profile from `profiles.ini`).
- `TBIRD_CREDENTIALS` — path to the credentials file
(default: `~/.config/tbird-mcp/credentials.toml`).
## 2. Add credentials (only needed for sending)
Reading needs no credentials. Sending does:
```bash
mkdir -p ~/.config/tbird-mcp
cp credentials.toml.example ~/.config/tbird-mcp/credentials.toml
chmod 600 ~/.config/tbird-mcp/credentials.toml
$EDITOR ~/.config/tbird-mcp/credentials.toml
```
Use **app passwords**, not your account login passwords:
- **Migadu** — Admin → Mailboxes → the mailbox → *App passwords* → create one.
Aliases can't authenticate; create the app password on the **real mailbox**
and point each alias at it with an `[identity."alias@…"] auth_user = "…"`
block. One mailbox app password typically covers all aliases on its domain.
- **Zoho** — myaccount.zoho.com → Security → *App Passwords* → generate.
After editing, call `reload_config` (or restart the server).
## 3. (Later) v2 — sending as Outlook/hotmail
Outlook/hotmail send needs a one-time, free Azure app registration to obtain a
client ID, then OAuth2 device-code auth against Microsoft Graph's `Mail.Send`
scope. The `graph` transport slot is already wired into the identity registry;
v2 fills in `GraphTransport.send`. Until then, send from a Migadu/Zoho/SMTP
identity, or use Thunderbird directly.
## Notes / limitations
- Search streams the whole folder file, so a query against a multi-gigabyte
folder takes a few seconds — narrow with `account` + a tight `limit`.
- Message ids encode a byte offset into the mbox; if Thunderbird **compacts**
a folder, re-run the search to get fresh ids.
- Sub-folders inside `*.sbd` directories aren't enumerated in v1 (top-level
folders only).
TDQS
A3.7/5.0
Scored across 9 tools
Disambiguation5/5
Each tool targets a distinct action: listing accounts, listing folders, searching, reading, attachments, identities, sending, and reloading config. There is no overlap in functionality.
Naming Consistency5/5
All tools follow a consistent verb_noun pattern in snake_case (e.g., list_accounts, search_mail, send_mail), making it easy to predict tool names.
Tool Count5/5
9 tools is well-scoped for a Thunderbird mail MCP, covering essential operations without being overwhelming or too sparse.
Completeness4/5
The set covers key mail operations (account listing, search, read, send, attachments) but is missing operations like create/delete folders or mark as read, which are minor gaps for the intended use.
Maintenance
ActivityInactive
ResponsivenessNo issues