Skip to main content
Glama
aminafara123

m365-evidence-mcp

by aminafara123

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

Related MCP server: azure-query-mcp

Setup

pipx install m365-evidence-mcp

uvx m365-evidence-mcp works too if you prefer no install. Hacking on a clone instead:

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 -- m365-evidence-mcp

Running 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.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

Available Tools

4 tools
mfa_coverageA
Read-onlyIdempotent

Share of users registered for MFA, with up to ten who are not. Needs Reports.Read.All.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_rolesA
Read-onlyIdempotent

Activated directory roles and who holds them, ten members shown per role. The access review starting point. Needs Directory.Read.All.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_scoreA
Read-onlyIdempotent

Current Microsoft Secure Score with the five weakest controls. Needs SecurityEvents.Read.All.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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_accountsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.6/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

  1. 4 tool updatesv1.0.0
    • First observedmfa_coverage
    • First observedprivileged_roles
    • First observedsecure_score
    • First observedstale_accounts

TDQS

A4/5.0

Scored across 4 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Enables 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.
    5
    18 npm
    2
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Read-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.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables 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