Skip to main content
Glama

ms-graph-mcp

CI Python License: MIT MCP

A Model Context Protocol server for Microsoft Graph — 60 tools across calendar, email, meetings (including transcripts), Teams chat, files, people, directory, tasks and OneNote, over stdio or Streamable HTTP.

  • No msgraph-sdk, no azure-identity — the Graph client is raw httpx, so the dependency tree stays small and the wire behaviour is inspectable.

  • Auth-agnostic by default — tools receive an already-acquired Graph token via the request context. The server can also perform its own on-behalf-of exchange when you want it to act as a proper OAuth resource server.

  • Read/write separation is enforced, not advisory — write tools are hidden and refused unless the caller explicitly opts in.

Status: early. Extracted from a production agent platform where it has been running against a real tenant. The code is battle-tested; the packaging, docs, and public API surface are new. Expect the config surface to move before 1.0.

Install

Not yet on PyPI. The package name is unclaimed and the release pipeline is in place, but nothing has been published. Until the first release, install from source. The uvx --from ms-graph-mcp commands below are what will work after publication; substitute --from git+https://github.com/nitin27may/ms-graph-mcp today.

# From source (works now)
git clone https://github.com/nitin27may/ms-graph-mcp
cd ms-graph-mcp
uv sync

# After the first PyPI release
uv add ms-graph-mcp
# or
pip install ms-graph-mcp

Related MCP server: ms-teams-mcp

Run

stdio — Claude Desktop, Claude Code, any local MCP client

GRAPH_MCP_ACCESS_TOKEN=<a delegated Microsoft Graph token> \
  uvx --from ms-graph-mcp ms-graph-mcp
// claude_desktop_config.json
{
  "mcpServers": {
    "ms-graph": {
      "command": "uvx",
      "args": ["--from", "ms-graph-mcp", "ms-graph-mcp"],
      "env": {
        "GRAPH_MCP_ACCESS_TOKEN": "<delegated graph token>",
        "GRAPH_MCP_USER_EMAIL": "you@yourtenant.com"
      }
    }
  }
}

stdio env var

Purpose

GRAPH_MCP_ACCESS_TOKEN

The delegated Graph token every tool call uses.

GRAPH_MCP_USER_EMAIL

Caller identity, used for tenant-scoping in some tools.

GRAPH_MCP_WRITE_SCOPE

true to expose the 8 write tools. Default off.

Streamable HTTP

GRAPH_MCP_PORT=8094 uvx --from ms-graph-mcp ms-graph-mcp-http
curl -s localhost:8094/health

Per-request headers:

Header

Purpose

Authorization: Bearer <token>

Required. Either a Microsoft Graph access token (validated as a real Entra JWT), or the configured shared secret for a machine caller.

X-Write-Scope: true

Expose and permit the write tools for this request.

X-Entra-App-Token: <token>

Optional app-only token for directory/group lookups that delegated permissions can't cover tenant-wide.

X-Internal-Scope: true

Expose the internal deterministic tier. Honoured only for the shared-secret machine principal — never for a user token.

X-OBO-Token: <token>

Internal tier only: an explicitly supplied downstream token.

Embed in your own app

from ms_graph_mcp.app import build_app
from ms_graph_mcp.config import GraphMcpConfig

app = build_app(GraphMcpConfig(shared_secret="…"))  # a Starlette app — mount or serve it

build_app(cfg, *, setup_telemetry=None, instrument_starlette=None) takes optional OpenTelemetry hooks. The domain modules also work as plain async functions, without MCP:

from ms_graph_mcp import calendar

events = await calendar.calendar_list_upcoming_events(params, {"access_token": tok})

Configuration

All settings are read from the environment (a .env in the working directory is picked up). GRAPH_MCP_* is canonical; the three app-registration fields also accept the conventional AZURE_AD_* names.

Setting

Env

Default

TLS verification off (corporate proxy)

GRAPH_MCP_DISABLE_SSL_VERIFY

false

Recipient-domain allowlist for send/propose email

GRAPH_MCP_SEND_EMAIL_ALLOWED_DOMAINS

"" (no gate)

Max files per browse

GRAPH_MCP_BROWSE_MAX_FILES

500

Remove the write tier entirely

GRAPH_MCP_READ_ONLY

false

Shared secret for machine callers

GRAPH_MCP_SHARED_SECRET

"" (no gate)

Tenant id

GRAPH_MCP_TENANT_ID / AZURE_AD_TENANT_ID

""

Client id

GRAPH_MCP_CLIENT_ID / AZURE_AD_CLIENT_ID

""

Client secret

GRAPH_MCP_CLIENT_SECRET / AZURE_AD_CLIENT_SECRET

""

Verify JWT signatures (JWKS)

GRAPH_MCP_JWT_VERIFY

true

Server performs its own OBO exchange

GRAPH_MCP_DOES_OBO

false

Audience to validate in OBO mode

GRAPH_MCP_AUDIENCE

derived from client id

Graph scopes requested during OBO

GRAPH_MCP_OBO_SCOPES

https://graph.microsoft.com/.default

HTTP port

GRAPH_MCP_PORT

8094

GRAPH_MCP_JWT_VERIFY defaults on. Turn it off only for a local run with no JWKS connectivity — with it off, token signatures are not verified. There is deliberately no setting that skips authentication altogether; see ADR 0003.

Tool surface

Three tiers, one auth seam.

Tier

Count

Exposed when

Examples

Read

43

always

calendar_list_upcoming_events, mail_search, meetings_get_transcript, files_search, directory_list_user_groups

Write

8

X-Write-Scope: true

mail_send, files_upload, files_create_sharing_link, notes_create_page, tasks_create_todo

Internal

9

X-Internal-Scope: true, machine principal only

graph_request passthrough, drive walk/upload, message attachments, app-only probe_graph_access

Tool names are namespaced by Graph permission family rather than by Microsoft product, because real questions cross product boundaries — files_ covers OneDrive and SharePoint document libraries, which are the same driveItem resource underneath.

By namespace: files 10 · directory 7 · mail 7 · meetings 7 · tasks 6 · calendar 4 · chat 4 · people 3 · notes 3.

Every tool declares MCP annotations (readOnlyHint, destructiveHint, idempotentHint) so clients know what needs confirming, and every description names the delegated permission it requires.

Renamed in 0.2.0. Every pre-0.2.0 tool name still works as an alias and will keep working until 0.3.0. Aliases are accepted by tools/call but are not advertised in tools/list.

The lists live in ms_graph_mcp.allowlists and are resolved against the tool registry on every tools/list. A name in an allowlist with no registered tool raises rather than being skipped — the server refuses to serve a partial surface instead of silently dropping a tool.

Documentation

CONTRIBUTING.md

Dev setup, the add-a-tool checklist, and the invariants that are enforced by tests

SECURITY.md

Reporting vulnerabilities, and the settings to change before exposing this beyond localhost

CHANGELOG.md

Release history

CLAUDE.md

Architecture and the non-obvious traps, for coding agents and new contributors alike

docs/graph-coverage.md

What this server covers of the Graph v1.0 surface, what it does not, and what is out of scope

docs/adr/

Architecture Decision Records

Development

uv sync
uv run pytest -q            # full suite
uv run ruff check .
uv run ruff format .

See CONTRIBUTING.md before opening a pull request — the tool allowlists and the tier separation have invariants that are enforced rather than advisory.

Roadmap

Tracked in more detail in the issues. The near-term programme:

  • MCP SDK 2.x — done. Speaks the 2026-07-28 protocol revision while still serving 2025-era clients. Note that 2.x moves the SDK's HTTP stack to httpx2, a distribution separate from the httpx this server's Graph client uses; consolidating the two is tracked separately.

  • OAuth resource server — RFC 9728 Protected Resource Metadata, WWW-Authenticate challenges, and RFC 8707 audience binding, so any spec-compliant MCP client can authenticate without client-specific configuration.

  • Toolset profiles — expose a subset of the 55 tools per client, to cut the tool-definition tokens an agent pays before it does any work.

  • Graph coverage — SharePoint sites and lists, unified /search/query, calendar write, and 1:1 chats are the notable gaps.

  • Full documentation: app-registration setup, the delegated-permission matrix per tool, and end-to-end configuration for VS Code, Claude Code, Claude Desktop and MCP Inspector.

  • Sovereign cloud support (GCC High / 21Vianet) — a few Graph and login endpoints are still hardcoded to the commercial cloud.

  • Publish to PyPI, and a container image on GHCR.

Contributing

Issues and pull requests are welcome. Start with CONTRIBUTING.md; participation is governed by the Code of Conduct.

License

MIT — see LICENSE.

Install Server
A
license - permissive license
A
quality
B
maintenance

Maintenance

Maintainers
<1hResponse time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    C
    maintenance
    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.
    Last updated
    92
    MIT
  • F
    license
    -
    quality
    C
    maintenance
    Remote MCP server for Microsoft Graph with delegated OAuth support, enabling interaction with Microsoft 365 services like mail, calendar, OneDrive, SharePoint, Teams, and more via natural language.
    Last updated
  • A
    license
    A
    quality
    C
    maintenance
    A local stdio MCP server that enables reading, sending, and searching emails, as well as listing calendar events via Microsoft Graph API, using device-code authentication.
    Last updated
    10
    113
    MIT

View all related MCP servers

Related MCP Connectors

  • Markdown-first MCP server for Notion API with 8 composite tools and 39 actions.

  • Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.

  • Streamable HTTP MCP server for Google Calendar and Sheets with OAuth login.

View all MCP Connectors

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/nitin27may/ms-graph-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server