Files
mcp-email/README.md
T

473 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MCP Email Server
A Dockerized MCP (Model Context Protocol) email assistant for law firms and legal teams.
Integrates:
- Multiple IMAP/SMTP email accounts
- Shared/public folder support
- New-message tracking and flagging
- Conflict check search
- Triage guidance using personnel/chain-of-command
Designed to be consumed by LLMs via MCP (Streamable HTTP) in Open WebUI.
## Quick start (single account)
1. Build:
docker build -t mcp-email-server /home/user/wall-o/mcp-email-server
2. Run (example):
docker run -d \
-p 8000:8000 \
-e API_KEY="your_api_key_here" \
-e LOG_LEVEL="DEBUG" \
-e IMAP_HOST=imap.example.com \
-e IMAP_PORT=993 \
-e IMAP_USE_SSL=true \
-e IMAP_USERNAME="user@example.com" \
-e IMAP_PASSWORD="secret" \
-e SMTP_HOST=smtp.example.com \
-e SMTP_PORT=587 \
-e SMTP_USE_TLS=true \
-e SMTP_USE_SSL=false \
-e SMTP_USERNAME="user@example.com" \
-e SMTP_PASSWORD="secret" \
-e SMTP_FROM="user@example.com" \
-e DEFAULT_CC="supervisor@example.com" \
-e BUSINESS_DESCRIPTION="A law firm handling corporate and litigation matters." \
-e PERSONNEL_JSON='[{"name":"Jane Doe","role":"Managing Partner","email":"jane@example.com","escalates_to":null},{"name":"John Smith","role":"Associate","email":"john@example.com","escalates_to":"Jane Doe"}]' \
mcp-email-server
3. Health check:
http://localhost:8000/health
4. MCP endpoint:
- POST http://localhost:8000/mcp
- Uses JSON-RPC 2.0 (methods: initialize, tools/list, tools/call)
5. Integrate with Open WebUI (MCP Streamable HTTP):
- Admin Settings → External Tools → Add Server
- Type: MCP (Streamable HTTP)
- Server URL: http://<your-server>:8000/mcp
- Auth: Bearer
- Key: your_api_key_here
- Save, then enable tools in a chat.
## Multi-account configuration
The server can manage multiple IMAP/SMTP accounts. Tools accept an optional "account" parameter; if omitted, the default account is used.
You have two main options:
1) Inline JSON (ACCOUNTS_JSON)
Set ACCOUNTS_JSON with a JSON array of accounts.
Copy-paste template (single line, for docker run):
-e ACCOUNTS_JSON='[{"id":"account1","name":"Primary Firm Inbox","imap_host":"imap.primary.com","imap_port":993,"imap_use_ssl":true,"imap_username":"user@primary.com","imap_password":"CHANGE_ME_1","smtp_host":"smtp.primary.com","smtp_port":587,"smtp_use_tls":true,"smtp_use_ssl":false,"smtp_username":"user@primary.com","smtp_password":"CHANGE_ME_1","smtp_from":"user@primary.com"},{"id":"account2","name":"Secondary Inbox","imap_host":"imap.secondary.com","imap_port":993,"imap_use_ssl":true,"imap_username":"user@secondary.com","imap_password":"CHANGE_ME_2","smtp_host":"smtp.secondary.com","smtp_port":587,"smtp_use_tls":true,"smtp_use_ssl":false,"smtp_username":"user@secondary.com","smtp_password":"CHANGE_ME_2","smtp_from":"user@secondary.com"}]'
Human-readable equivalent (for reference):
ACCOUNTS_JSON='[
{
"id": "account1",
"name": "Primary Firm Inbox",
"imap_host": "imap.primary.com",
"imap_port": 993,
"imap_use_ssl": true,
"imap_username": "user@primary.com",
"imap_password": "CHANGE_ME_1",
"smtp_host": "smtp.primary.com",
"smtp_port": 587,
"smtp_use_tls": true,
"smtp_use_ssl": false,
"smtp_username": "user@primary.com",
"smtp_password": "CHANGE_ME_1",
"smtp_from": "user@primary.com"
},
{
"id": "account2",
"name": "Secondary Inbox",
"imap_host": "imap.secondary.com",
"imap_port": 993,
"imap_use_ssl": true,
"imap_username": "user@secondary.com",
"imap_password": "CHANGE_ME_2",
"smtp_host": "smtp.secondary.com",
"smtp_port": 587,
"smtp_use_tls": true,
"smtp_use_ssl": false,
"smtp_username": "user@secondary.com",
"smtp_password": "CHANGE_ME_2",
"smtp_from": "user@secondary.com"
}
]'
2) JSON file (ACCOUNTS_CONFIG_PATH)
Mount a JSON file and set ACCOUNTS_CONFIG_PATH. Example:
docker run -d \
-p 8000:8000 \
-v /path/to/accounts.json:/etc/mcp-email/accounts.json:ro \
-e API_KEY="your_api_key_here" \
-e ACCOUNTS_CONFIG_PATH="/etc/mcp-email/accounts.json" \
mcp-email-server
Use the same structure as ACCOUNTS_JSON.
Default account:
- Use DEFAULT_ACCOUNT="firm_main" to set the default.
- If not set:
- If only one account exists, it is default.
- Otherwise, an account with id "default" is preferred, or the first one is used.
Tool usage with multiple accounts:
- Most tools accept an "account" field. Examples:
- list_folders: { "account": "firm_main" }
- search_messages: { "account": "secondary", "folder": "INBOX", "query": "conflict" }
- send_email: { "account": "firm_main", "to": ["client@example.com"], "subject": "...", "body": "..." }
- If "account" is omitted, the default account is used.
A new tool is available:
- list_accounts:
- Lists all configured accounts and shows which is default.
## Environment variables
See env.example for a ready-to-use template.
Core:
- API_KEY:
- If set, all /mcp requests must include:
Authorization: Bearer <API_KEY>
- Leave empty to disable auth (not recommended in production).
- LOG_LEVEL:
- e.g., INFO, DEBUG, ERROR (default: INFO)
Single-account IMAP (only if not using ACCOUNTS_JSON/ACCOUNTS_CONFIG_PATH):
- IMAP_HOST
- IMAP_PORT
- IMAP_USE_SSL
- IMAP_USERNAME
- IMAP_PASSWORD
Single-account SMTP (only if not using ACCOUNTS_JSON/ACCOUNTS_CONFIG_PATH):
- SMTP_HOST
- SMTP_PORT
- SMTP_USE_TLS
- SMTP_USE_SSL
- SMTP_USERNAME
- SMTP_PASSWORD
- SMTP_FROM
Multi-account configuration:
- ACCOUNTS_JSON:
- Inline JSON array of accounts (alternative to a mounted file).
- ACCOUNTS_CONFIG_PATH:
- Path inside the container to a JSON file with account definitions.
- DEFAULT_ACCOUNT:
- Default account ID to use when tools are called without specifying "account".
- If blank:
- If only one account exists, it is default.
- Otherwise, an account with id "default" is preferred, or the first one is used.
Time and timezone:
- TIMEZONE:
- IANA timezone used by get_current_time (e.g. "America/New_York", "Europe/London", "UTC").
- Default: "UTC".
- Example:
-e TIMEZONE="America/New_York"
Optional email defaults:
- DEFAULT_CC: Comma-separated CC addresses.
- DEFAULT_BCC: Comma-separated BCC addresses.
Business and triage context:
- BUSINESS_DESCRIPTION:
- Context for the LLM (e.g., firm description).
- PERSONNEL_JSON:
- JSON array of personnel/chain-of-command.
- Example:
[
{
"name": "Jane Doe",
"role": "Managing Partner",
"email": "jane@example.com",
"escalates_to": null
},
{
"name": "John Smith",
"role": "Associate",
"email": "john@example.com",
"escalates_to": "Jane Doe"
}
]
Scheduling:
- SCHEDULED_SEND_INTERVAL:
- Seconds between checks for scheduled emails (default: 10).
HTML signature and LLM identity:
- EMAIL_HTML_SIGNATURE:
- Optional HTML signature appended to HTML emails.
- Can be:
- Inline HTML string, or
- A file path inside the container (e.g. /etc/mcp-email/signature.html).
- Inline example:
-e EMAIL_HTML_SIGNATURE='<div style="font-size:12px;">Best regards,<br>Jane Doe<br>Associate</div>'
- Template file example:
- Mount:
-v /path/to/signature.html:/etc/mcp-email/signature.html:ro
- Set:
-e EMAIL_HTML_SIGNATURE='/etc/mcp-email/signature.html'
- Signature template variables:
- The signature can include placeholders:
- {{NAME}}
- {{TITLE}}
- {{PHONE}}
- {{ADDRESS}}
- {{EMAIL}}
- These are filled in using:
- Per-call LLM identity (signature_vars), or
- Fallback environment variables:
LLM_NAME, LLM_TITLE, LLM_PHONE, LLM_ADDRESS, LLM_EMAIL
- Example env-based defaults:
-e LLM_NAME='Adam P. Strömbergsson-DeNora'
-e LLM_TITLE='Barrister & Solicitor'
-e LLM_PHONE='1 613 699 2127'
-e LLM_ADDRESS='7th floor - 1 Rideau St. Ottawa, ON. K1N 8S7'
-e LLM_EMAIL='adam@apstrom.ca'
- LLM identity via MCP (signature_vars):
- When sending, replying, forwarding, or scheduling an email, the LLM should include its identity so the signature is populated correctly.
- Example (send_email):
{
"name": "send_email",
"arguments": {
"to": ["client@example.com"],
"subject": "Your subject",
"body": "<p>Hello,</p><p>...</p>",
"html": true,
"signature_vars": {
"NAME": "Adam P. Strömbergsson-DeNora",
"TITLE": "Barrister & Solicitor",
"PHONE": "1 613 699 2127",
"ADDRESS": "7th floor - 1 Rideau St. Ottawa, ON. K1N 8S7",
"EMAIL": "adam@apstrom.ca"
}
}
}
- The LLM must provide accurate identity details; do not leave these fields blank or generic.
External summary model (for summarize_email):
- EXTERNAL_SUMMARY_MODEL_ENDPOINT:
- OpenAI-compatible /v1/chat/completions endpoint.
- Example: http://localhost:8080/v1
- EXTERNAL_SUMMARY_MODEL_API_KEY:
- API key for the external model.
- EXTERNAL_SUMMARY_MODEL_NAME:
- Model name (default: gpt-4o-mini).
- EXTERNAL_SUMMARY_MAX_TOKENS:
- Max tokens for each summary (default: 400).
CalDAV / CardDAV (e.g., Nextcloud) - if used by integrations:
- DAV_BASE_URL
- DAV_USERNAME
- DAV_PASSWORD
- DAV_VERIFY_TLS
## MCP tools
All tools are exposed via MCP (Streamable HTTP) at POST /mcp.
General:
- list_accounts
- get_current_time
Email (listing, reading, and triage):
- list_folders
- search_messages
- get_new_messages
- sync_seen
- get_unread_summary
- list_unread_emails
- get_email
- summarize_email
- get_thread
Email (actions):
- mark_as_read
- flag_message
- move_message
- copy_message
- apply_label
- remove_label
- list_labels
Email (send/reply/forward):
- send_email
- reply_to_message
- forward_message
- save_draft
- schedule_send
Attachments and threads:
- list_attachments
- download_attachment
- search_attachments
- export_conversation
Legal-specific:
- conflict_check_search
- get_triage_config
Notes:
- IMAP operations use UIDs for stability.
- Conflict check search scans subject lines across specified folders for given terms.
- New-message tracking is in-memory per container instance.
- For production:
- Always set API_KEY.
- Use HTTPS and secure IMAP/SMTP settings.
## New tools for efficient email triage
These tools are designed to help LLMs triage many emails without overloading the context window.
- list_unread_emails
- Purpose: List unread emails with minimal content (metadata + short snippet).
- Use this first when scanning a large inbox.
- Parameters:
- account: optional (uses default if omitted)
- folder: IMAP folder (default: INBOX)
- max_results: max emails to return (default: 50)
- include_body: if true, include full body (default: false)
- since: optional SINCE date, e.g. "01-Jan-2024"
- Returns:
- For each email: uid, subject, from, to, date, flags, snippet, has_attachments
- Plus total_unread and returned counts
- get_email
- Purpose: Fetch the full content of a single email by UID.
- Use this after scanning with list_unread_emails or get_unread_summary.
- Parameters:
- folder: IMAP folder (default: INBOX)
- uid: message UID
- include_html: if true, include HTML body (default: false)
- Returns:
- subject, from, to, cc, date, body_plain, attachments
- body_html only if include_html=true
- summarize_email
- Purpose: Get a concise summary of an email via an external model (if configured), instead of loading the full text into the main LLM context.
- Use this when you need to understand an email quickly without reading its full content.
- Parameters:
- folder: IMAP folder (default: INBOX)
- uid: message UID
- max_length: max summary length in words (default: 150)
- Behavior:
- If external summary model is configured, it sends the email to that model and returns its summary.
- If not configured or the call fails, it falls back to the first N words of the email.
- Returns:
- uid, subject, from, date, summary (including attachment note if present)
- get_thread
- Purpose: Get a concise view of the conversation thread for a given email.
- Use this to understand context without loading all message bodies.
- Parameters:
- folder: IMAP folder (default: INBOX)
- uid: message UID to use as the anchor
- max_messages: max thread messages to return (default: 10)
- Returns:
- subject, participants, message_count
- For each message: uid, from, date, subject, snippet (short)
Suggested LLM workflow:
1) Call list_unread_emails(max_results=100) to scan metadata.
2) For interesting emails:
- Use summarize_email(uid) for a quick summary, or
- Use get_email(uid) if you need the full content.
3) For email threads:
- Use get_thread(uid) to see the conversation outline.
- Then selectively call get_email on key messages.
## External summary model configuration
Optional: configure an external LLM to summarize emails via summarize_email.
This keeps long emails out of the main models context.
Environment variables:
- EXTERNAL_SUMMARY_MODEL_ENDPOINT:
- OpenAI-compatible /v1/chat/completions endpoint.
- Example: http://localhost:8080/v1
- EXTERNAL_SUMMARY_MODEL_API_KEY:
- API key for the external model.
- EXTERNAL_SUMMARY_MODEL_NAME:
- Model name (default: gpt-4o-mini).
- EXTERNAL_SUMMARY_MAX_TOKENS:
- Max tokens for each summary (default: 400).
Example (docker run):
-e EXTERNAL_SUMMARY_MODEL_ENDPOINT='http://localhost:8080/v1' \
-e EXTERNAL_SUMMARY_MODEL_API_KEY='your_summary_model_key' \
-e EXTERNAL_SUMMARY_MODEL_NAME='gpt-4o-mini' \
-e EXTERNAL_SUMMARY_MAX_TOKENS='400'
If these are not set:
- The summarize_email tool will still work, but will fall back to returning the first N words of the email instead of using an external model.
## get_current_time tool
Provides the LLM with a reliable reference time so it can interpret relative terms like "today", "yesterday", or "last week".
- Name: get_current_time
- Input: none
- Output:
- iso: current time in ISO 8601 format (e.g. 2025-06-28T10:15:00+01:00)
- timezone: configured timezone (from TIMEZONE env variable)
Usage:
- Call get_current_time when:
- Filtering or sorting by relative dates
- Checking if an email is recent or overdue
- The tool uses the TIMEZONE environment variable.
- Example Docker run:
docker run -d \
-p 8000:8000 \
-e TIMEZONE="America/New_York" \
mcp-email-server