m365-audit-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-audit-mcpFind orphaned documents"
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 Audit MCP server
Docs: Getting started · Architecture · Customization · Evaluation · Diagrams · FAQ
Live demo: derekgallardo01.github.io/m365-audit-mcp — sample question + tool invocation + JSON response for each of the 5 tools, regenerated on every push.

Full-page capture (all 5 tools) →
An MCP server that exposes Microsoft 365 privacy / compliance audit checks as tools any MCP client (Claude Desktop, Cursor, VS Code, custom Agent SDK builds) can call.
Default backend is a realistic mocked tenant — so the server runs anywhere, zero credentials, zero setup. The production seam swaps to Microsoft Graph without changing the tool surface.
pip install -e .
m365-audit-mcp # runs the MCP server over stdiopython -m pytest -q # 11 unit tests covering every toolStdlib-only Python except for the mcp SDK itself. No real M365 tenant
required to develop against.
Run in Docker
docker build -t m365-audit-mcp .
docker run --rm m365-audit-mcp python -m pytest -q # run tests in the image
docker run --rm -i m365-audit-mcp # run the server (stdio)For Claude Desktop / Cursor integration, prefer the pip install -e .
path on the host — MCP clients launch the server as a subprocess and
talk to it via pipes, which is awkward through Docker. The Dockerfile
is for CI, packaging, and remote-hosted deployments.
Related MCP server: azure-compliance-mcp
Example: production scenario
examples/tenant_health_report.py — Calls all 5 audit tools directly (skipping MCP transport) and builds an executive markdown tenant-health report with the top 3 priority actions surfaced
python examples/tenant_health_report.pyWhat it's for
When you're running an M365 / Copilot rollout, the questions that come up weekly are the same: "is our tenant configured correctly?", "what SharePoint documents are orphaned?", "are our Conditional Access policies actually enforcing or still in report-only?", "where is Copilot adoption stalling?"
This MCP server lets you chat them in Claude / Cursor instead of clicking through the M365 admin centre, and returns structured data the LLM can summarise, compare, or paste straight into a sign-off doc.
Tools
Tool | What it returns | Typical question |
| Tenant metadata + per-item verification status mirroring the m365-privacy-config checklist | "Are we configured to keep client data in-tenant?" |
| Documents with no owner OR not accessed in N days, each with a recommendation | "What's at risk to leak into Copilot grounding?" |
| All CA policies; flags any not in | "Are any of our policies still report-only?" |
| DLP policies, optionally filtered by location | "What's covering Teams chats?" |
| Tenant-wide or per-team Copilot adoption stats | "Where is rollout stalling?" |
Each tool returns JSON-serializable dicts. The LLM consumes them and turns them into natural language for the human, or chains tool calls (e.g. "list low-adoption teams, then for each one summarize their top prompts").
How to wire into Claude Desktop
Add to your Claude Desktop config:
{
"mcpServers": {
"m365-audit": {
"command": "m365-audit-mcp"
}
}
}Restart Claude Desktop. The five tools appear in the tool list — Claude
can now answer questions like "summarize our tenant's privacy posture
and flag anything outstanding" by calling check_tenant_privacy_config
without any further prompting from you.
The exact same config shape works in Cursor, in custom Agent SDK builds, and in any MCP client that supports stdio transport.
Architecture
flowchart LR
C["MCP client<br/>(Claude Desktop / Cursor / SDK)"] <-->|stdio| S["FastMCP server<br/>src/m365_audit_mcp/server.py"]
S --> T["audit_tools.py<br/>(pure functions)"]
T --> B{"BACKEND"}
B -- "default" --> M["mock_data.py<br/>(realistic mocked tenant)"]
B -.->|"production swap"| G["Microsoft Graph client<br/>(yours to implement)"]server.pyis a thin FastMCP wrapper — registers each tool, hands off to the pure function inaudit_tools.py.audit_tools.pydoes the work. Each function is testable directly without touching the MCP transport (that's how all 11 tests work).mock_data.pyreturns realistic tenant-shaped data. To swap in real Microsoft Graph, replace theBACKENDconstant inaudit_tools.pywith a Graph client wrapper that returns the same shape. No other code changes.
Bringing it to a real tenant
The BACKEND swap point in audit_tools.py is the single integration
point. A production replacement would:
Implement a
GraphBackendclass with the same attributes (TENANT,PRIVACY_CONFIG,DOCUMENTS,CONDITIONAL_ACCESS_POLICIES, etc.) but populated from Microsoft Graph queries instead of constants.Use an Entra ID app registration with the minimum scopes per tool (
User.Read.All,Directory.Read.All,Policy.Read.All,Reports.Read.All,Sites.Read.All).Cache aggressively — Graph quotas are real, and audit queries don't need second-by-second freshness.
The mocked default lets you develop and demo the integration into an agent (Claude Desktop or otherwise) without ever touching a real tenant.
What's inside
Path | Purpose |
| FastMCP server registering 5 tools |
| Pure-function tool implementations |
| Realistic mocked tenant data |
| 11 unit tests (each tool + edge cases) |
| Python packaging + |
Companion repos
m365-privacy-config — the human-readable checklist this MCP server mirrors
rag-over-docs-kit — pairs naturally if you want to ground answers in your own M365 docs in addition to the audit data
copilot-studio-support-agent — the inverse pattern: an agent INSIDE M365, vs. this server SERVING M365 data to an agent outside it
Available Tools
5 toolsaudit_conditional_access_policiesA
Audit Conditional Access policies for risks.
Lists every CA policy and flags any that aren't in enabled state (i.e.
reportOnly or disabled). Report-only policies are documented intent
that isn't actually enforcing; long-lived report-only policies are a
common audit finding.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It describes the behavior: listing all CA policies and flagging non-enabled ones, with additional context about report-only policies being common audit findings. This discloses potential implications without stating side effects (which are likely none, as it's a read operation).
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?
The description is relatively concise with two sentences in the second paragraph and a clear structure: purpose sentence followed by explanation. It could be slightly more streamlined but is efficient and front-loaded.
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?
No output schema exists, so the description should explain return values. It states it lists and flags policies, but does not detail the output format (e.g., what constitutes a 'flag'). The mention of report-only policies adds useful context, but completeness is average.
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 the description does not need to add param info. Baseline is 4, and the description appropriately mentions no parameters implicitly.
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?
The description clearly states the tool audits Conditional Access policies for risks and explains it lists all policies and flags those not in enabled state. The verb 'audit' is somewhat generic but the elaboration makes the purpose specific. It distinguishes from sibling tools which cover different domains.
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?
Usage is implied by the description: use when you need to audit CA policies for non-enabled states. However, there is no explicit when-to-use, when-not-to-use, or mention of alternatives. Given the sibling tools are unrelated, the context is sufficient but minimal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_tenant_privacy_configA
Return the tenant's M365 privacy / compliance configuration with verification status.
Mirrors the structure of the m365-privacy-config checklist (data residency, Copilot no-training, Azure OpenAI retention, BAA scope) so the output can be pasted straight into a sign-off document for the compliance owner.
Returns a dict with the tenant metadata, a summary count of verified vs
outstanding items, and per-item evidence (or action_required if not yet
verified).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description details the return structure (dict with tenant metadata, summary count, per-item evidence or action_required), which is sufficient behavioral transparency. It does not indicate side effects or destructive actions, which is appropriate for a read-only tool.
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?
The description is three sentences, front-loading the purpose and then elaborating on the output structure. It is concise but could be slightly more streamlined by combining the second and third sentences.
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?
Given no output schema and no annotations, the description adequately explains the return value and its structure. It covers the necessary context for an agent to understand what the tool provides in a compliance sign-off scenario.
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 has zero parameters, so the schema already covers everything. The description adds value by explaining the output format and intended use, which goes beyond the empty schema.
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?
The description clearly states 'Return the tenant's M365 privacy / compliance configuration with verification status' with a specific verb and resource. It distinguishes itself from sibling tools like 'audit_conditional_access_policies' or 'list_dlp_policies' by focusing on privacy and compliance configuration mirroring a checklist.
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 implies usage for generating sign-off documents for compliance owners, providing context that the output is structured for direct insertion into a checklist. While it does not explicitly exclude alternatives, the use case is clearly defined.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_orphaned_documentsA
Find documents in the tenant that look orphaned.
A document is flagged if EITHER:
it has no owner (when include_no_owner is True), OR
it hasn't been accessed in
days_thresholddays.
Each flagged document includes a recommendation (archive, reassign, or review). Useful for monthly governance review or before enabling Copilot on a site (orphaned docs leak into Copilot grounding by default).
| Name | Required | Description | Default |
|---|---|---|---|
| days_threshold | No | ||
| include_no_owner | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It explains the detection logic (EITHER condition) and consequence (orphaned docs leak into Copilot grounding). No contradictions.
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-paragraph structure: first states purpose, second explains conditions. Every sentence adds value. Could be slightly more structured (e.g., bullet list), but no waste.
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 tool with 2 parameters and no output schema, description covers detection logic, use cases, and implications (Copilot grounding). Complete for its complexity.
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% but description adds meaning to both parameters: 'include_no_owner' controls flagging docs with no owner, 'days_threshold' sets access age. This goes beyond the schema's name and type.
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?
The description clearly states the tool finds orphaned documents with two explicit conditions (no owner or not accessed within threshold) and mentions included recommendations. It distinguishes from sibling tools (audit, DLP, etc.) by focusing on orphan detection.
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?
Provides clear use cases: monthly governance review or before enabling Copilot on a site. Does not explicitly state when not to use or compare to alternatives, but context is helpful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_dlp_policiesA
List Data Loss Prevention (DLP) policies.
Optional location filter (e.g. "Exchange", "SharePoint", "OneDrive",
"Teams"). Returns the policy id, displayName, state, locations, and
sensitiveTypes covered. Useful for confirming that the surfaces a
Copilot or AI build will touch are actually covered before go-live.
| Name | Required | Description | Default |
|---|---|---|---|
| location | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries burden. It discloses returned fields (id, displayName, state, locations, sensitiveTypes) but lacks mention of permissions, rate limits, or any side effects. Adequate but not comprehensive.
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: first succinctly states purpose, second adds useful examples and context. No wasted words.
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 simple list tool with one optional parameter and no output schema, the description covers purpose, filter, and use case adequately. Could detail output format more but sufficient for selection and invocation.
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?
Parameter schema only has 'Location' with default null. The description adds concrete examples ('Exchange', 'SharePoint', etc.), significantly enhancing understanding beyond the schema's minimal info.
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?
The description clearly states the tool lists DLP policies, with an optional location filter. It distinguishes from siblings like audit_conditional_access_policies and summarize_copilot_usage, which address different concerns.
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?
Provides a specific use case: confirming coverage before go-live for Copilot or AI builds. Does not explicitly exclude alternatives but gives clear context for when to use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
summarize_copilot_usageA
Summarize Microsoft 365 Copilot usage.
With no arguments, returns a tenant-wide summary plus per-team breakdown
sorted by adoption percentage (lowest first - the rollout-gap teams).
With team_id, returns the detailed stats + top prompts for that team.
Adoption is activeUsers / totalUsers. Teams below 50% get
adoptionStatus: "low" so the user can see where rollout has stalled.
| Name | Required | Description | Default |
|---|---|---|---|
| team_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses behavioral traits: the behavior difference with/without team_id, the sort order, the adoption calculation, and the 'low' status for teams below 50%. It does not mention permissions or rate limits, but for a read-only summary tool this is acceptable.
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?
The description is concise, front-loaded with the core purpose, and each sentence earns its place. No unnecessary words or fluff.
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?
Given the tool has one optional parameter and no output schema, the description covers the two usage scenarios, sort order, and adoption status logic. It does not explain return format (e.g., fields), but is sufficient for typical use.
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 single parameter team_id is described only via the context that providing it yields detailed stats for that team. With 0% schema coverage, this adds some meaning but does not specify format or source of team IDs. Partially compensates but leaves room for improvement.
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?
The description clearly states the tool summarizes Microsoft 365 Copilot usage, and specifies two distinct modes: tenant-wide summary with per-team breakdown (no arguments) and detailed stats per team (with team_id). This distinguishes it from sibling tools which focus on audit, privacy, or DLP.
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 explicitly tells when to use without arguments (tenant summary) and with team_id (detailed stats), including the sort order (lowest adoption first). However, it does not mention explicit when-not-to-use scenarios or alternatives, though siblings are unrelated.
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.
5 tool updates
v1.0.0- First observed
audit_conditional_access_policies - First observed
check_tenant_privacy_config - First observed
find_orphaned_documents - First observed
list_dlp_policies - First observed
summarize_copilot_usage
TDQS
Scored across 5 tools
Each tool targets a distinct aspect of M365 auditing: conditional access policies, tenant privacy config, orphaned documents, DLP policies, and Copilot usage. There is no overlap or ambiguity between them.
All tool names follow a consistent verb_noun pattern (audit_, check_, find_, list_, summarize_) using snake_case, making them predictable and easy to distinguish.
With 5 tools covering different audit domains, the count is well-scoped for an audit-focused MCP server. Each tool serves a clear purpose without redundancy.
The tools cover key audit areas (conditional access, privacy, orphaned docs, DLP, Copilot) but lack common audit tasks like user activity logs, sharing policy audits, or admin role reviews. Several important audit dimensions are missing.
Maintenance
Related MCP Connectors
Official Microsoft MCP Server to query Microsoft Entra data using natural language
Compliance frameworks (SOC 2, ISO 27001, CMMC, NIST, more) delivered to AI agents as MCP tools.
EU compliance corpus across 8 frameworks (NIS2, DORA, AI Act, ISO 27001 + more) via MCP.
Find, vet, and run MCP tools through a secure audited gateway with prompt-injection risk scoring
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceMCP-native auditor for LLM hallucination and grounding issues in RAG systems. Provides prioritized findings in table, JSON, or SARIF format for CI gating and AI agent integration.-
- AlicenseAqualityBmaintenanceEnables natural-language queries about Azure resource compliance, including VM compliance, patch status, orphaned RBAC, and infrastructure health, through read-only MCP tools.3MIT
- AlicenseAqualityDmaintenanceExposes Azure AI Foundry agents, workflows, and AI Search vector-database capabilities as MCP tools, enabling natural language interaction with agents, semantic search, and index management.102MIT
- AlicenseAqualityBmaintenanceExposes the Maester security test framework for Microsoft 365/Entra/Defender as MCP tools, enabling AI agents to run tests, audit AI agents and MCP servers, and investigate security posture.9MIT