Skip to main content
Glama
goyalayus

email-mcp

by goyalayus
README.md
# email-mcp

MCP server that turns the existing `email_bridge.py` workflow into one outbound email tool with automatic single-thread mapping.

## Tool

- `send`
  - Sends an email in the mapped Gmail thread.
  - First call creates the thread.
  - Later calls keep replying in that same thread.

## Automatic Thread Mapping

Mapping key selection order:

1. explicit `context_id` argument
2. `CODEX_THREAD_ID` env var
3. `CODEX_SESSION_ID` env var
4. 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_id` in tool calls if you want separate Gmail threads per chat/session.
- Optional override: set `EMAIL_MCP_PROCESS_SESSION_KEY` to force a fixed fallback key.

## Prerequisites

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_ADDRESS`
- `CODEX_EMAIL_PASSWORD`
- `CODEX_EMAIL_TO` (or pass `to` in tool calls)
- optional SMTP/IMAP host/port vars from the email-bridge docs

## Install

```bash
cd email-mcp
npm install
```

## Add To Your App (MCP)

This 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_ADDRESS`
- `CODEX_EMAIL_PASSWORD`
- `CODEX_EMAIL_TO`
- `EMAIL_MCP_PREWARM=true`
- `EMAIL_MCP_BRIDGE_SCRIPT=/absolute/path/to/email-mcp/bridge/email_bridge.py`
- `EMAIL_MCP_PYTHON=python3`

### Codex (`~/.codex/config.toml`)

Add this in `~/.codex/config.toml`:

```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.

### Cursor (`~/.cursor/mcp.json` or project `.cursor/mcp.json`)

Add:

```json
{
  "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.

### Claude Code

Use MCP add with stdio:

```bash
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.js
```

If your Claude client uses JSON `mcpServers` config instead, use the same block shown in the Cursor example.

## Notes

- 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 `subject` inputs are ignored for that session.
- `send` uses 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.