Architecture
A file-by-file map of the source tree.
Architecture
src/rubit_mcp_mail/
server.py MCP tool definitions
__main__.py CLI: serve | install | auth | doctor | gui
installer.py setup wizard: writes config, signs in, registers with Claude
installer_gui.py the setup window (tkinter), falling back to the terminal
shortcuts.py Start Menu / Desktop / .desktop entries for the GUI
claude_registration.py claude_desktop_config.json / `claude mcp add`
session.py wires config + auth + backend; attachment path safety
config.py TOML config -> Account models
diagnostics.py the doctor checks, as data (shared by the CLI and the GUI)
permissions.py registry of per-account-toggleable tool names
config_editor.py every write to config.toml: comment-preserving, validated
config_gui.py the settings window (tkinter): accounts, permissions, doctor
providers.py provider profile registry
secrets.py keyring with 0600-file fallback
models.py pydantic models + message handles
mime.py BODYSTRUCTURE walking, decoding, HTML->text
backends/
base.py MailBackend protocol
imap.py the IMAP implementation
auth/
password.py app passwords
oauth_microsoft.py MSAL device-code flow
Adding a provider
src/rubit_mcp_mail/providers.py is a dict of profiles — host, port, and which
auth strategy to use. Adding a preset is one entry.
A provider that needs a non-IMAP API instead implements the MailBackend
protocol in src/rubit_mcp_mail/backends/base.py; the tool layer does not
change. That protocol's docstring carries the project's central rule:
No implementation may set flags, move, delete, append, or expunge.
The layering
server.pyis the only file that knows about MCP. It does argument validation, permission guarding, and turns exceptions into readable strings.session.pyowns the wiring — config in, an authenticated backend out — and is the only place that touches the filesystem for downloads.backends/imap.pyis the only file that speaks IMAP. Every read path usesEXAMINEandBODY.PEEK; there are no write paths, and a test enforces that.auth/hands back credentials without knowing what they'll be used for.