Outlook MCP Server
README.md
# Outlook MCP Server
A Model Context Protocol (MCP) server that gives AI assistants (Claude, Cursor, etc.) full access to your Microsoft Outlook — emails, calendar, and contacts — via the Microsoft Graph API.
## Features
| Category | Operations |
|---|---|
| **Email** | List, read, search, send, reply, reply-all, forward, create draft, send draft, delete, move, mark read/unread, flag |
| **Mail Folders** | List folders, create folder |
| **Calendar** | List calendars, list events (with date range), get event, search, create, update, delete, accept/decline/tentative |
| **Contacts** | List, get, search, create, update, delete, list folders |
| **Auth** | Device code flow with persistent token cache, sign out |
---
## Prerequisites
- Node.js 18+ (tested with v22)
- A Microsoft 365 or Outlook account
- An Azure AD (Entra ID) app registration (free, takes ~5 minutes)
---
## Step 1: Register an Azure AD Application
1. Go to the [Azure Portal](https://portal.azure.com) → **Microsoft Entra ID** → **App registrations** → **New registration**
2. Fill in:
- **Name**: `Outlook MCP` (or any name)
- **Supported account types**: Choose based on your setup:
- *Personal Microsoft accounts only* → for @outlook.com / @hotmail.com
- *Accounts in any organizational directory and personal accounts* → for work + personal
- **Redirect URI**: Leave blank (we use device code flow)
3. Click **Register**. Copy the **Application (client) ID** — this is your `OUTLOOK_CLIENT_ID`.
4. Copy the **Directory (tenant) ID** if you're using a work/school account — this is your `OUTLOOK_TENANT_ID`. For personal accounts use `consumers`.
5. Go to **API permissions** → **Add a permission** → **Microsoft Graph** → **Delegated permissions**. Add:
- `Mail.ReadWrite`
- `Mail.Send`
- `Calendars.ReadWrite`
- `Contacts.ReadWrite`
- `MailboxSettings.ReadWrite`
- `User.Read`
- `offline_access`
6. Click **Grant admin consent** (if you're an admin) or ask your admin to do so.
7. Go to **Authentication** → Enable **Allow public client flows** → Yes → Save.
---
## Step 2: Build the Server
```bash
cd outlook-mcp
npm install
npm run build
```
---
## Step 3: Configure in Cursor (or Claude Desktop)
### Cursor
Add to your Cursor MCP config (`~/.cursor/mcp.json` or via Settings → MCP):
```json
{
"mcpServers": {
"outlook": {
"command": "node",
"args": ["/absolute/path/to/outlook-mcp/dist/index.js"],
"env": {
"OUTLOOK_CLIENT_ID": "YOUR_CLIENT_ID_HERE",
"OUTLOOK_TENANT_ID": "common"
}
}
}
}
```
> Use `"common"` for multi-tenant, `"consumers"` for personal accounts (@outlook.com / @hotmail.com), or your specific tenant ID for work/school accounts.
### Claude Desktop
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"outlook": {
"command": "node",
"args": ["/absolute/path/to/outlook-mcp/dist/index.js"],
"env": {
"OUTLOOK_CLIENT_ID": "YOUR_CLIENT_ID_HERE",
"OUTLOOK_TENANT_ID": "common"
}
}
}
}
```
---
## Step 4: First-Time Authentication
The first time a tool is called, the server uses **Device Code Flow**:
1. A message will appear in the MCP client (or stderr) like:
```
To sign in, use a web browser to open the page https://microsoft.com/devicelogin
and enter the code ABCD1234 to authenticate.
```
2. Open that URL in your browser, enter the code, and sign in with your Microsoft account.
3. The token is cached at `~/.outlook-mcp-token-cache.json` (permissions 600) and refreshed automatically.
4. You won't need to authenticate again until the refresh token expires (~90 days of inactivity).
---
## Available Tools
### Auth
| Tool | Description |
|---|---|
| `outlook_get_profile` | Get your account name, email, and mailbox settings |
| `outlook_sign_out` | Clear cached tokens |
### Email
| Tool | Key Parameters |
|---|---|
| `email_list` | `folder`, `top`, `skip`, `filter`, `orderBy` |
| `email_get` | `messageId` |
| `email_search` | `query` (KQL), `top` |
| `email_send` | `to[]`, `subject`, `body`, `cc[]`, `bcc[]`, `importance` |
| `email_reply` | `messageId`, `comment`, `replyAll` |
| `email_forward` | `messageId`, `to[]`, `comment` |
| `email_create_draft` | `to[]`, `subject`, `body`, `cc[]`, `bcc[]` |
| `email_send_draft` | `messageId` |
| `email_delete` | `messageId` |
| `email_move` | `messageId`, `destinationFolderId` |
| `email_mark_read` | `messageId`, `isRead` |
| `email_flag` | `messageId`, `flagStatus` (flagged/complete/notFlagged) |
| `email_list_folders` | — |
| `email_create_folder` | `displayName`, `parentFolderId` |
### Calendar
| Tool | Key Parameters |
|---|---|
| `calendar_list_calendars` | — |
| `calendar_list_events` | `calendarId`, `startDateTime`, `endDateTime`, `top` |
| `calendar_get_event` | `eventId` |
| `calendar_search_events` | `query`, `top` |
| `calendar_create_event` | `subject`, `startDateTime`, `endDateTime`, `timeZone`, `attendees[]`, `isOnlineMeeting` |
| `calendar_update_event` | `eventId`, + any fields |
| `calendar_delete_event` | `eventId` |
| `calendar_accept_event` | `eventId`, `sendResponse`, `comment` |
| `calendar_decline_event` | `eventId`, `sendResponse`, `comment` |
| `calendar_tentative_event` | `eventId`, `sendResponse`, `comment` |
### Contacts
| Tool | Key Parameters |
|---|---|
| `contacts_list` | `top`, `skip`, `filter`, `orderBy` |
| `contacts_get` | `contactId` |
| `contacts_search` | `query` |
| `contacts_create` | `displayName`, `emailAddresses[]`, `businessPhones[]`, etc. |
| `contacts_update` | `contactId`, + any fields |
| `contacts_delete` | `contactId` |
| `contacts_list_folders` | — |
---
## Development
```bash
# Run directly with tsx (no build step)
OUTLOOK_CLIENT_ID=xxx npm run dev
# Rebuild after changes
npm run build
```
---
## Troubleshooting
**"OUTLOOK_CLIENT_ID environment variable is required"**
→ Make sure you've set the env var in your MCP config.
**"AADSTS50011: The redirect URI ... was not found"**
→ Enable *Allow public client flows* in Azure Portal → App Registration → Authentication.
**"Insufficient privileges"**
→ Add the missing Graph API permissions and re-grant admin consent. Then run `outlook_sign_out` and re-authenticate.
**Token keeps expiring**
→ Make sure `offline_access` is in your API permissions.
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues