---
title: "AI and MCP"
description: "Translate, write and summarise mail, connect AI clients to your mailbox, call MCP tools, and ask the docs."
url: "https://openemail.uk/docs/cli/ai-and-mcp"
area: "CLI"
category: "Using it"
---

# AI and MCP

Translate, write and summarise mail, connect AI clients to your mailbox, call MCP tools, and ask the docs.

## AI commands

| Command | What it does | Sign-in |
| --- | --- | --- |
| ai translate | Translate a subject and body without sending anything | Either kind, with `emails:send` |
| ai languages | List every language translation accepts | Any, or none: signed out it prints the table built into the CLI |
| ai compose "<prompt>" | Write an email body in your own style | A browser sign-in |
| ai summarize <thread-id> | Print the summary OpenEmail keeps for a thread | A browser sign-in |

`translate` and `compose` each spend one AI action from the workspace allowance for the day, and a spent allowance stops with exit code `8`. `compose` and `summarize` run through the MCP tools `composeEmail` and `getThreadSummary`, which is why they need a browser sign-in: an API key cannot reach the MCP server.

## Translate

**Terminal**

```
openemail ai translate --to de --subject "Your invoice" --text "The invoice is attached."
openemail ai translate --to Japanese --body-file reply.html --no-original
cat notes.txt | openemail ai translate --to fr
openemail ai languages --search port
```

It runs the translation a translated send would run and prints the result, so you can read it before anything leaves. Nothing is stored or sent. `--to` takes a code, an English name or the language’s own name. The body comes from `--text`, `--html`, `--body-file` or stdin, and `--text` and `--html` also read a file with `@path`.

- Your original text is kept below the translation, unless you pass `--no-original`.
- The detected source language is printed on stderr, and `--json` prints the whole translation.
- To translate as you send, use `openemail send --translate de`.

## Write and summarise

**Terminal**

```
openemail ai compose "thank Ada for the invoice and ask for a PDF copy" --to ada@example.com
openemail ai compose "say yes to Tuesday at 3pm" --thread CAHk7pQ2x9LmZ4 --tone friendly
openemail ai compose "decline politely" --thread CAHk7pQ2x9LmZ4 | openemail send --to ada@example.com --subject "Re: Proposal"
openemail ai summarize CAHk7pQ2x9LmZ4
```

- `compose` prints a body written in your style and sends nothing, so pipe it into `openemail send` when you are happy with it. With `--thread` it reads the latest messages of the thread first and writes a reply. `--tone` is one of `formal`, `friendly`, `casual`, `concise`, `direct` or `warm`.
- `summarize` prints the summary with the subject, sender and date. Summaries are written when mail arrives, and a thread that holds an encrypted message has none, which exits with code `5`.

## Connect an AI client

The OpenEmail MCP server gives an AI client the tools the assistant in the app uses: it can read and send mail and manage contacts, templates, domains and more, limited to what you approve. A client connects in one of two ways, and `openemail mcp config` prints both for the client you use:

- The remote server. The client runs its own browser sign-in, you approve it on the OpenEmail consent page, and it appears in Account → Connected apps. This is the simpler choice when the client supports it.
- The local bridge, `openemail mcp serve`, which the client starts through `npx`. It uses the sign-in of this CLI, so run `openemail login` first. It suits clients that only start local servers.

**Terminal**

```
openemail mcp config
openemail mcp config --client claude-code
openemail mcp config --client cursor --profile work
openemail mcp config --client vscode --json
```

**Remote server**

_Claude Code_

```bash
claude mcp add --transport http openemail https://api.openemail.uk/mcp
```

_Cursor_

```json
{ "mcpServers": { "openemail": { "url": "https://api.openemail.uk/mcp" } } }
```

_VS Code_

```json
{ "servers": { "openemail": { "type": "http", "url": "https://api.openemail.uk/mcp" } } }
```

_Windsurf_

```json
{ "mcpServers": { "openemail": { "serverUrl": "https://api.openemail.uk/mcp" } } }
```

_Codex_

```text
[mcp_servers.openemail]
url = "https://api.openemail.uk/mcp"
```

**Local bridge**

_Claude Code_

```bash
claude mcp add openemail -- npx -y @openemail/cli mcp serve
```

_Claude Desktop_

```json
{ "mcpServers": { "openemail": { "command": "npx", "args": ["-y", "@openemail/cli", "mcp", "serve"] } } }
```

_Cursor_

```json
{ "mcpServers": { "openemail": { "command": "npx", "args": ["-y", "@openemail/cli", "mcp", "serve"] } } }
```

_VS Code_

```json
{ "servers": { "openemail": { "type": "stdio", "command": "npx", "args": ["-y", "@openemail/cli", "mcp", "serve"] } } }
```

_Windsurf_

```json
{ "mcpServers": { "openemail": { "command": "npx", "args": ["-y", "@openemail/cli", "mcp", "serve"] } } }
```

_Codex_

```text
[mcp_servers.openemail]
command = "npx"
args = ["-y", "@openemail/cli", "mcp", "serve"]
```

After adding the remote server, Claude Code signs in from `/mcp` and Codex with `codex mcp login openemail`. Claude Desktop adds it under Settings → Connectors → Add custom connector. `openemail mcp config --client <name>` also says which file each client reads.

## The local bridge

`openemail mcp serve` reads newline-delimited JSON-RPC on stdin, forwards each message to the MCP server with your saved browser sign-in, and writes each answer to stdout as one line. It refreshes an expired access token without the client noticing, answers a batch as one array, and stops when stdin closes. Only protocol reaches stdout, and stderr stays quiet unless you pass `--debug`.

**Terminal**

```
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | openemail mcp serve
openemail mcp serve --profile work
openemail mcp serve --debug 2> mcp.log
```

> The bridge cannot ask for a verification code over stdio. A tool that needs one reaches the client as a refusal, and the bridge prints one hint on stderr. Run `openemail verify` in a terminal with the same profile, and those tools run for the next 60 minutes.

## Call tools yourself

**Terminal**

```
openemail mcp tools
openemail mcp tools composeEmail
openemail mcp call whoAmI
openemail mcp call listThreads --arg folder=inbox --arg maxResults=5
openemail mcp call getThread --args '{"threadId":"CAHk7pQ2x9LmZ4"}'
```

- `mcp tools` lists the tools this sign-in may use, which already leaves out any your role or the approval does not allow. Name a tool to see its description and arguments.
- `mcp call` takes the arguments as one JSON object in `--args` (inline, `@file` or `-`), and `--arg key=value` sets one at a time. A value is read as JSON when it parses, so quote a number you mean as text.
- The MCP server never asks for confirmation, so a tool that sends or deletes acts at once.
- A result that starts with `Refused (` exits with code `4`. An unknown tool exits with `5`, invalid arguments with `7`, and a spent AI allowance with `8`.

Six tools make a change the REST API guards with a verification code, and they ask for the same code: `createRule`, `setRuleEnabled`, `removeDomain`, `removeDomainAddress`, `deleteAudience` for an audience you created, and `emptyAudience` for an audience you created that still has contacts. In a terminal, `mcp call` asks for the code and calls the tool again. Unattended it exits with code `4`, so run `openemail verify` first.

## Ask the docs

**Terminal**

```
openemail docs ask "how do I verify a domain?"
openemail docs open cli/authentication
openemail docs read cli/commands
openemail docs read
```

- `docs ask` puts a question to the docs assistant and prints the answer as it is written, then the pages it came from. It answers only from this documentation, needs no sign-in and never sends your credentials. A question can be up to 600 characters, and each network can ask a limited number a day.
- `docs open` opens a page in your browser, and `--print` prints its link instead.
- `docs read` prints a page as Markdown. With no page it prints the index of every page.
