Skip to main content

m365-evidence-mcp

An MCP server that turns the Microsoft Graph reads an IT auditor keeps repeating into tools any MCP-capable AI client can call. Point it at a tenant with a read-only token and ask for the evidence in plain language instead of clicking through four admin portals.

The four tools cover ITGC classics: security posture, MFA coverage, dormant accounts and privileged access. The model fetches, the auditor concludes.

Tools

Tool What it does
secure_score() Current Secure Score plus the five weakest controls
mfa_coverage() How many users are MFA registered, and who is not
stale_accounts(days) Enabled accounts with no sign-in in the last N days
privileged_roles() Activated directory roles and who holds them

Setup

python3 -m venv .venv
.venv/bin/pip install mcp

Get a Graph token. The Azure CLI is the quickest way:

export GRAPH_TOKEN=$(az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv)

The Access token tab in Graph Explorer works too. Scopes: SecurityEvents.Read.All for the score, Reports.Read.All for MFA coverage, User.Read.All plus AuditLog.Read.All for stale accounts, Directory.Read.All for roles. All of them are read scopes and most need admin consent.

Wire it into Claude Code:

claude mcp add m365evidence -- /path/to/m365-evidence-mcp/.venv/bin/python /path/to/m365-evidence-mcp/m365_evidence_mcp.py

Demo

What it looks like from Claude Code:

> pull the access review evidence for the quarter

⏺ m365evidence · privileged_roles()

  Global Administrator (2):
    - amir.admin@demo.example
    - breakglass@demo.example
  Helpdesk Administrator (1):
    - sara.support@demo.example

⏺ Two global admins and one of them is the break glass account.
  Helpdesk Administrator has a single holder. MFA coverage next?

The accounts above are demo data. The format is exactly what the server returns.

Design notes

  • Read-only by construction. Every tool is a single Graph GET, the annotations declare it, and a token with read scopes could not write anyway. Two layers, both structural.
  • Evidence, not judgement. Tools return counts with capped name lists, the kind of thing that goes straight into a workpaper. The conclusion stays with whoever reads it.
  • Nothing touches disk. The token lives in an environment variable and reports are never cached or logged.

Honest notes

  • Sign-in activity needs Entra ID P1 or better, so stale_accounts comes back empty on a bare Business Standard tenant.
  • Pagination is capped at ten pages of 999 objects. Fine for a small or midsize tenant, raise the cap in _get_all for bigger ones.
  • The logic is tested against canned Graph responses in test_server.py. Run python test_server.py.

About

Al Amin Bashir Afara, Dubai · github.com/aminafara123 · linkedin.com/in/aminafara

Release files for m365-evidence-mcp 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for m365-evidence-mcp 1.0.0
File Size Uploaded
m365_evidence_mcp-1.0.0.tar.gz 5.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for m365-evidence-mcp 1.0.0
File Interpreter ABI Platform
m365_evidence_mcp-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 12.2 kB

Release files / m365_evidence_mcp-1.0.0.tar.gz

Download URL m365_evidence_mcp-1.0.0.tar.gz
Size 5.7 kB
Tags Source
SHA-256 checksum
How to use checksums
7fe55db333fb826db484bf19ae41e6d29716aa70f5d0966cbc357137f97c88c3
BLAKE2b-256 checksum
How to use checksums
eb6eb2af761e897c720f8cbc181aa5cb782c60b858abf0b7948c7cef7749915b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / m365_evidence_mcp-1.0.0-py3-none-any.whl

Download URL m365_evidence_mcp-1.0.0-py3-none-any.whl
Size 6.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
12e1d2a5c0bf2bc7bb3726f73530db8de72485aa74674f1368d900612e2cd036
BLAKE2b-256 checksum
How to use checksums
556d5850498aa591e532ed3fd199465ef17a6754fbdeb7a4fbb0a9c0aa02fde0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page