Content
<!-- mcp-name: io.github.salahawad/outlook-personal-mcp -->
# outlook-personal-mcp
An MCP server that gives Claude Code and Codex full control of a personal Outlook.com mailbox and calendar via the Microsoft Graph API. Written in Python, speaks the MCP stdio transport, and uses per-user device-code OAuth so your credentials never leave your machine. MIT licensed.
---
## Features
- **Mail** — list, search, read, send, reply, forward, move, copy, flag, mark read/unread, delete (soft or hard)
- **Drafts** — create, update, attach local files, send
- **Folders** — list, create, rename, delete
- **Calendar** — list calendars, list/search/get/create/update/delete events, respond to invites (accept/decline/tentative), check free/busy availability
- **Per-user OAuth** — you register your own free Azure app; the server authenticates with your Microsoft account and caches the token locally
- **Local stdio** — runs as a child process of the MCP host; your mailbox data never transits a third party
---
## Prerequisites
- Python 3.10 or later
- [`uv`](https://docs.astral.sh/uv/) (fast Python package and tool runner) — **required at runtime**: the server is launched via `uvx`, and it is not bundled by your MCP host (including Claude Desktop). Install it with `curl -LsSf https://astral.sh/uv/install.sh | sh` (macOS/Linux) or `powershell -c "irm https://astral.sh/uv/install.ps1 | iex"` (Windows).
- A personal Microsoft account (Outlook.com, Hotmail, Live, etc.)
- A free Azure app registration (see below — takes about three minutes)
---
## Azure App Registration
1. Go to [https://portal.azure.com](https://portal.azure.com) → **Microsoft Entra ID** → **App registrations** → **New registration**.
2. Name it anything you like (e.g. `outlook-personal-mcp`). Under **Supported account types** choose **Personal Microsoft accounts only**. No redirect URI is needed. Click **Register**.
3. Open the app → **Authentication** → **Advanced settings** → **Allow public client flows** → set to **Yes** → **Save**. (This is required for the device-code login flow used by this server.)
4. Go to **API permissions** → **Add a permission** → **Microsoft Graph** → **Delegated permissions**, then add:
- `Mail.ReadWrite`
- `Mail.Send`
- `Calendars.ReadWrite`
(`User.Read` is included by default; `offline_access` is requested automatically at runtime — you do not need to add it.)
5. Copy the **Application (client) ID** from the **Overview** page. This is your `OUTLOOK_MCP_CLIENT_ID`.
### Alternatively: create the app with the Azure CLI
If you have the [`az` CLI](https://learn.microsoft.com/cli/azure/install-azure-cli), the whole registration is one command:
```bash
az login --use-device-code --allow-no-subscriptions # sign in with your personal account
az ad app create \
--display-name "outlook-personal-mcp" \
--sign-in-audience PersonalMicrosoftAccount \
--is-fallback-public-client true \
--required-resource-accesses '[{"resourceAppId":"00000003-0000-0000-c000-000000000000","resourceAccess":[{"id":"024d486e-b451-40bb-833d-3e66d98c5c73","type":"Scope"},{"id":"e383f46e-2787-4529-855e-0e479a3ffac0","type":"Scope"},{"id":"1ec239c2-d7c9-4623-a91a-a9775856bb36","type":"Scope"}]}]' \
--query appId -o tsv
```
The printed `appId` is your `OUTLOOK_MCP_CLIENT_ID`. (The GUIDs are the Microsoft Graph delegated scopes `Mail.ReadWrite`, `Mail.Send`, and `Calendars.ReadWrite`.) **Note:** a brand-new app registration takes a few minutes to propagate to Microsoft's consumer login endpoint — if your first login fails with `AADSTS700016` ("application … not found"), wait a few minutes and retry.
---
## Install & First-Time Login
Run the one-time interactive login. It prints a short URL and a code; open the URL in any browser, enter the code, approve the permissions, and you are done. The token is cached at `~/.config/outlook-personal-mcp/token_cache.bin` (mode 600) and refreshed automatically on subsequent runs — you will not be prompted again unless the refresh token expires or is revoked.
```bash
OUTLOOK_MCP_CLIENT_ID=<your-app-client-id> uvx mcp-outlook-personal login
```
> To run the latest unreleased code from source instead of the PyPI release, swap `mcp-outlook-personal` for `--from git+https://github.com/salahawad/outlook-personal-mcp mcp-outlook-personal`.
---
## Configure Claude Code
Add the server to your project's `.mcp.json` (or `~/.claude/.mcp.json` for all projects):
```json
{
"mcpServers": {
"outlook": {
"command": "uvx",
"args": ["mcp-outlook-personal"],
"env": { "OUTLOOK_MCP_CLIENT_ID": "<your-app-client-id>" }
}
}
}
```
Alternatively, use the CLI: `claude mcp add`.
---
## Configure Codex
Add the server to `~/.codex/config.toml`:
```toml
[mcp_servers.outlook]
command = "uvx"
args = ["mcp-outlook-personal"]
env = { OUTLOOK_MCP_CLIENT_ID = "<your-app-client-id>" }
```
---
## Install as a Claude Desktop extension (.mcpb)
This server is also packaged as a [Claude Desktop extension](https://www.anthropic.com/engineering/desktop-extensions) (`.mcpb`). Build the bundle from a checkout:
```bash
npx @anthropic-ai/mcpb pack . dist/mcp-outlook-personal.mcpb
```
Then in Claude Desktop open **Settings → Extensions**, install the `dist/mcp-outlook-personal.mcpb` file, and enter your **Azure App Client ID** (plus any optional settings) when prompted.
> **Requirement:** the extension launches the server with `uvx mcp-outlook-personal`, so [`uv`](https://docs.astral.sh/uv/) must be installed and on your `PATH` — Claude Desktop does not bundle it (see [Prerequisites](#prerequisites)). Codex and other stdio hosts use the config above instead of the `.mcpb`.
---
## Configuration (Environment Variables)
| Variable | Required | Default | Description |
|---|---|---|---|
| `OUTLOOK_MCP_CLIENT_ID` | **Yes** | — | Azure app's Application (client) ID |
| `OUTLOOK_MCP_AUTHORITY` | No | `https://login.microsoftonline.com/consumers` | MSAL authority URL (change only if you move to a work/school tenant) |
| `OUTLOOK_MCP_TOKEN_CACHE` | No | `~/.config/outlook-personal-mcp/token_cache.bin` | Path to the MSAL token cache file |
| `OUTLOOK_MCP_FILE_ROOT` | No | `~/.local/share/outlook-personal-mcp/files` | Only files under this directory can be read by `add_attachment` or written by `download_attachment` |
| `OUTLOOK_MCP_MAX_FILE_BYTES` | No | `3145728` | Maximum bytes allowed for local attachment reads and attachment downloads |
| `OUTLOOK_MCP_ALLOW_PERMANENT_DELETE` | No | `false` | Set to `true` to enable the `permanent_delete` tool (irreversible — see below) |
| `OUTLOOK_MCP_DEBUG` | No | `false` | Set to `true` to log each Graph request's method, URL, and HTTP status code to stderr. Never logs tokens or message content. |
---
## Tools
### Account
| Tool | Description |
|---|---|
| `whoami` | Return the signed-in user's Microsoft account profile |
### Mail
| Tool | Description |
|---|---|
| `list_messages` | List messages (newest first); optionally filter by folder or unread-only |
| `search_messages` | Full-text search across the entire mailbox (Graph `$search`) |
| `get_message` | Get a single message; optionally include the full body |
| `list_attachments` | List a message's attachments (id, name, size, content type) |
| `download_attachment` | Download an attachment to a path under `OUTLOOK_MCP_FILE_ROOT` (refuses to overwrite an existing file) |
| `send_mail` | Send an email |
| `reply` | Reply to a message (`reply_all` to reply to everyone) |
| `forward` | Forward a message to recipients with an optional comment |
| `move_message` | Move a message to another folder |
| `copy_message` | Copy a message to another folder |
| `mark_read` | Mark a message read or unread |
| `flag_message` | Flag or unflag a message |
| `delete_message` | Delete a message (moves it to Deleted Items; reversible) |
| `permanent_delete` | **Permanently** delete a message (irreversible). Only available when `OUTLOOK_MCP_ALLOW_PERMANENT_DELETE=true` |
### Folders
| Tool | Description |
|---|---|
| `list_folders` | List mail folders with unread and total message counts |
| `create_folder` | Create a mail folder, optionally nested under a parent |
| `rename_folder` | Rename a mail folder |
| `delete_folder` | Delete a mail folder (moves it to Deleted Items) |
### Drafts
| Tool | Description |
|---|---|
| `create_draft` | Create a draft message (not sent) |
| `update_draft` | Update a draft's subject and/or body |
| `add_attachment` | Attach a local file (a regular, non-symlink file under `OUTLOOK_MCP_FILE_ROOT`) to a draft |
| `send_draft` | Send an existing draft |
### Calendar
| Tool | Description |
|---|---|
| `list_calendars` | List the user's calendars |
| `list_events` | List events; if `start`/`end` (ISO 8601) are given, returns that time window |
| `search_events` | Search events by free text |
| `get_event` | Get one event including body, attendees, and online meeting link |
| `create_event` | Create a calendar event with optional attendees and online meeting |
| `update_event` | Update fields on an existing event (only provided fields change) |
| `delete_event` | Delete/cancel a calendar event |
| `respond_event` | Respond to a meeting invite: `accept`, `decline`, or `tentative` |
| `find_availability` | Get free/busy availability for a list of people over a time window |
---
## Permanent Delete
The `permanent_delete` tool bypasses the Deleted Items folder and removes a message irreversibly. It is **disabled by default** — when `OUTLOOK_MCP_ALLOW_PERMANENT_DELETE` is not set (or is `false`), the tool is not registered with the MCP server at all and will not appear in the tool list.
To enable it, set `OUTLOOK_MCP_ALLOW_PERMANENT_DELETE=true` in the server's environment block in your `.mcp.json` / `config.toml`. Only do this if you understand the consequences: there is no undo and no Recoverable Items path for personal accounts.
---
## Security
- **Token cache is a credential.** The file at `~/.config/outlook-personal-mcp/token_cache.bin` contains a long-lived refresh token. It is written with mode `600`, but treat it like a password — never commit it, never share it, and store it on an encrypted volume.
- **Data stays local.** The server runs as a child process of Claude Code / Codex over stdio. Your mailbox content is passed directly between the MCP host and the Microsoft Graph API; no third-party relay is involved.
- **Revocation.** To revoke access, delete the token cache file and/or navigate to [https://account.microsoft.com/permissions](https://account.microsoft.com/permissions) to remove the Azure app's consent. You can also delete the Azure app registration entirely from the portal.
- **File paths.** `download_attachment` writes only under `OUTLOOK_MCP_FILE_ROOT` and refuses to overwrite existing files. `add_attachment` reads only regular, non-symlink files under `OUTLOOK_MCP_FILE_ROOT`. Relative paths are resolved under that root; absolute paths outside it (and any path traversing a symlink) are rejected. Both tools enforce `OUTLOOK_MCP_MAX_FILE_BYTES`. Review these paths before confirming any tool call that touches the filesystem.
---
## Development
```bash
git clone https://github.com/salahawad/outlook-personal-mcp
cd outlook-personal-mcp
uv venv && uv pip install -e ".[dev]"
uv run pytest
uv run ruff check .
```
---
## Privacy Policy
This server runs entirely on your machine and sends data only between your machine and Microsoft's Graph API — no third-party relay, no telemetry, and the maintainer receives nothing. OAuth tokens are cached locally at `~/.config/outlook-personal-mcp/token_cache.bin` (mode 600). See [PRIVACY.md](PRIVACY.md) for the full privacy policy.
---
## License
MIT — see [LICENSE](LICENSE).
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available