Cloud Horizon Get the free audit

May 12, 2026 9 min read

MCP for Microsoft 365: reading Entra ID and audit logs through a protocol that does not exist yet

Microsoft does not ship an MCP server for M365 or Entra ID. We built a bridge that turns Microsoft Graph API calls into MCP tools, so Claude can reason about user licenses, sign-in logs, and conditional access policies in real time. Why this is harder than it looks, and what is coming next.

Microsoft ships APIs for almost every Microsoft 365 and Entra ID surface. You can read user licenses, audit sign-ins, list conditional access policies, and query service health through Microsoft Graph. What Microsoft does not ship is an MCP server that exposes those APIs as tools that Claude, Cursor, or any other MCP client can discover and call.

We built the bridge. Cloud Horizon's MCP server translates Microsoft Graph API calls into MCP tools, so Claude can reason about your Microsoft 365 tenant in real time. The architecture is different from AWS and GCP because Microsoft authentication is different. Here is how it works.

Why Microsoft is harder

AWS and GCP use long-lived access keys. Microsoft uses OAuth 2.0 with short-lived access tokens. A service account key for AWS lasts until you rotate it. A Microsoft Graph token expires in 1 hour. The MCP server must handle token refresh transparently or the tools stop working mid-conversation.

The second problem is permission models. AWS IAM and GCP IAM are straightforward: you create a role, attach a policy, done. Microsoft Graph permissions require admin consent in Entra ID. If the admin has not consented to AuditLog.Read.All, the sign-in log tool returns a 403 even if the user has the right role assignments.

The third problem is data volume. A 10,000-user tenant generates millions of sign-in events per month. The Graph API paginates at 1,000 events per request. Claude cannot reason about millions of rows. The MCP server filters and aggregates before returning anything.

Architecture: the Microsoft bridge

The MCP server stores three secrets in Cloudflare:

  • MS_TENANT_ID — the Entra ID tenant ID
  • MS_CLIENT_ID — the app registration client ID
  • MS_CLIENT_SECRET — the client secret for token acquisition

On each tool call, the Function requests an access token from https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token using client credentials grant. The token is cached in a Durable Object for 45 minutes. The Graph API call uses the token, and the result is returned to the MCP client.

The permission model

We recommend an app registration with exactly these Microsoft Graph application permissions:

  • User.Read.All — list users and their license assignments
  • Directory.Read.All — read organization details and groups
  • AuditLog.Read.All — read sign-in and audit logs
  • Policy.Read.All — read conditional access policies
  • ServiceHealth.Read.All — read service health incidents

No Directory.ReadWrite.All. No User.ReadWrite.All. The app cannot create users, change policies, or delete groups. Everything is read-only.

After creating the app registration, an Entra ID admin must grant admin consent in the Azure Portal. Without consent, every Graph call returns 403 regardless of the client credentials.

The tool surface

ToolWhat it returns
ms_entra_list_usersUsers, roles, license assignments, last sign-in times
ms_entra_get_signinsSign-in events filtered by user, app, or risk level
ms_entra_list_policiesConditional access policies, rules, and assignments
ms_service_healthActive incidents, advisories, and planned maintenance
ms_license_summaryAssigned vs available licenses by SKU

What Claude can ask

  • "Which users have not signed in for 30 days but still have E5 licenses?"
  • "Show me failed sign-ins from outside the EU in the last 24 hours"
  • "Which conditional access policies do not require MFA?"
  • "How many M365 E3 licenses are unassigned?"
  • "Is there any active service incident affecting Exchange Online?"

Claude translates each question into one or more Graph API calls, aggregates the results, and presents a structured answer. The human can then ask follow-up questions without writing KQL or PowerShell.

Demo mode: no tenant required

Without credentials, the MCP server returns realistic demo data: 500 users, 3 conditional access policies, 10,000 sign-in events, and 200 E5 licenses. The structure matches the real Graph API responses. When you connect your tenant, the same queries return live data.

Performance: handling scale

The sign-in log tool defaults to the last 24 hours with a maximum of 1,000 events. For larger queries, the tool aggregates by application, location, and status code before returning. The user gets a summary, not a raw event dump.

Token refresh is automatic. The cached token is refreshed 10 minutes before expiry. The MCP client never sees a 401.

What is next

Exchange Online mailbox audit. SharePoint site inventory. Teams usage analytics. Intune device compliance. Secure Score recommendations. Defender alerts. Every Microsoft 365 surface that exposes a read API through Graph belongs in the MCP server eventually.

The server is open source at cloudevolvers/cloudsight. The MCP config lives at /.well-known/mcp.json.

Keep reading

More from the blog