personal-outlook-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@personal-outlook-mcpcheck my inbox for unread emails from today"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
personal-outlook-mcp
A Model Context Protocol server that exposes a personal Outlook (consumer Microsoft account) inbox and calendar to MCP clients like Claude Desktop. Talks to Microsoft Graph over HTTPS, uses MSAL device-code flow for OAuth, and stores tokens in the OS keyring.
How it works
Each user runs the server locally on their own machine and connects it to their own personal Microsoft account. There is no hosted version. You bring your own Azure AD app registration — see "Azure setup" below. This is intentional: your tokens never leave your machine, throttling is your own, and the consent screen shows an app you own (not someone else's).
"Personal" here describes the account type, not a no-setup mode. It means a consumer Microsoft account (
@outlook.com,@hotmail.com,@live.com) as opposed to a work/school account. It does not mean a shared/hosted client you can use without configuration — you still complete the one-time Azure app registration below to get anAZURE_CLIENT_ID. Likewise, the device-code flow is just the sign-in style; it still authenticates through your app registration, so it can't be used to skip that step.
Related MCP server: Outlook MCP Server
Quickstart
# 1. Register your own Azure AD app (~5 minutes, see "Azure setup" below).
# Copy the Application (client) ID.
# 2. Clone and build:
git clone https://github.com/jaingxyz/personal-outlook-mcp && cd personal-outlook-mcp
npm ci && npm run build
# 3. Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"personal-outlook": {
"command": "node",
"args": ["/absolute/path/to/personal-outlook-mcp/dist/index.js"],
"env": {
"AZURE_CLIENT_ID": "<YOUR-CLIENT-ID>",
"AZURE_TENANT": "consumers"
}
}
}
}
# 4. From the clone, seed the OS keyring once:
npm run whoami
# Paste the device code in the printed URL, sign in, approve.
# 5. Restart Claude Desktop. Tools appear under personal_email_* and personal_calendar_*.Prerequisites
Node.js 22.22.1+ (tested against Node 22 and 24).
An Azure AD app registration's Application (client) ID — instructions below.
One of the supported keyring backends:
macOS — built-in Keychain. No setup.
Windows — built-in Credential Manager. No setup.
Linux — a Secret Service implementation (e.g.
gnome-keyringorkwallet) running.
Azure setup
You must register your own Azure AD app. This server has no hosted backend — every user is their own publisher. Cost: $0, time: ~5 minutes.
You do NOT need a paid Azure subscription. Sign into https://entra.microsoft.com with your personal Microsoft account and a free "Default Directory" tenant is created for you automatically; registering an app in it costs nothing. Microsoft's generic quickstart says an "active subscription" is required — that does not apply to registering an app with a personal account.
Go to https://entra.microsoft.com (sign in with your personal Microsoft account) → App registrations → "New registration". (
portal.azure.comworks too, but the Entra admin center is smoother for personal accounts.)[REQUIRED] Supported account types: "Accounts in any organizational directory and personal Microsoft accounts". This is load-bearing — the
consumersauthority this server uses only accepts personal Microsoft accounts. Pick the wrong option here and sign-in fails instantly withinvalid_grantand no device code (see Troubleshooting).Leave the redirect URI blank. Click Register.
In the new app: Authentication → "Add a platform" → "Mobile and desktop applications" → add the redirect URI
https://login.microsoftonline.com/common/oauth2/nativeclient.[REQUIRED] Same page, scroll to Advanced settings → set "Allow public client flows" = Yes. Save. Device-code flow is a public-client flow; without this, sign-in fails with
invalid_grant.Copy the Application (client) ID from the Overview page.
The required Graph delegated permissions (Mail.ReadWrite, Mail.Send, offline_access, User.Read) are requested at sign-in. For personal accounts the user consents at the device-code prompt — no admin consent required.
If
portal.azure.com(orentra.microsoft.com) returnsAADSTS5000225: This tenant has been blocked due to inactivity, your MSA's auto-created "Default Directory" tenant has been deactivated and the sign-in dropdown offers only that dead tenant — so you can't register an app there. You need a live tenant instead. Two options:
Microsoft 365 Developer Program — https://developer.microsoft.com/en-us/microsoft-365/dev-program provisions a fresh sandbox tenant. (Eligibility was tightened in 2024, so instant free signup isn't guaranteed for every account.)
A fresh Microsoft account — a brand-new
@outlook.comgets its own unblocked tenant. Register the app there as "any org directory and personal Microsoft accounts," then sign in atwhoamitime with whichever account owns the mailbox you actually want to read (the multi-tenant registration accepts either).
Setup (from source, for development)
If you want to hack on the server rather than just install it, clone and build locally:
git clone https://github.com/jaingxyz/personal-outlook-mcp.git
cd personal-outlook-mcp
cp .env.example .env
# edit .env and paste your AZURE_CLIENT_ID
npm ci # exact versions from package-lock.json
npm run build
npm test # unit + integration tests, no networkAvailable scripts
Script | What it does |
| Compile TypeScript to |
|
|
| Launch the compiled MCP server (only useful via stdio). |
| Auth smoke test; prints |
| Unit tests (Graph mocked, no network). |
| Vitest in watch mode. |
| Coverage report under |
| ESLint over |
| Lint + auto-fix. |
| Prettier write across the repo. |
| Prettier check (CI uses this). |
| Remove |
First run (device-code auth)
npm run whoamiThe script will print to stderr:
To sign in, use a web browser to open https://microsoft.com/devicelogin
and enter the code ABCD-1234 to authenticate.Open the URL, enter the code, sign in with your personal Microsoft account, grant the requested permissions. The script then prints your account info as JSON on stdout. Tokens are persisted to the OS keyring (via @napi-rs/keyring) under service personal-outlook-mcp, account msal-cache — subsequent runs refresh silently.
To sign out and forget the cached token:
node -e "import('./dist/auth.js').then(m => m.signOut())"MCPB bundle (Claude Desktop one-click install)
A pre-packaged MCPB bundle is built from the npm run bundle script. Currently macOS arm64 only — the bundle includes a platform-specific native binary for the OS keyring backend, and we ship one platform at a time. Other OSes should run from a source clone (see Quickstart).
To build and test locally:
npm run bundle
# produces personal-outlook-mcp.mcpb (~5 MB)
# double-click in Finder to install into Claude DesktopThe bundle's manifest declares three user-config fields, prompted at install: Azure client ID, tenant (default consumers), display timezone (default America/Los_Angeles).
Using from a local source clone
Point Claude Desktop at the built script in your clone:
{
"mcpServers": {
"personal-outlook": {
"command": "node",
"args": ["/absolute/path/to/personal-outlook-mcp/dist/index.js"],
"env": {
"AZURE_CLIENT_ID": "YOUR-CLIENT-ID-HERE",
"AZURE_TENANT": "consumers"
}
}
}
}First-run auth from inside Claude Desktop is awkward because the device-code prompt is written to stderr, which Claude Desktop doesn't surface. Run
npm run whoamifrom a terminal once before launching Claude Desktop to seed the keychain — after that, the MCP server picks up the cached token silently.
Tools
Tool | Purpose |
| List mail folders with id, display name, unread/total counts. |
| Newest-first messages in a folder. Supports |
| Free-text or KQL search across the mailbox. Ranked by relevance. |
| Fetch one message with full body (text or html). |
| Mark a message read or unread. |
| Move a message to another folder (id or well-known name). |
| Soft-delete (move to Deleted Items) by default; |
| Send a new email immediately. Saves a copy to Sent Items. |
| Reply to a message by id. |
| Create a draft in Drafts without sending. Returns a draftId. |
| Send a previously created draft by id. |
| List attachments on a message (id, name, contentType, size). |
| Save a file attachment to disk. Defaults to |
| List calendars (primary, holidays, custom group calendars). |
| Events in a date range (calendarView; recurring series expanded into occurrences). |
| Full event details: attendees, body, recurrence pattern. |
| Create an event. If attendees are listed, Graph sends invites. |
| Update subject/time/location/body/attendees. Refuses single occurrences of recurring series. |
| Cancel (sends notice) or hard-delete (no notice). |
| accept / tentativelyAccept / decline an invite. |
Folder names accept Outlook well-known names: inbox, sentitems, drafts, deleteditems, archive, junkemail. Custom folders need their id (get it from personal_email_list_folders).
Calendar event times use Graph's native shape: { "dateTime": "2026-05-20T15:00:00", "timeZone": "America/Los_Angeles" }. The dateTime field is a local datetime with no offset; timeZone is an IANA name. Output times default to America/Los_Angeles; override with the PERSONAL_OUTLOOK_TZ env var.
Troubleshooting
Missing required env var AZURE_CLIENT_ID—.envnot present or not loaded. Checkcat .env.AuthError: invalid_grantthrown immediately, with no device code printed — the app registration is misconfigured, not your sign-in. Theconsumersauthority only accepts personal Microsoft accounts via a public client. Two causes: (1) Supported account types doesn't include personal Microsoft accounts — set it to "any org directory and personal Microsoft accounts" (manifestsignInAudience: AzureADandPersonalMicrosoftAccount); (2) Allow public client flows is not Yes. Both live on the app's Authentication blade — see "Azure setup" steps 2 and 5. Fix and re-runnpm run whoami; you should now get a real device code.AADSTS5000225during sign-in (or while trying to register the app) — the tenant your app registration lives in has been deactivated for inactivity, and the portal's tenant dropdown offers only that dead tenant. You need a live tenant: either the Microsoft 365 Developer Program sandbox (subject to eligibility) or a fresh@outlook.comaccount (whose new tenant isn't blocked). Register the app as multi-tenant + personal accounts there, then sign in with whichever account owns the mailbox you want. See "Azure setup" for the full note.MCP client says "server crashed" with no useful output — common cause is something writing to stdout, which corrupts the JSON-RPC stream. All non-protocol output must go to stderr.
Re-authentication required: ...at runtime — the cached token can't be refreshed (scopes changed, password changed, refresh expired). Runnpm run whoamifrom a terminal to do device-code flow once; the MCP server picks up the new token automatically on the next tool call.
Architecture
See CLAUDE.md.
License
AGPL-3.0-or-later. See LICENSE for the full text.
This is a copyleft license that closes the SaaS loophole: anyone running a modified version as a network service must release their modifications under the same terms. Suitable for personal projects that want to remain free as in freedom while preventing closed-source forks from being hosted as commercial products.
Acknowledgements
Built with assistance from Claude (Anthropic). The architecture, design decisions, and final code review remain the responsibility of the human author; Claude served as a pair-programming and drafting collaborator.
This server cannot be deployed
Maintenance
Related MCP Connectors
Manage Microsoft 365 email, calendar, contacts and inbox rules via the Graph API with OAuth 2.0.
Permissioned access to Outlook, OneDrive and Teams via the user's own Microsoft account
Hosted email MCP for your own Gmail, Outlook.com, Microsoft 365, iCloud or IMAP inbox: read, search, draft, reply in thread, forward and file mail. It moves or flags up to 500 messages in one call, and a send leaves exactly one copy in Sent. A calendar is a separate connection, and connecting one adds diary and scheduling tools.
Your Gmail, Calendar, Drive, GitHub, Oura, wallet and confirmed profile facts in any MCP client.
Related MCP Servers
- FlicenseAqualityDmaintenanceA lightweight MCP server for personal Microsoft Outlook/Hotmail accounts, enabling email search, reading, attachment management, and folder operations via Microsoft Graph API with OAuth device-code flow.61-
- FlicenseNot gradedqualityCmaintenanceMCP server that uses Microsoft Entra OAuth 2.0 On-Behalf-Of flow to access Microsoft Graph for Outlook data, enabling email, calendar, and contacts interactions via MCP tools.-
- AlicenseBqualityBmaintenanceEnables MCP-compatible clients to connect to Outlook mailboxes via the Microsoft Graph API using app-only authentication.228 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables personal Outlook/Hotmail/Live account email management through Microsoft Graph, letting users list, search, read, and delete emails (with confirmation) via MCP.ISC