m365-mcp
Click on "Install 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., "@m365-mcpList my unread emails from the last hour"
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.
m365-mcp
A Model Context Protocol server that gives Claude Code (or any MCP client) controlled access to Microsoft 365 through the Microsoft Graph API: mail, calendar, contacts, files, notes, tasks, Teams, SharePoint, and the full tenant-admin surface.
It runs locally as a stdio subprocess. There is no hosted component, no client secret, and no inbound network exposure. Authentication is a local public-client browser flow, and every token stays on your machine.
Status: 441 tools, multi-account (personal and work identities mixed in one server), public-client auth with per-account token caches. License: MIT.
┌──────────────────────────────────────────────────────────────────┐
│ 441 tools total │
│ │
│ 173 available to PERSONAL Microsoft accounts (167 + 6 mgmt) │
│ 441 available to WORK / school accounts (everything) │
│ │
│ Same tool names for both. Work-only tools are blocked, with a │
│ clear error, when called against a personal account. │
└──────────────────────────────────────────────────────────────────┘The capability story has three tiers, and the rest of this document follows that order: what a personal account gets, what a business (work/school) account adds, and what a tenant administrator unlocks on top.
Tier 1: Personal Microsoft accounts
If you sign in with a consumer Microsoft account (@outlook.com, @hotmail.com,
@live.com, @msn.com), you get the complete personal productivity surface:
173 tools (167 Graph tools plus 6 account-management tools). Everything in
this tier works against a personal mailbox with no tenant, no admin, and no
license beyond a normal Microsoft account.
Family | Tools | What it covers |
50 | Read, search (full-text + paginated), draft, reply, reply-all, forward, send, move, copy, flag, categorize, delete, folders, rules, inbox-tip checks, MIME export, Focused-Inbox overrides, attachments (incl. >3 MB upload sessions), auto-reply | |
Calendar | 25 | List/create/update/delete events, respond to invites, calendars + groups, recurring-event expansion, |
Contacts | 15 | Search, CRUD, contact folders, per-contact photos, delta sync |
Microsoft To Do | 14 | Task lists, tasks, checklist steps, linked resources, delta sync |
OneDrive | 24 | Browse, upload, download, copy/move, share links, invitations, permissions, versions, search, recent, thumbnails, Office-Online previews, delta sync |
OneNote | 14 | Notebooks, sections, section groups, pages, HTML content read/write, previews |
Profile + Mailbox settings | 13 | Profile, photo, working hours, time zone, language, supported-locale lists |
Subscriptions / webhooks | 5 | Change-notification subscriptions (needs a public HTTPS callback) |
Refinements | 7 | Master categories, unified search, reference + item attachments |
Account management | 6 |
|
Primary use case
Screen an inbox, draft replies for your approval, triage junk, route newsletters with rules, manage your calendar, and organize OneDrive, all by asking Claude in natural language.
Known personal-account limits
A handful of Graph families are work-only at the platform level and simply do
not exist for consumer accounts (Teams chat, SharePoint sites, org directory,
Planner, admin reports, and so on). The server tags those tools so they fail
fast with a readable message instead of a raw Graph 403. The durable list lives
in PERSONAL_ACCOUNT_LIMITS.md. Notable nuances:
OneNote works on personal accounts but can return transient errors for a minute or two right after first consent. Retry rather than concluding it is unsupported.
Subscriptions require a publicly reachable HTTPS
notificationUrl, so they need an ngrok-style tunnel to be useful from a purely local server. Personal accounts support subscriptions on mail, calendar, drive root, and To Do tasks, but not on contacts.Workbook / Excel API is de-scoped on personal accounts in favor of the separate
excel-mcp-server.
Related MCP server: Outlook Assistant
Tier 2: Business (work / school) accounts
Sign in with a Microsoft Entra (Azure AD) work or school account and you keep all 173 personal tools, then add 157 collaboration tools that only exist inside an organization. These target Teams, SharePoint, Microsoft 365 Groups, Planner, the org directory, shared mailboxes, Bookings, and the Excel Workbook API.
Family | Tools | What it covers |
Teams chat | 17 | List/create chats, send/edit/delete/restore messages, reactions, members, pins, tenant-wide message search |
Teams channels | 16 | Channels (standard/private/shared), messages + threaded replies, reactions, members, files folder |
Teams (teams themselves) | 10 | List/get/update teams, archive/unarchive, clone, members, promote owners |
Online meetings | 9 | Create/update/delete Teams meetings, attendance reports, recordings, transcripts (WebVTT) |
SharePoint sites | 7 | Root site, site search, subsites, modern pages, permission entries |
SharePoint document libraries | 14 | Browse/upload/download/copy/move, share links, invitations, search across libraries |
SharePoint lists + items | 11 | Lists, items, fields, columns (the row-oriented data primitive: trackers, registers, lookups) |
Microsoft 365 Groups | 15 | Groups, members, owners, group mailbox conversations + threads, the backing team |
Planner | 15 | Plans, buckets, tasks, task details, assignments (etag-aware) |
Directory + people | 14 | User search, manager/reports hierarchy, member-of, free/busy, People API, org contacts |
Shared mailboxes | 10 | Read/search/draft/send on a shared mailbox you have delegate access to |
Bookings | 9 | Booking businesses, appointments, services, staff, publish |
Workbook / Excel | 10 | Worksheets, ranges, tables, named ranges, persistent sessions |
What this enables
A work account turns the server into a full collaboration assistant: post to a Teams channel, search every chat you are in, manage a SharePoint document library or list, run a Planner board, look up a colleague's manager or free/busy, or draft from a shared support mailbox.
Delegated, not impersonating. Every action runs as you, with your permissions. Shared-mailbox tools require that you already hold Exchange Online FullAccess or folder rights on that mailbox; the Graph scopes alone do not grant the underlying data access.
Tier 3: Tenant administrators
If your work account holds admin roles, the server exposes 111 additional governance, security, and device-management tools. These read and write tenant-wide configuration, so several are flagged as sensitive and should only be invoked with explicit intent.
Family | Tools | What it covers |
Admin queries | 10 | Service health + incidents, Message Center posts, directory audit log, sign-in logs, provisioning logs |
Reports | 15 | Usage reports across Office 365, email, Teams, OneDrive, SharePoint, Outlook, apps, Yammer (rolling D7/D30/D90/D180 windows) |
Identity governance | 12 | Access reviews + decisions, entitlement-management access packages, Terms of Use, lifecycle workflows |
Conditional Access + roles | 17 | CA policies (create/update/delete ⚠), named locations, auth-strength, authorization policy, directory role assignments, PIM activate |
Directory objects | 20 | Devices, applications, service principals, administrative units, deleted-item recycle bin (restore ⚠ / purge ⚠) |
eDiscovery + sensitivity labels | 13 | eDiscovery cases, custodians (legal hold ⚠), KQL searches, review sets, sensitivity labels |
Security | 9 | Alerts, incidents, Secure Score history + controls, threat indicators |
Intune | 10 | Managed devices (wipe ⚠ / retire ⚠ / sync), configuration + compliance policies, app policies, mobile apps |
Universal Print | 5 | Printers, printer jobs, your jobs, print shares |
⚠ sensitive operations. Tools that change tenant-wide security policy, place data on legal hold, or wipe a device are marked with a warning in
CLAUDE.md. Confirm intent before invoking. Note that Graph exposes device writes only to app-only auth, soupdate_device/delete_devicecannot run through this delegated public-client flow (device read works fine; Intunewipe/retireuse a different, supported path).
The full, per-tool inventory for every tier lives in
CLAUDE.md; architecture and design notes are in
As_Built_Specification.md.
Setup overview
Setup is three moving parts, done once per identity:
Register an Azure app and grant it Graph permissions (this section).
Point the server at the app via
.env.Generate a token with the
add_accounttool (the Authentication section).
You register one app per Microsoft identity:
Path | You have | Apps to register |
A | A personal account only | 1 app in the consumer (Microsoft-account) directory |
B | A work account only | 1 single-tenant app in that work tenant |
C | Both, or several work tenants | 1 app per identity; they coexist in one server |
Microsoft only allows one personal account per person, so the personal app uses
the un-suffixed .env keys. Each work tenant adds its own suffixed pair.
Prerequisites
Node.js 18+ (uses native
fetch).A Microsoft account (personal, or work/school in any Entra tenant).
For work apps: tenant-admin consent, either yours or your admin's.
macOS, Windows, or Linux. The first sign-in opens your default browser briefly.
Account setup and permission changes (Azure portal)
Do this in the Microsoft Entra admin center, entra.microsoft.com. Sign in as the identity you want to connect. For a work account, confirm the tenant shown in the top-right is the correct one before you start.
Step 1: Register the app
Applications → App registrations → + New registration.
Field | Personal-account app | Work-account app |
Name |
|
|
Supported account types | "Personal Microsoft accounts only" | "Accounts in this organizational directory only (single tenant)" |
Redirect URI | Platform = Public client/native (mobile & desktop), URI = | same |
Click Register.
Use single-tenant for work apps. Register a separate app per work tenant rather than one multitenant app, unless you specifically need cross-tenant sign-in.
Step 2: Copy the identifiers
On the app's Overview page, copy:
Field | Goes into | Notes |
Application (client) ID |
| A GUID |
Directory (tenant) ID |
| The tenant GUID for work apps. For personal apps, use the literal string |
Step 3: Add API permissions
API permissions → + Add a permission → Microsoft Graph →
Delegated permissions. These are the 14 base (Tier 1) scopes every
account needs:
Scope | Enables |
| Profile, photo, sign-in discovery |
| All mail tools |
| Auto-reply, working hours, time zone, inbox rules |
| All calendar tools |
| All contact tools |
| Microsoft To Do |
| OneNote |
| OneDrive |
Work and admin accounts add the work-only scope set on top (roughly 90 scopes spanning Teams, SharePoint, Groups, Planner, directory, reports, identity governance, Conditional Access, security, Intune, Print, and Bookings). Rather than transcribe all of them here:
Run the
list_known_scopestool to print the exact base + work-only list theadd_accountflow will request, orRead the authoritative source:
DEFAULT_SCOPESandWORK_ONLY_SCOPESinsrc/auth/multi-account-auth.ts.
Add every scope your tier needs, then click Add permissions.
Step 4: Grant admin consent (work accounts only)
On the API permissions page, click
"Grant admin consent for <tenant>". The admin-only .All scopes
require this. If you are not an admin, send your tenant admin this URL
(substitute your client and tenant IDs):
https://login.microsoftonline.com/<tenant-id>/adminconsent?client_id=<client-id>&redirect_uri=http://localhost:3333/auth/callbackAfter a one-time approval, users in the tenant sign in without per-user consent
prompts on the .All scopes. Personal accounts skip this step; you consent
in-browser during add_account.
Step 5: Confirm authentication settings
Authentication:
Platform configurations = "Mobile and desktop applications" with redirect URI
http://localhost:3333/auth/callback.Advanced settings → Allow public client flows = Yes. If it is No, switch it and Save.
There is no client secret. This is a public-client / loopback-redirect app by design; adding a secret is unnecessary and unsupported by the flow.
Install and configure
git clone https://github.com/Corvalon/mcp-m365.git
cd mcp-m365
npm install
cp .env.example .env
npm run buildEdit .env. The server auto-loads it from the repo root on startup. Always
single-quote every value (Node's env parser treats an unquoted # as a
mid-line comment and will silently truncate a value).
# --- Personal account (Path A) ---
AZURE_CLIENT_ID='<personal-app-client-id>'
AZURE_TENANT_ID='consumers'
# --- Work account(s) (Path B/C), one suffixed pair per tenant ---
# The suffix is a short name you choose; it must match the `tenant`
# argument you pass to add_account.
AZURE_CLIENT_ID_CONTOSO='<contoso-app-client-id>'
AZURE_TENANT_ID_CONTOSO='<contoso-tenant-guid>'A personal pair and any number of work pairs can all live in the same .env.
Wire into Claude Code
Add the server to your MCP config (~/.claude.json, or via the Claude Code IDE
settings):
{
"mcpServers": {
"m365": {
"command": "node",
"args": ["/absolute/path/to/mcp-m365/dist/index.js"]
}
}
}Restart Claude Code. The server logs a startup line confirming
441 tools registered, and the tools become available as mcp__m365__*. The
.env is read from the repo root automatically, so no extra env wiring is
needed.
Authentication / token generation
Tokens are generated at runtime through the MCP tools, not by a separate
script. The first time you connect an identity you run add_account, which
opens a browser for OAuth consent and caches the result locally.
Generate your first token
Ask Claude to run add_account, or call it directly:
Personal account:
// mcp__m365__add_account
{ "alias": "personal", "accountType": "personal" }Work account (the tenant value must match your .env suffix, lowercase):
// mcp__m365__add_account
{ "alias": "contoso", "accountType": "work", "tenant": "contoso" }What happens:
The tool reads the matching client/tenant IDs from
.envand builds the consent URL (base scopes for personal, base + work-only for work).Your default browser opens. Sign in and approve. The call blocks for up to 2 minutes waiting for you to finish.
A local listener on
http://localhost:3333/auth/callbackcatches the redirect and exchanges the code for tokens.An audience guard verifies you signed in with the expected identity. If you accidentally pick the wrong account in the browser, the account is rejected and not persisted; just re-run
add_account.The access + refresh tokens are written to a per-alias cache under
.token-cache/, and the account metadata toaccounts.json. The first account you add becomes the default.
After this, MSAL refreshes tokens silently. You only return to the browser when
a refresh fails or you widen scopes. On failure the server raises a structured
REAUTH_REQUIRED <alias> error naming exactly which account to re-add.
Routing calls to an account
Every Graph tool accepts an optional account alias. Omit it to use the
default.
{ "account": "contoso", "top": 10 } // read_inbox against the work account
{ "top": 10 } // read_inbox against the default accountManage accounts
Tool | Purpose |
| Show every registered account and which is default |
| Full record for one alias (client/tenant/authority, scopes, timestamps) |
| Choose the alias used when a call omits |
| Remove an account and delete its token cache |
| Preview the scopes |
Re-authenticate or widen scopes
Re-auth one account:
remove_account <alias>thenadd_accountagain.Widen scopes: add the broader scope in the Azure portal, then re-run
add_accountwith the same alias and a widerscopesarray (MSAL merges the consent).Fully revoke:
remove_accountdeletes the local cache but does not revoke the Microsoft-side grant. To revoke server-side, remove the app at account.microsoft.com/consent/manage (personal) or via the tenant admin (work).
Security model
No client secret. Public-client, loopback-redirect, delegated auth only.
Local-only tokens.
.env,accounts.json, and.token-cache/are all gitignored and never leave your machine.Delegated permissions. Every action runs as the signed-in user with that user's rights. The server cannot exceed what the account can already do.
Tier enforcement. Work-only tools carry a
compatibility="work"flag and are rejected before the handler runs when targeted at a personal account (and vice versa), for both explicit-alias and default-account calls.Redaction.
homeAccountIdis truncated to its first 8 characters in surfaces an operator might log (list_accounts,get_account_info).
Troubleshooting
Symptom | Likely cause | Fix |
| App audience wrong, or | Use the tenant GUID for work; |
| Missing admin consent for a | Grant admin consent on the API permissions page, or send the admin-consent URL |
| You picked the wrong identity in the browser popup | Re-run |
Browser opens but the callback hangs | Something else is on port 3333 | Free the port ( |
| Refresh token expired or scopes changed | Run |
| Called against a personal account | Those are work-only; see |
OneNote returns | Known OneNote warm-up flakiness | Retry; it is not a real failure |
Development
npm run build # tsc -> dist/
npm run dev # tsx src/index.ts (no build step)
npm test # Vitest unit suite
npm run test:coverage # with coverageTools are grouped into per-family src/tools/*.register.ts modules and wired up
in src/index.ts. Auth lives in src/auth/ (multi-account-auth.ts holds the
scope catalog and MSAL layer; graph-client.ts loads .env and exposes the
default client). All Graph calls funnel through one account-aware choke point,
so tools stay account-agnostic.
Reference docs
File | Purpose |
Full per-tool inventory + project conventions | |
Architecture, modules, auth model, scope catalog | |
Operational procedures (re-auth, build, scope changes) | |
Graph families that do not work on personal accounts |
License
MIT. See LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Corvalon/mcp-m365'
If you have feedback or need assistance with the MCP directory API, please join our Discord server