Skip to main content
Glama
commonpost

Commonpost MCP for Thunderbird

by commonpost

Commonpost MCP for Thunderbird

CI OpenSSF Best Practices Tools Localhost Only Thunderbird License: MIT

Give your AI assistant full access to Thunderbird -- search mail, compose messages, manage filters, and organize your inbox. All through the Model Context Protocol.

A continuation of thunderbird-mcp by Tomasz Kasperczyk (MIT), started from its 0.7.5 release with its full history kept. It is an independent project by the Commonpost community, not the original and not endorsed by it; it can be installed beside the original (see Migrating). If the original author wants any of this work back, we hand it over: our changes are MIT-licensed and offered upstream too. Thunderbird is a trademark of the Mozilla Foundation; this project is not affiliated with Mozilla or MZLA.

The original was inspired by bb1/thunderbird-mcp. What is in this release is listed in the changelog.


Quick install (about 3 minutes)

  1. Install the extension. Download commonpost-mcp-v<version>.xpi from the latest release. In Thunderbird: Tools > Add-ons and Themes > gear menu > Install Add-on From File. Restart Thunderbird.

  2. Download mcp-bridge.cjs from the same release and put it in a folder you will keep, for example ~/commonpost-mcp/. The bridge is a single file and needs nothing else: the release does not ship a package.json. (The bridge carries its own version; it reads no package.json.)

  3. Check Node.js: node --version must show 22 or later.

  4. Register the bridge with your MCP client.

    • Claude Code, with the plugin (no file to download or to update by hand; see Claude Code plugin):

      claude plugin marketplace add commonpost/thunderbird-mcp
      claude plugin install commonpost-mcp@commonpost
    • Claude Code, with the file (use the absolute path of the file):

      claude mcp add commonpost-mail -- node /absolute/path/to/mcp-bridge.cjs
    • Claude Code on Windows, for example:

      claude mcp add commonpost-mail -- node C:\Users\<you>\commonpost-mcp\mcp-bridge.cjs
    • Other clients: add this to the client's MCP config (Claude Desktop, VS Code, Cursor, Codex CLI and Gemini CLI have their own file and format: see Other MCP clients). In JSON, write Windows paths with / or double the backslashes ("C:/Users/<you>/commonpost-mcp/mcp-bridge.cjs").

      {
        "mcpServers": {
          "commonpost-mail": {
            "command": "node",
            "args": ["/absolute/path/to/mcp-bridge.cjs"]
          }
        }
      }
  5. Test it. Keep Thunderbird open and ask your assistant: "list my Thunderbird accounts".

The bridge is not updated automatically, and each MCP client has its own. When one should be replaced, the extension says so in a tool result (your assistant passes it on) and in its options page (section Bridge), which lists the bridges that connected with "Up to date", "Newer version available" (it works; updating is optional) or "Update recommended". For a bridge to update or one the extension refuses, Thunderbird also shows a system notification, once per bridge and per Thunderbird session; the hidden preference extensions.commonpost-mcp.bridgeUpdateAlert set to false turns it off. Every release page starts with what the release brings, whether it changes the bridge, and the steps: download mcp-bridge.cjs and put it in place of your copy (its path is in the MCP configuration of your client; in Claude Code: claude mcp get <server name>), then reconnect your MCP client (/mcp in Claude Code); in Claude Desktop, install the .mcpb bundle again; with the Claude Code plugin, update the plugin. A release that does not change the bridge ships the same bridge again. The extension's version is shown in Tools > Add-ons and Themes.

Right after installing, open the extension's options page (Tools > Add-ons and Themes > Commonpost MCP for Thunderbird > Options) and choose which accounts and tools your assistant may use. Until you do, every account and tool is visible to MCP clients.

Snap, Flatpak and macOS need no extra step in most cases; see Sandbox-aware connection discovery. If something fails, see Troubleshooting.


Related MCP server: Thunderbird MCP Server

Why?

Thunderbird has no official API for AI tools. Your AI assistant can't read your email, can't help you draft replies, can't organize your inbox. This extension fixes that -- it exposes 40 tools over MCP so any compatible AI (Claude, GPT, local models) can work with your mail the way you'd expect. It stays within Cursor's limit of 40 tools per server.

Mail sends and event/task creation require review by default because Block skipReview starts enabled. skipReview: true is honored only after you explicitly disable that safety setting. By default, nothing is sent or created without your review.


How it works

                    stdio              HTTP (localhost:8780-8789)
  MCP Client  <----------->  Bridge  <--------------------->  Thunderbird
  (Claude, etc.)           mcp-bridge.cjs                    Extension + HTTP Server

The Thunderbird extension embeds a local HTTP server with session-scoped auth tokens. The Node.js bridge translates between MCP's stdio protocol and HTTP, discovering the port and token automatically via a connection file. The bridge handles MCP lifecycle methods (initialize, ping) locally, so clients can connect even before Thunderbird is fully loaded.


What you can do

Mail

Tool

Description

listAccounts

List all email accounts and their identities

listFolders

Browse folder tree with message counts -- filter by account or subtree; savedSearches lists saved searches instead

searchMessages

Search headers across accounts. Words must all match (subject, from, to, cc, preview); operators from:, to:, cc:, subject:, participant: (from/to/cc/bcc; @domain matches addresses in that domain only, commas list alternatives: participant:@acme.com,@acme-group.com) and quoted phrases can be combined, e.g. participant:@acme.com subject:"invoice 42". groupBy: "sender" | "thread" returns one row per sender or conversation (latestId is the newest message that is not a draft); threadOf: {messageId, folderPath} returns a whole conversation across folders (Sent included), oldest first (it reads at most 10,000 headers, then sets incomplete: true). A Re: message sent without threading headers joins by subject the earlier message its sender took part in (linkedBy: "subject"); the same mail sent separately to several people and repeated notifications stay separate. Filters pick messages of the conversation without cutting its links. Trash and Junk are skipped unless includeTrash or an explicit folderPath. Always returns { messages, totalMatches, offset, limit, hasMore } (default 20 rows, max 200); format: "table" returns { columns, rows }, and format: "legacy" the output of 0.10 and earlier (deprecated), see CHANGELOG. Also countOnly, includeSubfolders, date range, unread/flagged/tag filters, searchBody (Gloda full text: terms under 3 characters are left out and listed in warning, English words match other forms, Russian and other languages only the exact word form) and dedupByMessageId (copies in several folders collapse into one row with dupLocations).

getMessage

Read full email content -- bodyFormat: markdown (default), text, or html. Bodies are capped (maxBodyChars, default 20000); a longer body sets bodyTruncated and nextBodyOffset, read the rest with bodyOffset. Set rawSource: true for the complete RFC 2822 source (same cap), decoded as UTF-8 when valid, else by its top-level, part or detected charset (rawCharset; a warning when parts declare different charsets, listed in rawMixedCharsets, or when invalid UTF-8 was replaced), with hidden characters removed as in a body; rawEncoding: "base64" returns the exact bytes. Optional attachment saving. Set includeInlineImages: true to append supported inline CID images as MCP image blocks (PNG, JPEG, GIF, or WebP; max 1 MiB base64 per image and 4 MiB total). Skipped images are reported in attachment metadata.

getMessages

Read full email content for up to the configured batch limit in one call (default 10, max 20). Uses the same bodyFormat, rawSource, and attachment options as getMessage; each item supplies messageId and folderPath. Bodies are capped per message (maxBodyChars, default 4000).

getRecentMessages

Recent messages newest first from all folders (Trash/Junk skipped) or one folder -- daysBack (default 7), unread/flagged filters, includeTrash, pagination. Same envelope, rows and format as searchMessages.

displayMessage

Open a message in Thunderbird's GUI -- 3pane (default), tab, or window mode

updateMessage

Mark read/unread, flag/unflag, add/remove tags, move between folders, or trash -- supports bulk via messageIds

deleteMessages

Delete messages -- drafts are safely moved to Trash

createFolder

Create new subfolders to organize your mail, or a saved search (virtual folder: a live view, nothing moved) with savedSearch

renameFolder

Rename an existing mail folder; returns its new URI as path

deleteFolder

Delete a folder (moves to Trash, or permanently deletes if already in Trash); a saved search is removed as a view, no mail deleted

moveFolder

Move a folder to a new parent within the same account

emptyTrash

Permanently delete all messages in Trash (including subfolders)

emptyJunk

Permanently delete all messages in Junk/Spam (including subfolders)

Compose

Tool

Description

sendMail

Compose a new email -- opens a review window; direct sending requires explicitly disabling the skipReview safety block, and adds the identity signature as the compose window would

replyToMessage

Reply with quoted original and proper threading, from the identity Thunderbird would pick. mode: window (default) opens a review window, draft saves a draft with the recipients Thunderbird's Reply / Reply All computes and the body its reply window builds (cite line, quote, signature, reply position), send (or skipReview: true) sends directly -- it needs explicit to and from and is subject to the same safety block. latestInThread: true (window or draft only) replies to the newest message of the conversation, Sent included, and returns it as repliedTo; threadIncomplete in the result means a large mailbox was read in part and a newer message may exist

forwardMessage

Forward with all original attachments preserved, from the identity Thunderbird would pick. mode as for replyToMessage (draft and send get the subject and body Thunderbird's forward window builds: header table, original body, signature); to is optional except with send, which needs explicit to and from

saveDraft

Save a new message as a draft, as Thunderbird's compose window saves it (with the identity signature), or edit an existing draft with draftId -- returns its messageId and folderPath

All compose tools open a window for you to review and edit before sending by default. The Block skipReview preference is on by default, so skipReview: true (and mode: "send") is rejected until you explicitly disable the preference; only then can it send directly. mode: "draft" only saves a draft, so the preference does not block it (even next to skipReview: true); it needs the saveDraft tool to be enabled in the settings, as a tool you disabled is not reachable through another one. Attachments can be file paths or inline base64 objects.

A direct send or saving a draft (saveDraft, mode: "draft") can take a while: the bridge waits up to 180 s for Thunderbird (30 s for every other call). Your MCP client may also have its own time limit for a tool call; if it is shorter than 180 s, the client can give up while Thunderbird goes on sending or saving, so check the Sent folder and the Outbox (or the Drafts folder) before retrying to avoid sending the message, or saving the draft, twice.

Compose tools validate the from identity strictly -- if the specified sender doesn't match any configured Thunderbird identity, the tool returns an error instead of silently substituting another account.

Filters

Tool

Description

listFilters

List all filter rules with human-readable conditions and actions; with confirmation: true, read the state of a pending or recent confirmation instead, optionally one by confirmationId (see below)

createFilter

Create filters with structured conditions (from, subject, date...) and actions (move, tag, flag...)

updateFilter

Modify a filter's name, enabled state, conditions, or actions

deleteFilter

Remove a filter by index

reorderFilters

Change filter execution priority

applyFilters

Run filters on a folder on demand -- let your AI organize your inbox

Full control over Thunderbird's message filters. Changes persist immediately. Your AI can create sorting rules, adjust priorities, and run them on existing mail. applyFilters runs only the enabled rules marked "Manually Run" (tick it in the filter editor on the rules the assistant may launch) and lists the ones it skipped.

Filter rules that forward or reply send mail without the review window that the compose tools keep. The Block filter forward/reply setting (Options > Send Safety) is on by default: while it is on, such rules cannot be created or changed through MCP, and a filter list that holds one cannot be run through applyFilters. Deleting the rule stays possible. If you choose Ask me each time instead, a request of that kind returns pending_user_confirmation and Thunderbird shows a dialog with the rule, its conditions and its full destination; nothing is written unless you confirm it there, and closing the dialog or not answering within ten minutes writes nothing.

Encrypted messages

OpenPGP and S/MIME messages are not decrypted for the assistant by default: getMessage returns their headers and a short notice instead of their content. searchMessages leaves out a message its query matched, getRecentMessages lists one with the wire-level subject, no preview and encrypted: true, and threadOf leaves them out and never links a conversation through their subject. The setting Let the assistant read encrypted messages (Options > Encrypted messages) turns this on; the decrypted content is then handed to the assistant, and so to the service that runs it.

Contacts

Tool

Description

searchContacts

Search contacts across all address books by email, name, or organization (e.g. acme or @acme.com); empty fields are omitted. Supports maxResults and format: "table".

getContact

Read full contact details by UID

createContact

Create a contact with optional email/name, phones, postal addresses, organization, title, note, and birthday. Phone-only contacts are supported.

updateContact

Update contact fields; omitted fields stay unchanged, while empty phone/address arrays clear those collections

deleteContact

Delete a contact by UID

Calendar

Tool

Description

listCalendars

List all calendars with read-only, disabled, event, and task support flags

createEvent

Create a calendar event -- opens a review dialog; direct creation via skipReview requires explicitly disabling the default safety block. Accepts status: tentative | confirmed | cancelled (VEVENT STATUS per iCal RFC 5545).

listEvents

Query events by date range with recurring event expansion; a date without a time is a whole day in local time. Returns status on each event. Supports maxResults and format: "table".

updateEvent

Modify an event's title, dates, location, description, or status

deleteEvent

Delete a calendar event by ID

createTask

Open a pre-filled task dialog for review; direct creation via skipReview requires explicitly disabling the default safety block

listTasks

List tasks/to-dos from calendars -- filter by completion status, due date, or calendar. Supports maxResults and format: "table".

updateTask

Update a task's title, due date, description, priority, completion status, or percent complete

listCategories

List the calendar category names defined in Thunderbird, to use exactly in events and tasks

Access Control

Tool

Description

getAccountAccess

View which accounts the MCP server can access

Account and tool access are configured via the extension settings page (Tools > Add-ons > Commonpost MCP for Thunderbird > Options). Access control is not MCP-exposed -- only the user can change it.

The same settings page has a "Send Safety" section. Block skipReview is enabled by default and rejects skipReview: true for sendMail, replyToMessage, forwardMessage, createEvent, and createTask (and mode: "send" for replyToMessage and forwardMessage); their review window or dialog still opens normally. skipReview is honored only after you explicitly disable this preference.


Setup

1. Install the extension

Download commonpost-mcp-v<version>.xpi from the latest release, then in Thunderbird: Tools > Add-ons and Themes > gear menu > Install Add-on From File, and restart. Each release also carries a provenance attestation (*.sigstore.json) that ties the XPI to the commit and the workflow that built it; you can check it with gh attestation verify <file>.xpi --repo commonpost/thunderbird-mcp. The XPI can be rebuilt byte for byte from the tagged source with node scripts/build-xpi-reproducible.cjs.

The MCP bridge, mcp-bridge.cjs, is attached to each release next to the XPI (with its own provenance attestation). You can also git clone --branch v<version> https://github.com/commonpost/thunderbird-mcp.git and use the file from the clone; use the bridge of the same version as the extension.

Requires Thunderbird 140 or later, and Node.js 22 or later for the bridge (mcp-bridge.cjs). Tested on Thunderbird 140.16.0esr, 153.3.1esr and 156.0.1.

Automatic updates: the add-on checks https://commonpost.github.io/thunderbird-mcp/updates.json through Thunderbird's add-on update check; the file lists the hash of each release. Thunderbird downloads updates in the background and applies them on the next restart; because this add-on uses an Experiment API, updates are not hot-swapped. If updates do not arrive, check the Add-ons gear menu and make sure Update Add-ons Automatically is enabled. Thunderbird's default xpinstall.signatures.required=false lets unsigned add-ons install; a profile hardened to require signatures blocks both manual and automatic installs. Because the auto-update channel is a code-delivery channel, you can turn it off (per add-on, in its details page) and update by hand. The bridge is not updated automatically: the add-on tells you (in a tool result and in its options page, section Bridge) when to replace your mcp-bridge.cjs or .mcpb with the one of a newer release; then reconnect your MCP client. Some protections live in the bridge.

2. Configure your MCP client

Add to your MCP client config (e.g. ~/.claude.json for Claude Code):

{
  "mcpServers": {
    "commonpost-mail": {
      "command": "node",
      "args": ["/absolute/path/to/commonpost-mcp/mcp-bridge.cjs"]
    }
  }
}

Claude Code plugin

This repository is also a Claude Code plugin marketplace: the plugin commonpost-mcp declares the commonpost-mail MCP server and carries the bridge of the release, so there is no mcp-bridge.cjs to download or to replace by hand.

claude plugin marketplace add commonpost/thunderbird-mcp
claude plugin install commonpost-mcp@commonpost
  • The plugin (plugins/claude-code/) contains only the bridge, a copy of this repository's mcp-bridge.cjs that the version check keeps identical; install the Thunderbird extension separately (step 1 above). Node.js 22 or later must be on the PATH.

  • Updates: Claude Code does not update a third-party marketplace on its own unless you turn it on (/plugin > Marketplaces > Enable auto-update). Otherwise run /plugin marketplace update commonpost (or claude plugin update commonpost-mcp@commonpost), then /reload-plugins. Each release raises the plugin's version, so an update follows every release, whether or not the bridge changed; the bridge in the plugin is always the one of the release.

  • Tool names carry the plugin and server names: mcp__plugin_commonpost-mcp_commonpost-mail__searchMessages, for example. Permission rules written for a server added by file (mcp__commonpost-mail__*) do not match them. The options page of the add-on (section Bridge) lists this bridge as a mcp-bridge.cjs file.

  • The plugin is fetched from this repository with git (main, or a release tag you pin with claude plugin marketplace add commonpost/thunderbird-mcp#vX.Y.Z, from v0.17.0 on); it is not signed. The bridge inside it is the mcp-bridge.cjs of that commit, the same file every release attests.

Claude Desktop (one-click bundle)

On macOS and Windows, Claude Desktop can install the bridge from a .mcpb bundle instead of a hand-edited config file. Download commonpost-mcp-v<version>.mcpb from the latest release and open it with Claude Desktop, then confirm the installation. If the file does not open in Claude Desktop (on Windows it may not be associated with it), use Settings > Extensions > Advanced settings > Install Extension and choose the file.

  • The bundle contains only the bridge (mcp-bridge.cjs). Install the Thunderbird extension separately (step 1 above). The bundle's version is the version of the bridge inside, which changes only when the bridge changes: a release can carry a bundle with a lower number than the add-on, and it is still the current bridge. Claude Desktop never updates a bundle installed from a file: install the new .mcpb when the add-on (in a tool result or in its options page, section Bridge) says so.

  • The bundle asks for Node.js 22 or later, like the bridge. It has no settings: if the bridge cannot find the connection file, use the manual configuration in Other MCP clients with COMMONPOST_MCP_CONNECTION_FILE.

  • The bundle is not signed. Each release carries a provenance attestation for it (*.mcpb.sigstore.json): check it with gh attestation verify <file>.mcpb --repo commonpost/thunderbird-mcp. It can be rebuilt byte for byte from the tagged source with node scripts/build-mcpb-reproducible.cjs.

Other MCP clients

The bridge is a standard MCP stdio server and is not tied to any client: it works with any client that can launch a local server. The mcpServers layout above is common but not universal, so each client below has its own file and format. In every case use the absolute path of mcp-bridge.cjs and the server name commonpost-mail, then restart the client.

Claude Desktop. Edit claude_desktop_config.json (Settings > Developer > Edit Config opens it): ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows. In JSON, double the backslashes of Windows paths.

{
  "mcpServers": {
    "commonpost-mail": {
      "command": "node",
      "args": ["C:\\Users\\<you>\\commonpost-mcp\\mcp-bridge.cjs"]
    }
  }
}

Visual Studio Code. Edit .vscode/mcp.json in a workspace, or run "MCP: Open User Configuration" for your user profile. The top-level key is servers (not mcpServers), and a stdio server needs "type": "stdio".

{
  "servers": {
    "commonpost-mail": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/mcp-bridge.cjs"]
    }
  }
}

Cursor. Edit ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project). The top-level key is mcpServers.

{
  "mcpServers": {
    "commonpost-mail": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-bridge.cjs"]
    }
  }
}

OpenAI Codex CLI. Edit ~/.codex/config.toml (or .codex/config.toml in a trusted project). This is TOML, not JSON: one table per server.

[mcp_servers.commonpost-mail]
command = "node"
args = ["/absolute/path/to/mcp-bridge.cjs"]

Gemini CLI. Edit ~/.gemini/settings.json (or .gemini/settings.json in a project). The top-level key is mcpServers. Its env block expands $VAR, ${VAR} and, on Windows, %VAR% references, so a value containing $ or % would be altered.

{
  "mcpServers": {
    "commonpost-mail": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-bridge.cjs"]
    }
  }
}

The bridge normally finds Thunderbird's connection file by itself, so no environment variable is needed. Only if it cannot, set COMMONPOST_MCP_CONNECTION_FILE to the file's real path in the server's environment: an "env": { ... } object next to args in the JSON formats, a [mcp_servers.commonpost-mail.env] table for Codex (see Sandbox-aware connection discovery; on Windows the file must be under the bridge's own %TEMP%). A path set there replaces the automatic discovery, so never leave a placeholder in it. Client formats change; if one of these no longer matches, follow the client's own MCP documentation and keep the same command and arguments.

Sandbox-aware connection discovery

The bridge re-discovers connection.json on every cache miss. It tries these locations in order:

  1. COMMONPOST_MCP_CONNECTION_FILE, if set

  2. Native temp dir: <os.tmpdir()>/commonpost-mcp/connection.json

  3. macOS fallback: /var/folders/*/*/T/commonpost-mcp/connection.json owned by the current user

  4. Linux Snap: only from a process that is really the confined Thunderbird snap (/proc/<pid>/exe resolves under /snap/thunderbird/ and SNAP_NAME=thunderbird is in its environment), read from its live TMPDIR; the official snap's own ~/Downloads/thunderbird.tmp fallback is tried only once such a process was actually seen

  5. Linux Flatpak / Betterbird Flatpak: the real /run/user/<uid> (verified by lstat, never trusted from $XDG_RUNTIME_DIR), under a closed list of app ids (org.mozilla.thunderbird, org.mozilla.thunderbird_esr, org.mozilla.Thunderbird, eu.betterbird.Betterbird)

This covers native installs, the official Thunderbird snap, Thunderbird Flatpak (including its beta channel, which shares the same app id installed from a different remote), and Betterbird Flatpak, without changing the extension side. If multiple sandbox candidates exist at once, the bridge tries the newest file first. Set COMMONPOST_MCP_CONNECTION_FILE to force a single explicit path.

Example override:

{
  "mcpServers": {
    "commonpost-mail": {
      "command": "node",
      "args": ["/absolute/path/to/commonpost-mcp/mcp-bridge.cjs"],
      "env": {
        "COMMONPOST_MCP_CONNECTION_FILE": "/absolute/path/to/connection.json"
      }
    }
  }
}

That's it. Your AI can now access Thunderbird.

Migrating from thunderbird-mcp

Both add-ons can be installed at the same time: they use different ids, preferences, ports (8780-8789 here, 8765-8774 there) and temporary directories. Nothing is shared or migrated automatically:

  • settings (extensions.thunderbird-mcp.*) are not copied; set them again in this add-on's options page. Until you do, every account and tool is visible to MCP clients: your account and tool restrictions are not carried over;

  • your MCP client must point its bridge at this repository's mcp-bridge.cjs (or the commonpost-mcp binary) and, if you set it, use COMMONPOST_MCP_CONNECTION_FILE (the old THUNDERBIRD_MCP_CONNECTION_FILE is ignored on purpose, so that one bridge never reads the other add-on's file);

  • if you keep both, the options page shows a notice, and each MCP client must be configured for the one you want. To avoid two servers touching the same mailbox, disable the one you do not use.


Security

  • Auth tokens: The HTTP server requires a session-scoped bearer token. Generated on startup, written to <TmpD>/commonpost-mcp/connection.json with 0600 permissions. The bridge re-discovers that file automatically across native installs, Snap, Flatpak, Betterbird Flatpak, and macOS temp directories. The options page also offers a stable token that stays the same across restarts, stored in a Thunderbird preference instead of the connection file; removing the add-on while it is still enabled clears that preference, but removing an add-on that was disabled first does not, so clear it yourself (uncheck "Use stable token" in the options page) before removing a disabled add-on.

  • Dynamic port: Tries ports 8780-8789, records the actual port in the connection file. No hardcoded port dependency.

  • Account access control: Restrict which email accounts are visible to MCP clients via the settings page. Changes take effect immediately.

  • Tool access control: Disable specific tools via the settings page. Disabled tools are hidden from tools/list and blocked at dispatch.

  • Localhost only: By default, the server binds to localhost only. The "Listen on all interfaces" option in settings binds to all IPv4 interfaces for WSL, Docker, or remote access. This exposes the MCP server to every device on your local network. Only enable on trusted networks. Auth token is always required.

  • Auto-update integrity: Auto-update is a code-delivery channel whose integrity depends on continued control of the GitHub repository, the GitHub Actions token, and the commonpost GitHub organization.

  • Bridge version: the bridge announces its version on every request (X-Commonpost-Bridge header). The add-on warns about bridges older than it recommends and can refuse bridges below a security floor written in its code (shipped disarmed); nothing is checked or downloaded over the Internet. The header is self-declared: the token, not the header, protects the server. See SECURITY.md.

Attachments refused

A sendMail, saveDraft, replyToMessage or forwardMessage call whose attachment path matches any of the following is refused, and the whole call fails (nothing is sent, saved, or opened) rather than silently dropping just that attachment:

  • a dotfile or dot-directory anywhere in the path (.ssh, .aws, .config/gcloud, .git-credentials, ...);

  • a filename that holds credentials or secrets on its own, wherever it is found (credentials.json, *.ppk, *.jks, *.pem, *.p12, *.kdbx, wallet.dat, terraform.tfstate*, Local State, browser cookie/login stores, ...);

  • system directories (/etc, /proc, C:\Windows\System32, ...) and each mail client's own profile (Thunderbird's, other mail clients' saved credentials);

  • the folders of every Thunderbird profile and the local folder of every mail account, wherever they are (another drive, a portable install, a folder you chose): the add-on lists them in the connection file, and the bridge refuses anything under them by path, by real path and by folder identity, so a link to them or a second mount of the same folder is refused too. This needs the add-on and the bridge of 0.17.1 or later. Not covered: the account folders of profiles other than the running one, a mail store at the root of a drive, a folder the bridge sees under another path (a bridge under WSL or in a container), and copies made outside these folders;

  • on macOS, anything under the signed-in user's Library folder (Mail, Messages, Keychains, Application Support, ...), including its APFS Data-volume real-path form;

  • on Windows, AppData and its compatibility-junction aliases (Local Settings, Application Data, Cookies, Recent, SendTo, ...) -- with one exception: the extension's own <TEMP>\commonpost-mcp\ backup folder, so a previously-saved attachment there can still be attached; connection.json itself is refused even there;

  • a UNC or device path (\\server\share\..., \\?\...), an alternate data stream, or a Windows form (8.3 short name, trailing dot or space) that resolves to a different name than the one given.

The bridge additionally resolves the attachment's real path (through symlinks and, on Windows, junctions and reparse points) and checks that too, so a denied file reached under an innocuous-looking name is still refused. The extension cannot do this on Windows (Gecko's nsLocalFile::IsSymlink has no implementation there) and instead refuses every string file path attachment on Windows outright; attach files through the bridge there.


If Thunderbird disables Experiment add-ons on the Release channel

This add-on uses a Thunderbird Experiment API (see docs/experiment-inventory.md). Thunderbird's Add-ons team has announced plans to stop running Experiment-API add-ons on the Release channel, and to keep supporting them on the ESR (Extended Support Release) channel. As of September 2026 this had not happened yet.

If that happens on your Thunderbird and this add-on stops working: switch to Thunderbird ESR. Downloads for every platform are on the official Thunderbird site (look for the "ESR" builds). This continuation has supported Thunderbird ESR since 0.8.2 (minimum 140.0; see the badge above and CHANGELOG.md).


Troubleshooting

Problem

Fix

Extension not loading

Check Tools > Add-ons and Themes. Errors: Tools > Developer Tools > Error Console

Connection refused

Make sure Thunderbird is running and the extension is enabled

Bridge can't find connection.json

Set COMMONPOST_MCP_CONNECTION_FILE explicitly if your environment uses a non-standard temp/runtime path

On Windows, bridge finds the file but still refuses it

The file must be under the bridge process's own %TEMP%. Running the bridge under WSL or in a container gives it a different %TEMP% than the one Thunderbird (native Windows) used, even if the file is reachable through \\wsl.localhost\... or a mount -- this is a correct refusal, not a bug. Set COMMONPOST_MCP_CONNECTION_FILE to the file's real path instead

Bridge in a container or under WSL, which used to find the connection file through a mounted temp folder, is now refused (stale or foreign process)

The bridge no longer trusts a file it cannot tie to a running Thunderbird. Set COMMONPOST_MCP_CONNECTION_FILE to the file's real path

On Windows, an attachment under %TEMP% is refused

%TEMP% sits under AppData\Local, which the deny-list treats like the rest of AppData (it holds credentials and app data for other programs on Windows). Copy the file to another folder first, for example Documents

Missing recent emails

IMAP folders can be stale. Click the folder in Thunderbird to sync, or right-click > Properties > Repair Folder

Tool not found after update

Reconnect MCP (/mcp in Claude Code) to pick up new tools

searchBody returns no results

IMAP accounts need offline sync enabled for Gloda to index message bodies

rawSource fails on IMAP

Requires local/offline message copy. Enable offline sync or click the message first to cache it.


Development

# Build the extension
./scripts/build.sh

# Test via the bridge (handles auth automatically)
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node mcp-bridge.cjs

# Test the HTTP API directly.
# On Snap / Flatpak / Betterbird Flatpak / macOS, point CONN_FILE at the
# real file or export COMMONPOST_MCP_CONNECTION_FILE first.
CONN_FILE="${COMMONPOST_MCP_CONNECTION_FILE:-/tmp/commonpost-mcp/connection.json}"
TOKEN=$(jq -r .token "$CONN_FILE")
PORT=$(jq -r .port "$CONN_FILE")
curl -X POST http://127.0.0.1:$PORT \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

A program that calls the HTTP API directly, without the bridge, sends no X-Commonpost-Bridge header and is treated like a bridge 0.11 or older: tool results can carry a notice to update the bridge, and replyToMessage / forwardMessage with mode: "send" or "draft" are refused (an old bridge stops waiting after 30 s). A direct client that waits at least 180 s for those calls can declare itself with -H "X-Commonpost-Bridge: 0.12.0; packaging=file". If a release arms the bridge security floor, a client without the header is refused entirely.

Dev-only extension reload: After changing extension source locally, remove the add-on from Thunderbird, restart, reinstall the XPI, and restart again. Thunderbird caches aggressively.

Run the tests with npm ci --ignore-scripts && npm test; see CONTRIBUTING.md. Everything that needs Thunderbird's full privileges is listed in docs/experiment-inventory.md.


Project structure

commonpost-mcp/
├── mcp-bridge.cjs              # stdio <-> HTTP bridge (auth, port discovery)
├── extension/
│   ├── manifest.json
│   ├── background.js           # Extension entry point
│   ├── httpd.sys.mjs           # Embedded HTTP server (Mozilla)
│   ├── options.html            # Settings page UI
│   ├── options.js              # Settings page logic
│   ├── icons/                  # Extension icons
│   └── mcp_server/
│       ├── api.js              # All 40 MCP tools + auth + access control
│       └── schema.json
├── test/                       # Test suite (node:test; fast-check for the property tests)
├── docs/                       # Experiment inventory, filter API notes
└── scripts/
    ├── build-xpi-reproducible.cjs   # release build (byte-for-byte reproducible)
    ├── build.sh                # quick development build
    └── install.sh

Known issues

  • IMAP folder databases can be stale until you click on them in Thunderbird

  • HTML-only emails are converted to plain text (original formatting is lost)

  • Recurring calendar event CRUD operates on the series, not individual occurrences

  • IMAP folder operations (rename, delete, move) are async -- verify with listFolders after

  • Combining tags with move/trash on IMAP may not preserve tags on the moved copy -- use separate calls

  • Pre-existing Thunderbird filters with cross-account move/copy targets are not restricted by account access control

  • searchBody on IMAP without offline sync only searches headers (Gloda limitation)

  • rawSource requires offline message copy for IMAP -- online-only messages will error


License and credits

MIT (see LICENSE): copyright Tomasz Kasperczyk (original project) and the Commonpost contributors. extension/httpd.sys.mjs is Mozilla's embedded HTTP server under the MPL-2.0 (see THIRD-PARTY.md). Fixes and ideas taken from upstream pull requests keep their authors: Tony (TKasperczyk/thunderbird-mcp#209), safrano9999 (TKasperczyk/thunderbird-mcp#214), Daniel Glaser (the78mole; TKasperczyk/thunderbird-mcp#195, since superseded by TKasperczyk/thunderbird-mcp#222), Neel Radhakrishnan (TKasperczyk/thunderbird-mcp#175), JordanRO2 (TKasperczyk/thunderbird-mcp#126, and the idea and preference name of the filter send guard, TKasperczyk/thunderbird-mcp#127), KinJLy and coulof (forks).

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides a Model Context Protocol interface for Mozilla Thunderbird, allowing AI assistants to manage emails, filters, calendars, and contacts. It exposes 24 tools for tasks like searching messages, drafting replies, and organizing folders through a local bridge.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides AI assistants with full access to Thunderbird email, compose, filters, calendar, and contacts via the Model Context Protocol.
    1
    -
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to control Thunderbird directly, including mail, folders, contacts, calendar, filters, and settings, through its own internals.
    50
    4
    MIT