Skip to main content

ms-graph-mcp

CI Python License: MIT MCP

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

Signs you in with your own Microsoft account — browser SSO, no token to paste, no client secret.

  • 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 on PyPI yet. pip install ms-graph-mcp and uvx --from ms-graph-mcp will not work until the first release. Run it from a clone — the Quick start below covers it, and every client config in this README uses that path.

Requires Python 3.12+ and uv.

Trying a pre-release

Release candidates are tagged in this repository, so you can run one directly without waiting for a PyPI release and without a TestPyPI account:

uvx --from git+https://github.com/nitin27may/ms-graph-mcp@v0.2.0-rc1 ms-graph-mcp
pip install git+https://github.com/nitin27may/ms-graph-mcp@v0.2.0-rc1

Once the first stable version is on PyPI, candidates are published there too and the usual pre-release flags work:

pip install --pre ms-graph-mcp        # newest, including candidates
pip install ms-graph-mcp==0.2.0rc1    # a specific one; no --pre needed for an exact pin

A candidate never reaches anyone who did not ask for one — pip skips pre-releases unless you pass --pre or pin the version exactly.

TestPyPI is not the place to get these. Every release is published there first, but that is a rehearsal of the publishing process, not a distribution channel: it can be wiped without notice, and it does not mirror PyPI, so installing from it needs --extra-index-url https://pypi.org/simple/ just to resolve ordinary dependencies. Use a git tag, or --pre.

Quick start

You need an Entra ID app registration — about two minutes. Do not create a client secret: this registers as a public client, which signs you in through your browser using PKCE. A secret on a program running on your own machine would be readable by anyone with the config file, which is why the flow is designed not to need one. Nothing is pasted into a config file except two ids, neither of which is sensitive.

1. Register the app

In the Entra portalApp registrationsNew registration:

  • Name: anything, e.g. ms-graph-mcp
  • Supported account types: Accounts in this organizational directory only
  • Redirect URI: select Public client/native, value http://localhost

Leave Certificates & secrets alone — you do not need anything from it.

Then, on the new app:

  • Authentication → enable Allow public client flows (this permits device-code sign-in)

  • API permissionsAdd a permissionMicrosoft GraphDelegated permissions, and add what you want the agent to reach. A sensible read-only starting set:

    User.Read  Mail.Read  Calendars.Read  Files.Read.All
    People.Read  Chat.Read  Tasks.Read  Notes.Read  Contacts.Read
    

    The complete, copy-paste consent set — and which permission each individual tool needs — is in docs/permissions.md.

Copy the Application (client) ID and Directory (tenant) ID from the Overview page.

2. Get the code and run it

The package is not on PyPI yet, so run it from a clone. Everything below assumes ~/workspace/ms-graph-mcp — substitute your own path.

git clone https://github.com/nitin27may/ms-graph-mcp ~/workspace/ms-graph-mcp
cd ~/workspace/ms-graph-mcp
uv sync                       # creates .venv and installs everything

That gives you:

~/workspace/ms-graph-mcp/
├── pyproject.toml            # defines the ms-graph-mcp console script
├── uv.lock
├── src/ms_graph_mcp/         # the server
├── tests/
├── docs/
└── .venv/                    # created by uv sync

Check it starts:

GRAPH_MCP_CLIENT_ID=<application-client-id> \
GRAPH_MCP_TENANT_ID=<directory-tenant-id> \
  uv run ms-graph-mcp

Your browser opens for Microsoft 365 sign-in. The process then sits waiting for a client to speak MCP to it over stdin — that is correct; press Ctrl-C. The sign-in is cached in ~/.ms-graph-mcp/token_cache.json (owner-readable only), so it will not prompt again.

To run it from anywhere — which is what an MCP client needs, since it will not be launched from this directory — use --directory:

uv run --directory ~/workspace/ms-graph-mcp ms-graph-mcp

MCP clients need an absolute path. They do not inherit your shell's working directory, and most do not expand ~. Get yours with:

cd ~/workspace/ms-graph-mcp && pwd
# /Users/you/workspace/ms-graph-mcp

Add it to your client

Every example uses the local clone, because that is what works today. Replace /Users/you/workspace/ms-graph-mcp with your own absolute path — the output of pwd in the clone. After the first PyPI release you can swap the command for uvx (see the end of this section).

VS Code

Create .vscode/mcp.json in whichever workspace you want it available in:

{
  "inputs": [
    { "id": "clientId", "type": "promptString", "description": "Entra application (client) ID" },
    { "id": "tenantId", "type": "promptString", "description": "Entra directory (tenant) ID" }
  ],
  "servers": {
    "ms-graph": {
      "type": "stdio",
      "command": "uv",
      "args": [
        "run",
        "--directory", "/Users/you/workspace/ms-graph-mcp",
        "ms-graph-mcp"
      ],
      "env": {
        "GRAPH_MCP_CLIENT_ID": "${input:clientId}",
        "GRAPH_MCP_TENANT_ID": "${input:tenantId}"
      }
    }
  }
}

Reload the window. VS Code prompts once for the two ids and remembers them, so this file is safe to commit. Open the Chat view, switch to Agent mode, and the tools appear under the tools picker. MCP: List Servers shows status and output if it does not connect.

For every workspace rather than one, run MCP: Open User Configuration and put the same servers block there.

Claude Code

claude mcp add ms-graph \
  --env GRAPH_MCP_CLIENT_ID=<application-client-id> \
  --env GRAPH_MCP_TENANT_ID=<directory-tenant-id> \
  -- uv run --directory /Users/you/workspace/ms-graph-mcp ms-graph-mcp

Then /mcp inside Claude Code to confirm it connected and see the tool list.

Claude Desktop

claude_desktop_config.json — macOS ~/Library/Application Support/Claude/, Windows %APPDATA%\Claude\:

{
  "mcpServers": {
    "ms-graph": {
      "command": "uv",
      "args": [
        "run",
        "--directory", "/Users/you/workspace/ms-graph-mcp",
        "ms-graph-mcp"
      ],
      "env": {
        "GRAPH_MCP_CLIENT_ID": "<application-client-id>",
        "GRAPH_MCP_TENANT_ID": "<directory-tenant-id>"
      }
    }
  }
}

Restart Claude Desktop fully — quit it, do not just close the window.

MCP Inspector

The quickest way to check the server independently of any client:

npx @modelcontextprotocol/inspector \
  uv run --directory /Users/you/workspace/ms-graph-mcp ms-graph-mcp \
  -e GRAPH_MCP_CLIENT_ID=<application-client-id> \
  -e GRAPH_MCP_TENANT_ID=<directory-tenant-id>

Needs Node 22.19+. It opens a browser UI where you can list tools and call them by hand — worth doing before blaming your client.

Pass variables with -e, not from your shell. Inspector does not give the server it spawns your environment, so GRAPH_MCP_CLIENT_ID=… npx @modelcontextprotocol/inspector … starts the server with no client id and it falls back to defaults. The -e flags go after the server command.

There is a scriptable --cli mode too — see docs/testing.md.

Two things that catch people out

uv must be on the client's PATH. GUI apps launched from Finder or the Dock do not inherit your shell's PATH, so a client can fail to start the server with an unhelpful error. If that happens, use the absolute path to uv:

which uv     # e.g. /Users/you/.local/bin/uv

and put that in "command" instead of "uv".

--directory is not optional. Without it, uv run resolves against whatever directory the client happened to launch from, which will not be the project.

After the first PyPI release

Once published, no clone is needed — replace the command and args with:

"command": "uvx",
"args": ["--from", "ms-graph-mcp", "ms-graph-mcp"]

Everything else, including the env block, stays the same.

stdio settings

Env var Purpose
GRAPH_MCP_CLIENT_ID Entra application (client) id. Enables interactive sign-in.
GRAPH_MCP_TENANT_ID Entra directory (tenant) id. Defaults to common.
GRAPH_MCP_SCOPES Comma-separated delegated scopes to request. Defaults to a read-only set.
GRAPH_MCP_TOOLSETS Which tool profiles to expose. Defaults to core. See below.
GRAPH_MCP_WRITE_SCOPE true to expose the 23 write tools. Default off.
GRAPH_MCP_DISABLE_SSL_VERIFY true to skip TLS certificate verification for Graph HTTP calls. Use only as a corporate-proxy workaround; see troubleshooting.
GRAPH_MCP_USER_EMAIL Caller identity, used for tenant-scoping in some tools. Optional.
GRAPH_MCP_ACCESS_TOKEN A pre-acquired delegated token, instead of signing in. For CI.
GRAPH_MCP_FORCE_DEVICE_CODE true to skip the browser and always use device-code sign-in.

Turning on write tools. They are off by default: with them enabled an agent can send mail, book meetings and change files as you. To use them, add the matching write scopes to GRAPH_MCP_SCOPES and set GRAPH_MCP_WRITE_SCOPE=true:

GRAPH_MCP_SCOPES=User.Read,Mail.ReadWrite,Mail.Send,Calendars.ReadWrite,Files.ReadWrite.All,Tasks.ReadWrite,ChatMessage.Send
GRAPH_MCP_WRITE_SCOPE=true

Troubleshooting

Symptom Cause
AADSTS7000218 on sign-in Allow public client flows is not enabled on the app registration.
AADSTS50011 redirect mismatch The redirect URI is not http://localhost, or the platform is not Public client/native.
SCOPE_DENIED from a tool The permission that tool needs was not consented. The error names it — add it in API permissions and sign in again.
Sign-in prompts every time The cache at ~/.ms-graph-mcp/token_cache.json is not writable.
Browser never opens Expected over SSH or in containers — use the device code printed to stderr.
AADSTS53003, or "You cannot access this right now" after a successful sign-in A Conditional Access policy requires a registered or compliant device. See below.
Client shows "server disconnected" Run the same command in a terminal; startup errors go to stderr and the client usually hides them.
421 Misdirected Request from a hosted deployment GRAPH_MCP_RESOURCE_URL is not set, so the transport trusts only localhost. See running hosted.
[SSL: CERTIFICATE_VERIFY_FAILED] when calling Graph tools A TLS-inspecting proxy (Netskope/Zscaler/etc.) is resigning Graph traffic with a certificate chain your Python/OpenSSL runtime does not trust.

SSL certificate verify failures behind corporate proxies

When this server calls Microsoft Graph, httpx validates the TLS chain using the Python/OpenSSL trust store of the process running ms-graph-mcp.

In corporate networks with TLS inspection, Graph certificates are often re-issued by a proxy CA. If that CA chain is not accepted by your runtime, Graph calls fail with errors like:

[SSL: CERTIFICATE_VERIFY_FAILED] self-signed certificate in certificate chain

or

[SSL: CERTIFICATE_VERIFY_FAILED] Basic Constraints of CA cert not marked critical

Use this workaround only when you have confirmed proxy-related TLS interception and cannot quickly repair trust-chain validation:

"GRAPH_MCP_DISABLE_SSL_VERIFY": "true"

Where to set it:

  • VS Code workspace config (.vscode/mcp.json) under the server env block.
  • User-level MCP config for clients that support per-server environment variables.

Security trade-off:

  • This disables certificate validation for Graph HTTP calls from this server process.
  • It reduces protection against machine-in-the-middle attacks and should be treated as a temporary compatibility escape hatch, not a default posture.

Preferred long-term fix:

  1. Install and trust the corporate proxy CA chain in the runtime trust store used by Python/OpenSSL.
  2. Remove GRAPH_MCP_DISABLE_SSL_VERIFY (or set it back to false).
  3. Restart the MCP client/server process and verify Graph calls succeed with TLS verification on.

AADSTS53003 — blocked by Conditional Access

Your credentials were accepted and the sign-in succeeded; a policy then refused the token. Click More details on the error page and look at the device lines:

Error Code:        53003
Device platform:   macOS
Device state:      Unregistered      <- the cause
Device identifier: Not available

Your tenant requires a registered or compliant device, and a plain system browser has no device identity to present. This is why Outlook and Teams still work: they sign in through the Microsoft Enterprise SSO plug-in (shipped with Company Portal / Intune), which holds that identity.

Nothing in the app registration fixes this. Conditional Access is evaluated separately from app configuration — not API permissions, not redirect URIs, not "allow public client flows". Your registration is already fine; the sign-in got past it.

Two real fixes:

  1. Register the device. Install Company Portal and sign in; device state becomes Registered and the policy is satisfied. Your existing configuration then works unchanged.
  2. Ask an admin to exclude the app. Entra → Protection → Conditional Access → find the policy (Sign-in logs → the failed entry → Conditional Access tab names it) → exclude this application id, or your account.

Device-code sign-in is not a workaround — it fails the same device check, and many tenants block that flow outright as a phishing vector.

Streamable HTTP — hosted deployments

# from a clone
GRAPH_MCP_PORT=8094 uv run --directory /path/to/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.

Which settings you need depends entirely on how you run it. The two deployment shapes use different authentication models, and mixing them up is the most common setup mistake.

Running locally (stdio) — you are the user

The server signs you in. It is a public client, so there is no client secret — a program running on your own machine cannot keep one, since anyone with the config file or the process has it. MSAL uses PKCE instead.

Setting Env Default
Application (client) id GRAPH_MCP_CLIENT_ID / AZURE_AD_CLIENT_ID ""
Directory (tenant) id GRAPH_MCP_TENANT_ID / AZURE_AD_TENANT_ID common
Delegated scopes to request at sign-in GRAPH_MCP_SCOPES read-only set
Tool profiles to expose GRAPH_MCP_TOOLSETS core
Expose the write tools GRAPH_MCP_WRITE_SCOPE false
Caller identity, for tenant-scoping GRAPH_MCP_USER_EMAIL ""
Always use device code, never the browser GRAPH_MCP_FORCE_DEVICE_CODE false
Where the token cache lives GRAPH_MCP_CACHE_DIR ~/.ms-graph-mcp
Pre-acquired token instead of signing in (CI) GRAPH_MCP_ACCESS_TOKEN ""

GRAPH_MCP_CLIENT_SECRET is not used here and should not be set. It belongs to the hosted shape below. If you find yourself creating a client secret to run this locally, something has gone wrong — the app registration only needs to be a public client with http://localhost as its redirect URI.

Running hosted (Streamable HTTP) — the server acts for many users

Callers present a token; the server validates it and may exchange it. This is where a client secret belongs, because the server is a confidential client running somewhere you control.

Setting Env Default
Verify JWT signatures against JWKS GRAPH_MCP_JWT_VERIFY true
Shared secret for machine callers GRAPH_MCP_SHARED_SECRET "" (no gate)
Server performs its own OBO exchange GRAPH_MCP_DOES_OBO false
Client secret, for the OBO exchange GRAPH_MCP_CLIENT_SECRET / AZURE_AD_CLIENT_SECRET ""
Audience to validate in OBO mode GRAPH_MCP_AUDIENCE derived from client id
Graph scopes requested during OBO GRAPH_MCP_OBO_SCOPES …/.default
HTTP port GRAPH_MCP_PORT 8094
Public URL, enabling OAuth discovery GRAPH_MCP_RESOURCE_URL "" (discovery off)
Additional accepted Host values GRAPH_MCP_ALLOWED_HOSTS ""

GRAPH_MCP_CLIENT_ID and GRAPH_MCP_TENANT_ID are needed in both shapes.

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.

Set GRAPH_MCP_RESOURCE_URL when you deploy behind a proxy

It does two things, and the second one will bite you if you skip it.

It turns on OAuth discovery: the server publishes RFC 9728 metadata at /.well-known/oauth-protected-resource/mcp and answers an unauthenticated request with a 401 carrying WWW-Authenticate: Bearer resource_metadata="…". A spec-compliant MCP client follows that pointer to find your tenant's authorization server on its own, rather than needing it configured by hand. Left empty, discovery is simply off — the server cannot know its own public URL from behind a proxy, and publishing a guess would send clients somewhere wrong.

It also registers your hostname with the transport's DNS-rebinding protection. The MCP SDK validates the Host header and, by default, trusts only localhost. Since this process binds 0.0.0.0, a deployment behind an ingress receives requests with a real hostname — and without this setting every one of them is refused with 421 Misdirected Request before reaching any handler. Localhost stays valid regardless, so local runs and MCP Inspector are unaffected.

GRAPH_MCP_RESOURCE_URL=https://graph-mcp.example.com/mcp

Use GRAPH_MCP_ALLOWED_HOSTS (comma-separated) only for additional names that URL does not cover — a split-horizon DNS name, a service-mesh address, a second domain.

Getting 421 Misdirected Request on every request? That is this, and it is the most likely thing to go wrong on a first hosted deployment. Set GRAPH_MCP_RESOURCE_URL to the URL clients actually connect to.

Docker

The image serves the HTTP transport only. stdio speaks JSON-RPC over the process's own stdin/stdout, so a client has to spawn it directly — wrapping that in docker run gains nothing and breaks the interactive sign-in.

docker run --rm -p 8094:8094 \
  -e GRAPH_MCP_CLIENT_ID=<application-client-id> \
  -e GRAPH_MCP_TENANT_ID=<directory-tenant-id> \
  -e GRAPH_MCP_RESOURCE_URL=https://graph-mcp.example.com/mcp \
  ghcr.io/nitin27may/ms-graph-mcp:latest

Published to GHCR on each release for linux/amd64 and linux/arm64, with build provenance attestations. Runs as a non-root user (uid 10001) that cannot write to its own virtualenv, and carries a HEALTHCHECK against /health — which is unauthenticated and does not touch Graph, so a healthy container means the process is serving, not that Entra is reachable.

Sensible resource limits for a single replica; the process is I/O-bound on Graph, not CPU-bound:

resources:
  requests: { cpu: 50m,  memory: 128Mi }
  limits:   { cpu: 500m, memory: 512Mi }

Build it yourself with docker build -t ms-graph-mcp ..

Dynamic client registration is not available. Entra ID does not implement RFC 7591, so a client cannot register itself from the discovery metadata alone. Clients need a pre-registered app id — either yours, or their own with your API added as a permission. This is an Entra limitation, not something this server can work around.

Behaviour and safety

Setting Env Default
Remove the write tier entirely GRAPH_MCP_READ_ONLY false
Recipient-domain allowlist for sending and forwarding mail GRAPH_MCP_SEND_EMAIL_ALLOWED_DOMAINS "" (no gate)
Max files per browse GRAPH_MCP_BROWSE_MAX_FILES 500
Log level (INFO shows every Graph call) GRAPH_MCP_LOG_LEVEL WARNING
TLS verification off (corporate proxy) GRAPH_MCP_DISABLE_SSL_VERIFY false

GRAPH_MCP_READ_ONLY is stronger than leaving GRAPH_MCP_WRITE_SCOPE off: it removes the write tools from the deployment entirely, so no caller can reach them whatever they ask for. See SECURITY.md for what to change before exposing this beyond localhost.

Toolset profiles

85 tools is a lot to put in front of a model. GRAPH_MCP_TOOLSETS selects named profiles, each a group of namespaces:

Profile Namespaces Read tools Approx. tokens
core (default) search, mail, calendar, files, people 23 ~4,200
mail mail 5 ~800
calendar calendar 6 ~1,500
meetings meetings, calendar 13 ~2,900
files files 6 ~900
chat chat 7 ~1,000
people people 5 ~750
directory directory, people 12 ~1,900
tasks tasks 5 ~830
notes notes 4 ~570
search search 1 ~290
all everything 53 ~9,200

Combine them with commas:

GRAPH_MCP_TOOLSETS=mail,calendar,tasks

core is the default, so some tools are not advertised unless you ask for them. If you want Teams chat, Planner, OneNote, meeting transcripts or directory lookups, name those profiles — or set GRAPH_MCP_TOOLSETS=all to expose everything.

Over HTTP a caller may send X-Toolsets to narrow further for one request. It can only narrow. The startup value is a ceiling, so a client asking for all gains nothing the deployment did not already enable.

This filters visibility, not authority. A hidden tool is simply not listed; the write-scope and internal-tier gates are what actually stop a call, and they are unaffected.

Tool surface

Three tiers, one auth seam.

Tier Count Exposed when Examples
Read 53 always calendar_list_upcoming_events, mail_search, meetings_get_transcript, files_search, directory_list_user_groups
Write 23 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: mail 11 · tasks 11 · calendar 10 · files 10 · chat 8 · directory 7 · meetings 7 · people 6 · notes 5 · search 1.

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/permissions.md Every tool and the delegated permission it needs, plus copy-paste consent sets
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/testing.md Running the suite, how it is arranged, and driving the server with MCP Inspector
docs/debugging.md Logs, error codes, and the auth failures people actually hit
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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ms_graph_mcp-0.2.0.tar.gz (323.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ms_graph_mcp-0.2.0-py3-none-any.whl (136.7 kB view details)

Uploaded Python 3

File details

Details for the file ms_graph_mcp-0.2.0.tar.gz.

File metadata

  • Download URL: ms_graph_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 323.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ms_graph_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 a1e7dc204819cd5bdbb9ef267e698d462e2e3464bc707300aef201e1568a59fd
MD5 0b44513b559b985e3bd9436fa9ec1afd
BLAKE2b-256 d2dd0f6d9cfce3fc573834284da4e81621c73af7897454d123878723c28cd81b

See more details on using hashes here.

Provenance

The following attestation bundles were made for ms_graph_mcp-0.2.0.tar.gz:

Publisher: release.yml on nitin27may/ms-graph-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ms_graph_mcp-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: ms_graph_mcp-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 136.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ms_graph_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e2dbdce4c8e3dbbf8f3a28f9fcd3d9d9bdbc638cd61c084850d076cafcc83baf
MD5 c68593e2e231c6bb62623008ada9a7dc
BLAKE2b-256 95821e52e79070345d1b46c016e11e9609cd0504eb17be2d116847f2706d63a1

See more details on using hashes here.

Provenance

The following attestation bundles were made for ms_graph_mcp-0.2.0-py3-none-any.whl:

Publisher: release.yml on nitin27may/ms-graph-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page