MCP server that turns the existing email_bridge.py workflow into one outbound email tool with automatic single-thread mapping.
send- Sends an email in the mapped Gmail thread.
- First call creates the thread.
- Later calls keep replying in that same thread.
Mapping key selection order:
- explicit
context_idargument CODEX_THREAD_IDenv varCODEX_SESSION_IDenv var- fallback: process-scoped key (
proc-<pid>-<random>)
Behavior:
- One mapping key -> one Gmail thread.
- Mapping is stored in
~/.codex/email-bridge/mcp-state/thread-map.json. - For non-Codex clients, pass
context_idin tool calls if you want separate Gmail threads per chat/session. - Optional override: set
EMAIL_MCP_PROCESS_SESSION_KEYto force a fixed fallback key.
This server includes a local bridge script at bridge/email_bridge.py (used as fallback when direct SMTP mode is unavailable).
Configure the same mailbox env vars used by that script:
CODEX_EMAIL_ADDRESSCODEX_EMAIL_PASSWORDCODEX_EMAIL_TO(or passtoin tool calls)- optional SMTP/IMAP host/port vars from the email-bridge docs
cd email-mcp
npm installThis is a local stdio MCP server.
- command:
node - args:
["/absolute/path/to/email-mcp/index.js"] - env: mailbox credentials + optional tuning flags
Recommended env vars:
CODEX_EMAIL_ADDRESSCODEX_EMAIL_PASSWORDCODEX_EMAIL_TOEMAIL_MCP_PREWARM=trueEMAIL_MCP_BRIDGE_SCRIPT=/absolute/path/to/email-mcp/bridge/email_bridge.pyEMAIL_MCP_PYTHON=python3
Add this in ~/.codex/config.toml:
[mcp_servers.email]
command = "node"
args = ["/absolute/path/to/email-mcp/index.js"]
tool_timeout_sec = 3600
[mcp_servers.email.env]
CODEX_EMAIL_ADDRESS = "your_email@gmail.com"
CODEX_EMAIL_PASSWORD = "your_app_password"
CODEX_EMAIL_TO = "recipient@example.com"
EMAIL_MCP_PREWARM = "true"
EMAIL_MCP_BRIDGE_SCRIPT = "/absolute/path/to/email-mcp/bridge/email_bridge.py"
EMAIL_MCP_PYTHON = "python3"tool_timeout_sec can stay high if you want one shared default, but this send-only server does not need long blocking timeouts.
Add:
{
"mcpServers": {
"email-mcp": {
"command": "node",
"args": ["/absolute/path/to/email-mcp/index.js"],
"env": {
"CODEX_EMAIL_ADDRESS": "your_email@gmail.com",
"CODEX_EMAIL_PASSWORD": "your_app_password",
"CODEX_EMAIL_TO": "recipient@example.com",
"EMAIL_MCP_PREWARM": "true"
}
}
}
}Then restart Cursor.
Use MCP add with stdio:
claude mcp add --transport stdio \
--env CODEX_EMAIL_ADDRESS=your_email@gmail.com \
--env CODEX_EMAIL_PASSWORD=your_app_password \
--env CODEX_EMAIL_TO=recipient@example.com \
--env EMAIL_MCP_PREWARM=true \
email-mcp -- node /absolute/path/to/email-mcp/index.jsIf your Claude client uses JSON mcpServers config instead, use the same block shown in the Cursor example.
- This MCP server only sends email.
- Incoming replies should be handled outside MCP by a watcher or intake flow, for example
bridge/email_bridge.py watch --once,bridge/email_bridge.py wait, or your higher-level helper scripts. - For stable Gmail threading, each mapped session uses one canonical subject base; later
subjectinputs are ignored for that session. senduses a pooled SMTP transport when SMTP env vars are present, which reduces repeated send overhead.- Startup prewarm is enabled by default (
EMAIL_MCP_PREWARM=true) and warms the SMTP path in the background.