Skip to content
Conduit

mcp server

beadle

Claude Code via e-mail based on an addressbook with UNIX style rwx permissions per interaction pair.

punt-labs/beadlecommunitylistedunreviewed

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 25, 2026

beadle

Email for your AI engineering assistant.

License CI Go Reference Working Backwards

beadle-email is an MCP server that gives Claude Code, or any MCP client, a real email address --- for developers who want their AI coding assistant to receive and send email under cryptographic control. Every message is classified into one of four trust levels, from Proton-to-Proton end-to-end encryption down to an unverified message with no signature, and per-contact rwx permissions gate what the agent can read, reply to, and act on. It is the first shipping piece of a larger vision for a GPG-signed, autonomous agent daemon (beadle-daemon). That daemon works — GPG-signed command files, trust and permission gates, a pipeline runner — but is not part of this release: it ships no binary, and no init/sign tooling exists yet for an operator to configure it.

Platforms: macOS, Linux

Quick Start

curl -fsSL https://raw.githubusercontent.com/punt-labs/beadle/4cc7f6b/install.sh | sh

Downloads the beadle-email binary, verifies its SHA256 checksum, and attempts to install the Claude Code plugin (MCP tools + slash commands + hooks). If plugin installation fails, the script falls back to registering the standalone MCP server (no slash commands or hooks). Runs doctor to check your setup. Restart Claude Code after install. If you previously registered beadle-email as a standalone MCP server via claude mcp add, remove it first with claude mcp remove beadle-email to avoid duplicate registrations.

Plugin install provides MCP tools, slash commands (/inbox, /mail, /send, /contacts, /beadle), and hooks (two-channel display, automatic session setup). Standalone MCP provides only MCP tools --- no slash commands or hooks.

curl -fsSL https://raw.githubusercontent.com/punt-labs/beadle/4cc7f6b/install.sh -o install.sh
cat install.sh
sh install.sh
mkdir -p ~/.local/bin
curl -fsSL https://github.com/punt-labs/beadle/releases/latest/download/beadle-email-darwin-arm64 -o ~/.local/bin/beadle-email
chmod +x ~/.local/bin/beadle-email

Replace darwin-arm64 with your platform: darwin-amd64, linux-arm64, linux-amd64. Ensure ~/.local/bin is on your PATH. Configure your MCP client to run beadle-email serve.

  • An IMAP server for reading (Proton Bridge on localhost, Fastmail, Gmail IMAP, etc.)
  • An SMTP server for sending (Proton Bridge, or any SMTP with STARTTLS support, or implicit TLS/SMTPS on port 465)
  • GPG for signature verification
  • (Optional) Resend API key for fallback sending

Features

  • 23 MCP tools (21 always-on + 2 poll tools gated on config) --- list, search, read, reply, send, mark read/unread (single + batch), move/archive (single + batch), download attachments, verify signatures, inspect MIME, classify trust, list folders, address book (list/find/add/remove contacts), whoami, switch_identity, enable/disable repo guidance, inbox polling (set interval, get status)
  • Multi-identity via ethos --- identity resolved per-request from ethos sidecar. Repo-local config pins identity. Mid-session switching via switch_identity tool. Fallback to default-identity file
  • Two-dimensional trust --- transport trust (trusted/verified/untrusted/unverified) + identity permissions (rwx per contact per identity). Both must pass before autonomous action
  • Four-level transport trust --- trusted (Proton-to-Proton E2E), verified (valid PGP), untrusted (bad PGP), unverified (no signature)
  • Inline PGP verification --- list_messages runs gpg --verify on signed messages automatically
  • Slash commands (plugin only) --- /inbox (process your inbox), /mail (email someone), /send (multi-channel outbound), /contacts (manage the address book), /beadle (enable/disable repo guidance)
  • Two-channel display (plugin only) --- compact panel summaries with full data in context, no raw JSON in conversation
  • Proton Bridge native --- IMAP STARTTLS for reading, SMTP for sending, Resend API fallback
  • Credential isolation --- secrets resolved at runtime from OS keychain, never stored in config files
  • Health checks --- doctor validates all dependencies; status shows active identity and configuration

What It Looks Like

$ curl -fsSL https://raw.githubusercontent.com/punt-labs/beadle/4cc7f6b/install.sh | sh
...
▶ Running doctor...
[+] version          0.16.5
[+] identity         you@example.com (source: ethos)
[+] secret_backends  pass, secret-tool, file (~/.punt-labs/beadle/secrets/), environment variable
[+] config           ~/.punt-labs/beadle/identities/you@example.com/email.json
[+] imap_password
[+] resend_api_key
[+] gpg              /usr/bin/gpg
[+] gpg_signing_key  you@example.com
[+] gpg_passphrase   not required (you@example.com has no passphrase — filesystem access grants signing authority)
[+] smtp             127.0.0.1:1025
[+] contacts         2 contacts at ~/.punt-labs/beadle/identities/you@example.com/contacts.json
[+] mcp_registration plugin provides the MCP server (no standalone duplicate)

beadle-email v0.16.5 is ready!

MCP Tools

ToolPurpose
list_messagesList messages with trust levels. PGP signatures verified inline. Repo-scoped by default; all_repos widens. Paginate with offset.
search_messagesSearch the mailbox by from / subject / since / text (server-side IMAP SEARCH). Repo-scoped by default; all_repos widens.
read_messageRead full message body, headers, attachments, and trust classification. Does not mark the message read.
reply_messageReply to a message: threads via In-Reply-To/References, preserves the Re: + repo tag, quotes the original. Write-gated like send_email.
send_emailSend via Proton Bridge SMTP (primary) or Resend API (fallback). Resolves contact names inline.
mark_message / batch_mark_messagesMark one or many messages read (or \Seen cleared with unread). Reports the count actually changed.
move_messageMove a message to another folder. Defaults to Archive.
batch_move_messagesMove multiple messages to another folder in one call. Returns the count actually moved.
list_foldersList all IMAP mailbox folders.
show_mimeInspect multipart MIME structure, PGP parts, and attachments.
verify_signatureVerify PGP signature on a message. Returns signer info and key ID.
check_trustDetailed trust classification with encryption type, origin analysis, and identity permission for sender.
download_attachmentExtract an attachment by MIME part index (from show_mime). Saves to identity-scoped directory.
list_contactsList all contacts with effective permissions for the active identity.
find_contactLook up a contact by name, email, or alias. Shows effective permissions.
add_contactAdd a contact (name, email, aliases, GPG key ID, permissions).
remove_contactRemove a contact by name.
whoamiReturn the active identity (email, display name, ethos handle).
switch_identitySwitch the active identity for this session. Pass an ethos handle or empty to reset.
enableTurn beadle's repo guidance on or off in this repo (action: enable or disable). Deposits the guide + enabled marker and adds the @.punt-labs/beadle/CLAUDE.md import, or removes them. Same marker as the CLI enable/disable.
set_poll_intervalSet automatic inbox polling interval (1m, 2m, 3m, 5m, 10m, 15m, 30m, 1h, 2h) or disable (n).
get_poll_statusReturn current polling configuration: interval, active state, last check time, unseen count.

Commands

Available when installed as a Claude Code plugin.

CommandWhat it does
/inboxCheck beadle's email inbox. Optional natural language filter.
/inbox 3mSet inbox polling interval (1m, 2m, 3m, 5m, 10m, 15m, 30m, 1h, 2h).
/inbox nDisable automatic inbox polling.
/inbox statusShow current polling configuration.
/mailMail something to the owner or a specific recipient.
/sendSend via any channel (email today, Signal later).
/contactsManage address book (list, add with permissions, remove, find).
/beadle enable / /beadle disableTurn beadle's repo guidance on or off in this repo (writes the enabled marker + CLAUDE.md import). Commit the change via a PR.

Setup

Beadle resolves credentials at runtime through a priority chain: OS keychain → secret file → environment variable. On Linux, the keychain layer tries pass first, then secret-tool (libsecret / GNOME Keyring). On macOS, it uses the system Keychain.

macOS Keychain:

security add-generic-password -s beadle -a imap-password -w 'your-bridge-password'
security add-generic-password -s beadle -a resend-api-key -w 'your-resend-key'
security add-generic-password -s beadle -a gpg-passphrase -w 'your-gpg-passphrase'

pass (Linux, recommended --- GPG-encrypted at rest with your own key):

pass insert beadle/imap-password
pass insert beadle/resend-api-key
pass insert beadle/gpg-passphrase

secret-tool (Linux, fallback --- GNOME Keyring via libsecret):

secret-tool store --label='beadle imap-password' service beadle account imap-password
secret-tool store --label='beadle resend-api-key' service beadle account resend-api-key
secret-tool store --label='beadle gpg-passphrase' service beadle account gpg-passphrase

Secret files (~/.punt-labs/beadle/secrets/<name>, mode 600):

mkdir -p ~/.punt-labs/beadle/secrets
printf '%s' 'your-bridge-password' > ~/.punt-labs/beadle/secrets/imap-password
chmod 600 ~/.punt-labs/beadle/secrets/imap-password

Environment variables:

export BEADLE_IMAP_PASSWORD='your-bridge-password'
export BEADLE_RESEND_API_KEY='your-resend-key'

Create the configuration file (~/.punt-labs/beadle/email.json) with your connection parameters.

Proton Bridge (localhost):

mkdir -p ~/.punt-labs/beadle
cat > ~/.punt-labs/beadle/email.json << 'EOF'
{
  "imap_host": "127.0.0.1",
  "imap_port": 1143,
  "imap_user": "you@example.com",
  "smtp_host": "127.0.0.1",
  "smtp_port": 1025,
  "smtp_user": "you@example.com",
  "from_address": "you@example.com",
  "poll_interval": "3m"
}
EOF

External IMAP + SMTP (Fastmail, Gmail, etc.):

{
  "imap_host": "imap.fastmail.com",
  "imap_port": 143,
  "imap_user": "you@fastmail.com",
  "smtp_host": "smtp.fastmail.com",
  "smtp_port": 587,
  "smtp_user": "you@fastmail.com",
  "from_address": "you@fastmail.com",
  "poll_interval": "10m"
}

Trust Model

LevelSenderDetectionWhat It Means
trustedProton → ProtonX-Pm-Content-Encryption: end-to-end + X-Pm-Origin: internalEnd-to-end encrypted by Proton infrastructure
verifiedExternalgpg --verify returns exit 0Valid PGP signature from a known key
untrustedExternalgpg --verify returns non-zeroPGP signature present but invalid or from unknown key
unverifiedExternalNo multipart/signedNo PGP signature present

PGP verification uses an isolated GNUPGHOME per operation. When no key is attached to the message, keys are bridged from the system keyring (~/.gnupg/) into the isolated environment.

Identity

The simplest identity setup needs one file: ~/.punt-labs/beadle/default-identity, a plain-text email address. Beadle uses that identity for everything --- no other identity configuration required (see Setup for the separate IMAP/SMTP config every identity still needs).

Beadle works better with ethos (sidecar pattern --- file reads, no import dependency) if you want more than one identity: per-repo identity pinning, or mid-session switch_identity switching. When ethos is present, resolution checks, in order:

  1. Repo-local config --- .punt-labs/ethos.yaml with agent: <handle>
  2. Global ethos active --- ~/.punt-labs/ethos/active
  3. Handle → ethos identity YAML --- ~/.punt-labs/ethos/identities/<handle>.yaml supplies name and email; ~/.punt-labs/ethos/identities/<handle>.ext/beadle.yaml supplies a GPG key ID that beadle-email identity reports (it doesn't drive signing --- that's email.json's gpg_signer field either way). Always global, never a repo-local vendored copy.

If no step resolves a handle --- ethos isn't installed, or nothing pins one --- beadle falls back to the plain default-identity file above. If a handle is resolved but its ethos identity file is missing or unreadable, beadle fails closed instead of falling back --- operating as the wrong identity is worse than failing.

Each identity gets its own directory under ~/.punt-labs/beadle/identities/<email>/ with separate email.json, contacts.json, and attachments/. Root files are auto-migrated on first use.

Contact Permissions

Each contact has an optional permissions map keyed by identity email. Permissions use the Unix rwx model:

PermissionMeaning
r (read)Beadle reads and surfaces the message. No autonomous action.
w (write)Beadle may compose and send replies to this contact.
x (execute)Beadle may execute instructions from this contact.

All permissions are stored explicitly. There are no implicit overrides. Contacts without explicit permissions default to --- (no permissions). The address book is a whitelist: messages from unknown senders appear redacted in listings and cannot be read. r and w are enforced; x enforcement is planned. This is orthogonal to transport trust --- both must be sufficient for autonomous action.

CLI

beadle-email list [--folder F] [--count N] [--offset N] [--unread] [--all-repos]  # List (current repo by default)
beadle-email read <uid> [--folder F]                    # Read a message (leaves it unread)
beadle-email search [--from A] [--subject S] [--since D] [--text T] [--count N] [--offset N] [--unread] [--all-repos]  # Search the mailbox
beadle-email mark <uid> [--ids a,b,c] [--unread] [--folder F]  # Mark message(s) read/unread
beadle-email send --to ADDR --subject S --body B        # Send an email
beadle-email reply <uid> --body B [--folder F]          # Reply to a message (threaded, quoted)
beadle-email move <uid> [--folder F] [--to DEST]        # Move a message
beadle-email folders                                    # List IMAP folders
beadle-email contact list|add|remove|find               # Manage contacts
beadle-email install                                    # Set up beadle-email (once per machine)
beadle-email uninstall                                  # Remove beadle-email
beadle-email enable                                     # Turn on agent guidance in this repo
beadle-email disable [--purge]                          # Turn it off (--purge deletes the dir)
beadle-email serve [--config PATH]                      # Start MCP server
beadle-email doctor [--config PATH]                     # Check installation health
beadle-email status [--config PATH]                     # Current state summary
beadle-email identity                                   # Show active identity
beadle-email identity set <handle>                      # Set per-repo identity
beadle-email version                                    # Print version

# Global flags (supported by most subcommands; not: install, uninstall, version)
beadle-email --json list                                # JSON output
beadle-email --verbose doctor                           # Debug logging
beadle-email --quiet send --to ...                      # Errors only

install is a once-per-machine step (the binary and the MCP server, which is provided by the beadle marketplace plugin). enable and disable are per-repo: enable, run inside a repo, deposits beadle's agent user-guide at .punt-labs/beadle/CLAUDE.md, writes an enabled marker, and adds the single @.punt-labs/beadle/CLAUDE.md import line to the repo's CLAUDE.md so an agent working there learns how to drive beadle. disable removes that line and the marker, leaving the guide dormant; disable --purge deletes the .punt-labs/beadle/ directory outright. This follows the org Tool Enable/Disable standard.

When a single mailbox is shared by an agent across repos, list shows only the current repo's mail by default (matched by the X-Beadle-Repo header or the [owner/repo] subject tag, with the repo taken from the git origin remote). Pass --all-repos to see the whole mailbox. If the current directory has no repo, list shows everything. The background new-mail poller's count is scoped the same way.

Documentation

Setup Guide | Design Log | Contributing | Changelog

License

MIT

↑↓ navigate openesc close