m365-evidence-mcp
Click on "Deploy 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-evidence-mcppull the access review evidence for this quarter"
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-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 |
| Current Secure Score plus the five weakest controls |
| How many users are MFA registered, and who is not |
| Enabled accounts with no sign-in in the last N days |
| Activated directory roles and who holds them |
Related MCP server: azure-query-mcp
Setup
pipx install m365-evidence-mcpuvx m365-evidence-mcp works too if you prefer no install. Hacking on a clone instead:
python3 -m venv .venv
.venv/bin/pip install mcpGet 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 -- m365-evidence-mcpRunning from a clone, point it at the venv instead:
claude mcp add m365evidence -- /path/to/m365-evidence-mcp/.venv/bin/python /path/to/m365-evidence-mcp/m365_evidence_mcp.pyDemo
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_accountscomes 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_allfor bigger ones.The logic is tested against canned Graph responses in
test_server.py. Runpython test_server.py.
About
Al Amin Bashir Afara, Dubai · github.com/aminafara123 · linkedin.com/in/aminafara
Available Tools
4 toolsmfa_coverageARead-onlyIdempotent
Share of users registered for MFA, with up to ten who are not. Needs Reports.Read.All.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, so the safety profile is covered. The description adds meaningful context beyond that: the required permission scope and the fact that the non-registered user list is capped at ten.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, zero filler, with the core metric front-loaded ahead of the permission requirement.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value details need not be spelled out, and the description still notes the ten-user cap and the permission prerequisite. Adequate for a zero-parameter read tool, though it could say slightly more about what the coverage share represents.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. There is nothing for the description to clarify regarding input semantics, and it does not confuse the issue.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific metric (share of users registered for MFA) plus an output cap detail (up to ten non-registered users). This clearly distinguishes it from siblings like secure_score or stale_accounts, though it doesn't name them explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'Needs Reports.Read.All' note gives a prerequisite, which is genuinely useful. However, there is no guidance on when to prefer this over secure_score or stale_accounts, so usage context is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
privileged_rolesARead-onlyIdempotent
Activated directory roles and who holds them, ten members shown per role. The access review starting point. Needs Directory.Read.All.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the bar is lower. The description adds two things annotations cannot: the required permission (Directory.Read.All) and an output-volume constraint (ten members per role), which warns the agent results may be truncated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with what the tool returns, followed by usage framing and the auth prerequisite. No filler and nothing repeated from the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless read tool with an output schema and full annotation coverage, the description supplies exactly the missing pieces: the permission requirement and the per-role member cap. Return values need not be described since the output schema handles that.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. The description correctly focuses on scope and prerequisites instead of parameter detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific resource (activated directory roles) and what it returns (who holds them), with a scope detail (ten members per role). It is clearly distinct from siblings like secure_score and mfa_coverage, though it never explicitly names them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"The access review starting point" implies when to reach for it, which is useful orientation. But there is no explicit when-not guidance or named alternative among secure_score, mfa_coverage, or stale_accounts, leaving the agent to infer routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
secure_scoreARead-onlyIdempotent
Current Microsoft Secure Score with the five weakest controls. Needs SecurityEvents.Read.All.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, open-world, and non-destructive behavior, so the bar is lower. The description adds important auth context ('Needs SecurityEvents.Read.All') and scopes the return to the score plus five weakest controls, which is useful beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the core result front-loaded and the permission requirement second. Every clause earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool with an output schema and rich safety annotations, the description supplies the remaining essentials: what is returned and which permission is required. Return-value details are appropriately left to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, so per the rubric the baseline is 4. The description adds no parameter details, but none are needed because the schema is explicitly empty and fully covered.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb/resource: returns the current Microsoft Secure Score plus the five weakest controls. It clearly describes what is retrieved, but does not distinguish this metric from sibling posture tools like mfa_coverage or stale_accounts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only usage context is the permission requirement (SecurityEvents.Read.All). There is no guidance on when to choose this tool over mfa_coverage, stale_accounts, or privileged_roles, and no exclusions or preconditions beyond the scope requirement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
stale_accountsARead-onlyIdempotent
Enabled accounts with no successful sign-in in the last N days, never-signed-in included. Needs User.Read.All and AuditLog.Read.All.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the bar is lower. The description adds real behavioral context beyond the structured fields: the two required Graph permissions and the inclusive handling of never-signed-in accounts, which directly affects result interpretation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler, and the substantive scope definition is front-loaded before the permission note. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read-only report with an output schema present, the definition supplies scope, edge-case semantics, and auth requirements. The only meaningful gap is the absence of routing guidance relative to the sibling tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% for the single 'days' parameter, so the description must carry the burden. 'Last N days' and 'never-signed-in included' clarify what the window means and that null sign-ins are not excluded, which is genuinely useful. It still does not state the unit bounds, the default of 90, or whether the window is measured to now, so it only partially compensates.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise scope: enabled accounts with no successful sign-in in the last N days, explicitly including never-signed-in accounts. That is a specific resource and filter definition an agent can distinguish from a generic account list. It does not, however, differentiate itself from the sibling reports (secure_score, mfa_coverage, privileged_roles), so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains what the output set contains but never says when to reach for this tool versus the sibling reports, nor any exclusion or prerequisite beyond the permission list. Usage is left to inference from the name and filter semantics.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v1.0.0- First observed
mfa_coverage - First observed
privileged_roles - First observed
secure_score - First observed
stale_accounts
TDQS
Scored across 4 tools
Each tool targets a distinct security evidence area: secure_score, mfa_coverage, stale_accounts, and privileged_roles. There is no overlap in purpose, and an agent can easily select the right tool for each data need.
All tool names follow a clear snake_case noun-phrase convention (e.g., secure_score, mfa_coverage, stale_accounts, privileged_roles). The pattern is predictable and consistent across the set.
Four tools is well-scoped for a focused M365 evidence-gathering server. Each tool earns its place and covers a key security posture check without redundancy.
The surface covers core identity and security evidence: overall score, MFA, stale accounts, and privileged roles. Minor gaps exist, such as conditional access or risky sign-in checks, but the core access review starting points are present.
Maintenance
Related MCP Connectors
Tenant-scoped evidence intake and controlled AI context over MCP.
Read-only finance and operations controls for AI agents with evidence and safe next actions.
Read-only MCP: free OpenAI security evidence ledger (55 fields) + SaaSDossier release register.
Remote MCP for A2A caller identity, scope policy, verdict receipts, and audit history.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables auditing and monitoring of Microsoft Entra ID security posture, Conditional Access policies, and Zero Trust alignment via Microsoft Graph API.5MIT
- AlicenseAqualityAmaintenanceEnables read-only querying of Azure Log Analytics and Azure Resource Graph through MCP, supporting KQL queries, workspace discovery, and resource inventory exploration with Azure RBAC authentication.518 npm2MIT
- FlicenseNot gradedqualityCmaintenanceRead-only MCP server for Microsoft Entra ID (Azure AD) that enables querying user sign-in logs, group memberships, and assigned Microsoft 365 licenses via Microsoft Graph API. Provides security and audit visibility without any write operations.-
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to query an organization's device posture, compliance, policies, and software/CVE status through a remote, read-only, OAuth-secured MCP endpoint.MIT