@web4w3/outlook-mcp-server
v1.0.6
Published
MCP server for Outlook.com email read/delete/mark operations via Microsoft Graph API
Maintainers
Readme
Outlook MCP Server
A Model Context Protocol (MCP) server for accessing and managing Outlook.com email accounts through Claude and other MCP clients.
Features
- List emails: Retrieve recent messages from your Outlook inbox
- Read emails: Get full email details including body, attachments info
- Delete emails: Remove emails permanently
- Mark emails: Set emails as read/unread
- Move emails: Transfer emails to other folders
- Attachments: List and download email attachments
- Flags: Set, complete, or clear follow-up flags (with optional due dates)
- Categories: List/create categories and apply them to emails
- Inbox rules: List, create, and delete server-side Inbox rules
Setup
Prerequisites
- Node.js 18+ and npm
- An Outlook.com or Microsoft 365 account
- Microsoft Azure Application Registration
1. Register Azure Application
- Go to Azure Portal
- Navigate to Azure Active Directory > App registrations
- Click New registration
- Fill in the details:
- Name:
Outlook MCP Server - Supported account types:
Accounts in any organizational directory and personal Microsoft accounts
- Name:
- Click Register
2. Create Client Secret
- In your app registration, go to Certificates & secrets
- Click New client secret
- Add a description and select expiration
- Copy the Value (you'll need this as
OUTLOOK_CLIENT_SECRET)
3. Set API Permissions
- In your app registration, go to API permissions
- Click Add a permission > Microsoft Graph
- Select Delegated permissions
- Search and add these permissions:
Mail.ReadMail.ReadWriteMail.SendMailboxSettings.ReadWrite(for categories and Inbox rules; flags work withMail.ReadWritealone)
- Click Grant admin consent (if you're in an organization)
4. Get Your Credentials
From your app registration overview page, copy:
- Application (client) ID →
OUTLOOK_CLIENT_ID - Directory (tenant) ID →
OUTLOOK_TENANT_ID(or use "common")
5. Get Refresh Token (for user login)
You'll need to perform a one-time authorization flow. Use this script:
# Generate auth URL
node scripts/get-auth-token.js
# Or, with no cloning, using the published package:
npx --package=@web4w3/outlook-mcp-server outlook-mcp-server-get-auth-token
# Follow the link to login and copy the authorization code
# Then exchange it for a refresh tokenOr use the Microsoft Graph explorer at https://developer.microsoft.com/en-us/graph/graph-explorer
6. Install
npx -y @web4w3/outlook-mcp-serverNo cloning or build step needed. The package is pre-compiled and available on npm as @web4w3/outlook-mcp-server.
7. Configure in Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"outlook": {
"command": "npx",
"args": ["-y", "@web4w3/outlook-mcp-server"],
"env": {
"OUTLOOK_CLIENT_ID": "your_client_id",
"OUTLOOK_CLIENT_SECRET": "your_client_secret",
"OUTLOOK_TENANT_ID": "common",
"OUTLOOK_REFRESH_TOKEN": "your_refresh_token"
}
}
}
}Remote (HTTP) mode
By default the server speaks MCP over stdio for a client on the same machine. To host it instead (for example on an always-on home server behind a tunnel):
MCP_TRANSPORT=http MCP_HTTP_PORT=3000 MCP_HTTP_TOKEN=<redacted> npm startThe server then listens for Streamable HTTP MCP requests on /mcp and
requires the token as Authorization: Bearer <token> on every request.
The endpoint is stateless; each request is independent. Keep it behind a
private tunnel or a TLS-terminating proxy — do not expose it to the open
internet without one.
Token lifecycle
The server authenticates with a delegated refresh token and manages it
carefully, because Microsoft rotates refresh tokens: most token
responses carry a new refresh token and the old one is eventually
invalidated. Relying on a static token from .env therefore breaks
sooner or later — this is how the server avoids that:
- Seed:
OUTLOOK_REFRESH_TOKENin.envis only the starting point, minted once withscripts/get-auth-token.js. - State file: whenever a token response contains a new refresh
token, it is adopted in memory and persisted atomically (temp file +
rename, permissions
0600) to a JSON state file:{"refreshToken": "…", "updatedAt": "<ISO timestamp>"}. Location: theOUTLOOK_TOKEN_STATE_PATHenvironment variable when set, otherwise<working directory>/data/refresh-token.json. - Precedence: at startup the state file wins over the
.envseed — it holds the freshest token. A missing or corrupt state file falls back to the seed with a warning on stderr; if neither source has a token, startup fails as before. If.envhas no refresh token but a valid state file exists, the server still starts. - Access tokens are cached in memory and reused until 5 minutes before they expire; concurrent refreshes share one request.
- Retries: the token request is retried up to 3 attempts with
backoff (~0.5s, then ~2s) on transient failures only — network
errors, HTTP 429 and HTTP 5xx. OAuth errors such as
invalid_grantare never retried. - Recovery: if the stored refresh token dies (revoked, expired, or
superseded by a rotation whose write was lost), tool calls fail with
an
invalid_granterror saying so. Re-runscripts/get-auth-token.js, put the new token intoOUTLOOK_REFRESH_TOKENin.env, and delete the state file so the fresh seed is used; then restart the server.
Operational notes: keep the state file on durable storage (for a systemd deployment, the service's working directory), and do not copy an old state file over a newer one — the older refresh token in it may already be invalidated.
Available Tools
outlook_list_folders
List all mail folders in your Outlook mailbox.
Parameters: None
Returns: Array of folder objects with id and displayName
outlook_list_emails
List recent emails from your mailbox.
Parameters:
limit(number, 1-100, default: 20): Number of emails to retrievefolder(string, optional): Folder name (default: "inbox")
Returns: Array of email summaries with subject, sender, date, read status, and preview
outlook_get_email
Get full details of a specific email including body, recipients, and attachments info.
Parameters:
id(string, required): Email message IDmarkAsRead(boolean, default: false): Mark email as read when retrieving
Returns: Full email object with complete details
outlook_delete_email
Permanently delete an email.
Parameters:
id(string, required): Email message ID
Returns: Confirmation message
outlook_mark_email
Mark an email as read or unread.
Parameters:
id(string, required): Email message IDisRead(boolean, required): True to mark as read, false for unread
Returns: Confirmation message
outlook_move_email
Move an email to a different folder.
Parameters:
id(string, required): Email message IDdestinationFolder(string, required): Target folder ID or name
Returns: Confirmation message
Note: If destinationFolder is a folder name (not an ID), the server will:
- Look up the folder by name
- If not found, create a new folder with that name
- Move the email to the resolved folder ID
outlook_get_attachments
Get list of attachments for an email.
Parameters:
messageId(string, required): Email message ID
Returns: Array of attachment objects with name, size, and MIME type
outlook_get_attachment_content
Download attachment content (base64 encoded).
Parameters:
messageId(string, required): Email message IDattachmentId(string, required): Attachment ID
Returns: Attachment object with base64 encoded content
outlook_flag_email
Set, complete, or clear the follow-up flag on an email.
Parameters:
id(string, required): Email message IDstatus(string, required):flagged,complete, ornotFlaggeddueDateTime(string, optional): ISO date or datetime, only withflaggedstartDateTime(string, optional): ISO date or datetime, only withflaggedtimeZone(string, optional): Time zone for the dates (defaultUTC)
Returns: Confirmation message
outlook_list_categories
List all categories from the master category list.
Returns: Array of categories with id, displayName, and color
outlook_create_category
Create a new category in the master category list.
Parameters:
displayName(string, required): Category namecolor(string, optional):noneor a presetpreset0–preset24(defaultpreset0)
Returns: The created category
outlook_categorize_email
Change the categories of an email.
Parameters:
id(string, required): Email message IDset(string[], optional): Replace the whole category listadd(string[], optional): Add categories to the current onesremove(string[], optional): Remove categories from the current ones
Returns: The resulting list of categories on the email
outlook_list_rules
List all Inbox rules (server-side rules that act on incoming mail).
Returns: Array of rules with id, displayName, sequence, isEnabled, conditions, and actions
outlook_create_rule
Create an Inbox rule. Rules run on the server and apply to incoming mail whether or not this server is running.
Parameters:
displayName(string, required): Rule nameisEnabled(boolean, optional): Defaulttruesequence(number, optional): Evaluation order, lower runs first- Conditions (all optional; no conditions matches all mail):
fromAddresses(string[]): Sender email addressessenderContains(string[]): Substrings to match in the sendersubjectContains(string[]): Substrings to match in the subjecthasAttachments(boolean)importance(string):low,normal, orhigh
- Actions (at least one required):
moveToFolder(string): Folder ID or display name (resolved likeoutlook_move_email)markAsRead(boolean)markImportance(string):low,normal, orhighassignCategories(string[])delete(boolean)stopProcessingRules(boolean)
Returns: The created rule
outlook_delete_rule
Delete an Inbox rule by its ID (see outlook_list_rules).
Parameters:
ruleId(string, required): Rule ID
Returns: Confirmation message
Integration with Email Analytics Agent
This server is designed to work with the Email Analytics Agent, which provides:
- Intelligent email grouping by sender domain
- Interactive folder assignment
- Rule learning for automatic email organization
Development
Run in development mode with auto-reload:
npm run devBuild TypeScript:
npm run buildStart the compiled server:
npm startCommon Issues
"Missing required environment variable"
Check that all required .env variables are set correctly.
"Unauthorized" or "Invalid credentials"
- Verify your Client ID, Client Secret, and Refresh Token are correct
- Check that your Azure app registration has the required permissions
- Ensure the refresh token hasn't expired (refresh tokens expire if unused for 90 days)
- If calls fail with
invalid_grant, the stored token died — see Token lifecycle for the recovery steps
"Permission denied"
Make sure the API permissions in your Azure app registration include:
- Mail.Read
- Mail.ReadWrite
- MailboxSettings.ReadWrite (categories and Inbox rules only; if this one is missing, mail tools keep working and only the category/rule tools fail — re-run the refresh-token step after adding the permission so the new token carries it)
License
MIT
