Outlook Personal MCP
Full-control MCP server for a personal Outlook.com mailbox and calendar (Microsoft Graph).
Open source Open in the app JSON README (API)
About
Full-control MCP server for a personal Outlook.com mailbox and calendar (Microsoft Graph).
Details
- Kind
- MCP servers
- Topic
- Communication
- Publisher
- salahawad
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 0.1.1
- Stars
- 1
- Last push
- 2026-06-28T09:19:19Z
- Repository state
- ativo
- Language
- Python
- License
- MIT
- Added
- 2026-08-29 04:01:21
- Updated
- 2026-08-29 04:01:21
- Origin id
io.github.salahawad/outlook-personal-mcp
README
<!-- 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).