Microsoft Graph MCP Server
Microsoft Graph MCP Server
Project
A Model Context Protocol (MCP) server that exposes the full Microsoft Graph API to AI agents such as opencode, Claude, Cursor and any other MCP client — 219 tools across 25 workloads: mail, calendar, files, Teams, SharePoint, Planner, To Do, OneNote, Excel, presence, search, identity governance, security, reports, audit logs and more.
Microsoft Graph is the single REST entry point into Microsoft 365. This server lets an agent authenticate to your tenant once and then operate your real mail, files, calendar, Teams and SharePoint data directly — reading inboxes, drafting and sending mail, creating calendar events and meetings, uploading or sharing files, answering Teams channels, maintaining Planner/To Do tasks, and administering users, groups, security and audit logs.
Self-hosted & by-design full-coverage. Unlike the hosted Microsoft-hosted "MCP Server for Enterprise", this server runs on your machine or container, uses your own credentials (interactive, device-code, client-secret, certificate, on-behalf-of, managed identity), and can write — with a hard read-only guard when you want it safe.
Table of Contents
Why another Microsoft Graph MCP server?
Several Microsoft Graph / Microsoft 365 MCP servers already exist. I have no affiliation with any of them — they are referenced honestly for comparison, exactly as with this project's siblings.
The main players
Official — Microsoft MCP Server for Enterprise — hosted by Microsoft, read-only Entra directory only. It does not expose one tool per Graph operation; instead it uses RAG to generate Queries on the fly (
microsoft_graph_suggest_queries,microsoft_graph_get,microsoft_graph_list_properties). Global cloud only, write support still in preview, no self-hosting.Softeria/ms-365-mcp-server — Node.js, the closest "full coverage" alternative: 300+ tools, 1:1 endpoint mapping, MSAL, read-only mode, tool presets + dynamic discovery. Worth evaluating.
DustHoff/msgraphmcp — Node.js/TypeScript, 140+ tools, four auth modes, notably deep Intune coverage (~64 Intune tools).
nitin27may/ms-graph-mcp — Python, 85 tools, no SDK / no
azure-identity(rawhttpx), namespaced tools, read/write separation behind a write scope.CodyBuilder-dev/ms-graph-mcp — Node.js, device-code auth, mail/calendar/ Teams/To Do/contacts/files/OneDrive/SharePoint, but no directory surface.
timfurlong/msgraph-mcp — Python, on PyPI, mail + calendar + read-only Teams, MSAL device code only, uses the Graph SDK.
What sets this project apart
Capability | Microsoft official | Softeria | DustHoff | nitin27may | CodyBuilder | timfurlong | this project |
Language / runtime | hosted | Node.js | Node.js | Python | Node.js | Python | Python |
Tools | 3 | 300+ | 140+ | 85 | ~50 | ~45 | 219 |
Read-only Entra directory | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
Mail (send/reply/rules/archive) | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Calendar + meetings + rooms | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Files / OneDrive (upload, sharing, revoke) | ❌ | ✅ | ✅ | ✅ | ✅ | partial | ✅ |
SharePoint sites/lists/columns/items | ❌ | ✅ | ✅ | partial | ✅ | ❌ | ✅ |
Teams channels + messages | ❌ | ✅ | ✅ | ✅ | ✅ | read-only | ✅ |
Planner + To Do | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ |
OneNote notebooks/pages | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ |
Excel workbooks/ranges/tables | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
Intune / device management | ❌ | partial | deep | ❌ | ❌ | ❌ | ✅ |
Identity governance (reviews/PIM) | partial | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
Security alerts/incidents + audit logs | ❌ | partial | ❌ | ❌ | ❌ | ❌ | ✅ |
Reports (M365 usage) | ❌ | partial | ❌ | ❌ | ❌ | ❌ | ✅ |
Change notifications / delta | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
Graph | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
No SDK dependency ( | n/a | n/a | ✅ | ✅ | n/a | ❌ | ✅ |
Sovereign clouds (US Gov, China, Germany) | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
Hard read-only guard ( | n/a | ✅ | ❌ | ✅ | partial | ❌ | ✅ |
Coverage drift CI vs official Graph spec | n/a | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
Tool counts and capabilities are approximate, from the respective READMEs at the time of writing — always verify against the source. The point is not that "more is better", but that this project is the deliberate Python, self-hostable, write-capable, zero-SDK option covering the practical day-to-day Microsoft 365 surface an agent actually uses, with CI that keeps it honest against the ever-growing Graph API.
Key differentiators
Full coverage, one auth seam. Authenticate once (six modes) and reach mail, files, calendar, Teams, SharePoint, Planner, To Do, OneNote, Excel, presence, security, audit and admin — instead of stitching together several single-workload servers.
No
msgraph-sdk, noazure-identity. A thin raw-HTTP client (httpx) +msal. A radically smaller dependency tree and an inspectable wire path.Writes are possible but guarded. Write tools call
require_write(); setMSGRAPH_READ_ONLY=trueto forbid every one of them. Nothing mutates your tenant by accident.Coverage drift CI. A scheduled job compares the tool surface against the official Microsoft Graph OpenAPI spec and files an issue when Microsoft ships endpoints we don't cover yet — so the gap is visible instead of silent.
What it provides
A single stdio/HTTP MCP server exposing 219 tools across 25 workloads:
Mail — list/search/get messages, send, reply, forward, drafts, folders, move, rules, attachments, mailbox settings
Files — OneDrive + SharePoint drives: items, upload sessions, versions, permissions, sharing links, revoke
Calendar — events, calendars, free/busy, meeting times, rooms, schedules
Teams — teams, channels, messages, replies, members, tabs
Users & groups — profiles, photos, licenses, memberships, members/owners
Planner & To Do — plans, buckets, tasks, assignments, checklist items
OneNote — notebooks, sections, section groups, pages
Excel — workbooks, worksheets, ranges, tables, sessions
SharePoint — sites, lists, columns, content types, list items
Admin & security — directory, device management, security alerts/incidents, audit logs, reports, identity governance
Meetings & presence — online meetings, transcripts, attendance, recordings, presence
Search & integration — unified Microsoft Search,
$batch, change notifications / delta
—
Getting started
You need an MCP-capable client (opencode, Claude Desktop, Cursor, etc.).
1. Install
Option A — from PyPI (recommended)
uvx msgraph-mcp-full
# or
pip install msgraph-mcp-fullOption B — from GitHub (latest source)
uvx --from "git+https://github.com/oliverhruby/msgraph-mcp.git" msgraph-mcp-full
# or
pip install "git+https://github.com/oliverhruby/msgraph-mcp.git"Option C — development from source
git clone https://github.com/oliverhruby/msgraph-mcp.git
cd msgraph-mcp
uv sync # or: python -m venv .venv && .venv/bin/python -m pip install -e ".[dev]"
uv run msgraph-mcp-fullRun the checks before merging changes:
uv run ruff check src scripts tests
uv run pytest -q # offline unit suite (auth, client, 219-tool sweep)
uv run pytest -m integration -q # live read-only tests; skips without credsOption D — Docker
docker pull ghcr.io/oliverhruby/msgraph-mcp:latest
docker run --rm -i \
-e MSGRAPH_AUTH_MODE=client_secret \
-e MSGRAPH_CLIENT_ID=... -e MSGRAPH_CLIENT_SECRET=... \
-e MSGRAPH_TENANT_ID=... \
ghcr.io/oliverhruby/msgraph-mcp:latest
pyproject.tomlpinsmcp<2(the stable FastMCP v1 API).mcp 2.xrenamedFastMCPtoMCPServerand changed the API surface; this server targets the FastMCP v1 API for simplicity and stability.
2. Register an app in Microsoft Entra ID
App registrations → New registration.
Under Authentication, add a public client / redirect for the auth mode you plan to use (device-code and interactive need no redirect URI).
Grant the API permissions your tools need (delegated and/or application).
DEFAULT_DELEGATED_SCOPESinauth.pylists sensible defaults.Note the Tenant ID, Client ID (and Client Secret / cert if using those modes).
Automated (Azure CLI) — the same registration can be created from your
az identity with one command (Bicep/ARM cannot register Entra apps; they live
in Microsoft Graph, not Azure Resource Manager):
az ad app create --display-name msgraph-mcp-local \
--sign-in-audience AzureADMyOrg \
--public-client-redirect-uris "http://localhost" \
--is-fallback-public-client truescripts/setup_entra_app.ps1 wraps this for the common cases — it reuses an
app if it already exists, prints the Client ID / Tenant ID, optionally
persists MSGRAPH_CLIENT_ID / MSGRAPH_TENANT_ID (setx), dumps the IDs to a
JSON file for other tooling, and can tear the registration back down:
.\scripts\setup_entra_app.ps1 # create + print IDs
.\scripts\setup_entra_app.ps1 -SetEnv # + persist env vars
.\scripts\setup_entra_app.ps1 -OutFile C:\temp\g.json # + write IDs for pipeline
.\scripts\setup_entra_app.ps1 -Delete -AppId <clientId> # remove registrationThe equivalent automation paths are the Microsoft Graph API (e.g. via
az rest --method POST --uri https://graph.microsoft.com/v1.0/applications)
or the Entra (azuread) Terraform provider, if you need full IaC.
3. Authenticate
Configuration is entirely via environment variables.
Interactive (default)
export MSGRAPH_AUTH_MODE=interactive
export MSGRAPH_CLIENT_ID=00000000-0000-0000-0000-000000000000
export MSGRAPH_TENANT_ID=11111111-1111-1111-1111-111111111111
msgraph-mcp-fullA browser opens, you sign in, and a token cache is saved at
~/.msgraph-mcp/token_cache.json for later runs.
Device code
export MSGRAPH_AUTH_MODE=device_code
export MSGRAPH_CLIENT_ID=...
msgraph-mcp-fullClient secret (app-only / daemon)
export MSGRAPH_AUTH_MODE=client_secret
export MSGRAPH_CLIENT_ID=...
export MSGRAPH_CLIENT_SECRET=...
export MSGRAPH_TENANT_ID=...
msgraph-mcp-fullCertificate (app-only)
export MSGRAPH_AUTH_MODE=certificate
export MSGRAPH_CLIENT_ID=...
export MSGRAPH_CERT_PATH=/path/to/cert.pem
export MSGRAPH_TENANT_ID=...
msgraph-mcp-fullOn-behalf-of
export MSGRAPH_AUTH_MODE=obo
export MSGRAPH_CLIENT_ID=... MSGRAPH_CLIENT_SECRET=... MSGRAPH_TENANT_ID=...
msgraph-mcp-fullManaged identity (Azure)
export MSGRAPH_AUTH_MODE=managed_identity # or `managed_identity_user`
export MSGRAPH_CLIENT_ID=... # the managed identity's client id
msgraph-mcp-fullPre-existing token
export MSGRAPH_AUTH_MODE=pre_token
export MSGRAPH_ACCESS_TOKEN=eyJ...
msgraph-mcp-full4. Register with your MCP client
opencode — add to ~/.config/opencode/opencode.json (or opencode.jsonc):
{
"mcp": {
"msgraph": {
"type": "local",
"enabled": true,
"command": ["uvx", "msgraph-mcp-full"],
"env": {
"MSGRAPH_AUTH_MODE": "client_secret",
"MSGRAPH_CLIENT_ID": "{env:MSGRAPH_CLIENT_ID}",
"MSGRAPH_CLIENT_SECRET": "{env:MSGRAPH_CLIENT_SECRET}",
"MSGRAPH_TENANT_ID": "{env:MSGRAPH_TENANT_ID}"
}
}
}
}Put credentials in your shell/environment (or a
.env) and reference them with{env:VAR}, or hardcode them underenv:directly.
Claude Desktop / Cursor — use claude_desktop_config.json / .mcp.json
with a standard mcpServers entry pointing command/args at the venv python
and -m msgraph_mcp, plus an env block.
Over HTTP/SSE (MCP_TRANSPORT=streamable-http):
{
"mcpServers": {
"msgraph": {
"url": "http://127.0.0.1:3000/mcp",
"headers": { "Authorization": "Bearer <MCP_API_KEY>" }
}
}
}After editing client config, restart the client so the MCP server is loaded.
Prompt examples
User prompt | Likely tool call(s) | Expected response |
"Show my last 10 emails" |
| Recent messages (sender, subject, preview). |
"Draft a reply to Oliver accepting the meeting" |
| Draft/sent confirmation (or draft body to review). |
"What's on my calendar this week?" |
| A short event list with times. |
"Create a 1-hour meeting tomorrow at 10:00" |
| Created event with id + link. |
"Upload |
| File metadata + sharing-ready link. |
"List questions asked in the #general channel today" |
| Channel messages with authors. |
"What tasks are due in my To Do this week?" |
| Tasks with due dates and states. |
"Any high-severity security alerts?" |
| Alerts with severity + status. |
"Who signed in from outside the US recently?" |
| Matching sign-in log entries. |
Configuration
Variable | Default | Description |
|
|
|
| (empty) | Entra app (client) ID |
|
| Entra tenant ID |
| (empty) | App secret (client_secret / obo) |
| (empty) | Path to PEM cert (certificate mode) |
| (empty) | Optional cert password |
| (built-in defaults) | Comma-separated extra scopes |
|
|
|
| (from cloud) | Override Graph base URL |
|
|
|
| (empty) | Pre-acquired token (pre_token) |
|
| Seconds a tool call waits for the Graph response; raise for interactive/ |
|
| Token cache location |
|
|
|
|
| Max pages auto-paginated per collection |
|
| Python log level |
|
| Reserved for future per-workload gating |
|
|
|
|
| HTTP bind host |
|
| HTTP bind port |
| (empty) | Bearer token required for HTTP transport |
Tool reference
Tools are grouped by workload (each module under src/msgraph_mcp/tools/).
Workload | # Tools | Examples |
| 19 | list/send/reply/forward messages, folders, drafts, rules, attachments, mailbox settings |
| 19 | OneDrive items, upload sessions, versions, permissions, sharing links, revoke |
| 17 | sites, lists, columns, content types, list items |
| 14 | events, calendars, free/busy, findMeetingTimes, rooms, schedule |
| 13 | teams, channels, messages, replies, members, tabs |
| 12 | profiles, photo, direct reports, licenses, transitive memberships |
| 11 | notebooks, sections, section groups, pages (CRUD + copy) |
| 11 | plans, buckets, tasks, task details, assignments |
| 10 | workbooks, worksheets, ranges, tables, sessions |
| 9 | directory objects, members, roles |
| 9 | CRUD, members, owners, transitive membership |
| 9 | task lists, tasks, checklist items |
| 8 | create meetings, transcripts, attendance, recordings |
| 7 | chats, messages, create chat |
| 7 | contacts, contact folders |
| 7 | managed devices, compliance |
| 6 | alerts, incidents, secure scores |
| 5 | subscriptions (webhooks), delta |
| 5 | access reviews, entitlement mgmt, PIM |
| 5 | relevance search, insights, profile |
| 5 | Microsoft 365 usage reports |
| 4 | sign-ins, directory audits, provisioning |
| 4 | user presence, batch presence |
| 2 | unified Microsoft Search (KQL) |
| 1 | Graph |
Total | 219 |
Each tool is decorated with @graph_tool(...) carrying its HTTP method, Graph
endpoint, and the delegated + application scopes required. Read any tool's
docstring for exact behaviour; write tools call require_write() and fail fast
in read-only mode.
Data & safety notes
Most tools are read-only. The write tools (send/reply, create event, upload/share/revoke file, create task, admin mutations, …) mutate real Microsoft 365 state. Use them with care, or set
MSGRAPH_READ_ONLY=trueto disable the entire write surface.The server acts as your credentials — it can reach only what the authenticated principal can reach. Delegated modes honour your user's permissions; app-only modes use the application's granted permissions.
Sovereign-cloud endpoints differ; set
MSGRAPH_CLOUDaccordingly.MSGRAPH_API_VERSION=betaexposes beta endpoints that may change without notice — preferv1.0unless you know you need a beta API.
Contributing
Contributor and maintainer guidance is in CONTRIBUTING.md.
Contribution workflow and local setup
Architecture and implementation details
Release process (PyPI, GitHub Releases, GHCR)
CI quality gates and upstream coverage drift checks
Limitations
Token lifetime = server lifetime. The auth session lives for the lifetime of the MCP server process; restarting the client means signing in again (the on-disk cache in
~/.msgraph-mcp/helps for interactive/device flows).Beta surface is opt-in. Only
v1.0is covered by the coverage-drift baseline; beta endpoints are registered but not independently monitored.Coverage is broad, not exhaustive. The Graph API has ~18,000 v1.0 operations; this server wraps the practical day-to-day surface (219 tools) and tracks the gap via the coverage-drift canary rather than claiming 100%.
Intune & admin depth. Device management and Intune are covered at a useful level but not as deep as a dedicated Intune server (e.g. DustHoff's).
No Graph Explorer-grade generality. For an arbitrary, not-yet-covered endpoint, prefer the official server, GraphMind-style indexing, or a raw
$batchcall.
Support
If you like this project and want to support or request a feature, send me a beer, it keeps my mind relaxed and ideas will come :-)

License
MIT © Oliver Hrubý
This project is not affiliated with or endorsed by Microsoft or any of the other MCP servers referenced above. Microsoft Graph and Microsoft 365 are trademarks of Microsoft Corporation.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/oliverhruby/msgraph-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server