Skip to main content
Glama
derekgallardo01

m365-audit-mcp

M365 Audit MCP server

CI License: MIT Python Open in GitHub Codespaces

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.

Live demo preview

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 stdio
python -m pytest -q     # 11 unit tests covering every tool

Stdlib-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.py

What 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

check_tenant_privacy_config

Tenant metadata + per-item verification status mirroring the m365-privacy-config checklist

"Are we configured to keep client data in-tenant?"

find_orphaned_documents

Documents with no owner OR not accessed in N days, each with a recommendation

"What's at risk to leak into Copilot grounding?"

audit_conditional_access_policies

All CA policies; flags any not in enabled state

"Are any of our policies still report-only?"

list_dlp_policies

DLP policies, optionally filtered by location

"What's covering Teams chats?"

summarize_copilot_usage

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.py is a thin FastMCP wrapper — registers each tool, hands off to the pure function in audit_tools.py.

  • audit_tools.py does the work. Each function is testable directly without touching the MCP transport (that's how all 11 tests work).

  • mock_data.py returns realistic tenant-shaped data. To swap in real Microsoft Graph, replace the BACKEND constant in audit_tools.py with 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:

  1. Implement a GraphBackend class with the same attributes (TENANT, PRIVACY_CONFIG, DOCUMENTS, CONDITIONAL_ACCESS_POLICIES, etc.) but populated from Microsoft Graph queries instead of constants.

  2. 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).

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

src/m365_audit_mcp/server.py

FastMCP server registering 5 tools

src/m365_audit_mcp/audit_tools.py

Pure-function tool implementations

src/m365_audit_mcp/mock_data.py

Realistic mocked tenant data

tests/test_audit_tools.py

11 unit tests (each tool + edge cases)

pyproject.toml

Python packaging + m365-audit-mcp script entry

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 tools
audit_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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.7/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_threshold days.

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

ParametersJSON Schema
NameRequiredDescriptionDefault
days_thresholdNo
include_no_ownerNo

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
locationNo

TDQS

A4.2/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
team_idNo

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 5 tool updatesv1.0.0
    • First observedaudit_conditional_access_policies
    • First observedcheck_tenant_privacy_config
    • First observedfind_orphaned_documents
    • First observedlist_dlp_policies
    • First observedsummarize_copilot_usage

TDQS

A4.1/5.0

Scored across 5 tools

Disambiguation5/5

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.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern (audit_, check_, find_, list_, summarize_) using snake_case, making them predictable and easy to distinguish.

Tool Count5/5

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.

Completeness3/5

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

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Exposes 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.
    10
    2
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Exposes 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.
    9
    MIT