Server · #379 trending MCP repo · ↗ +1 stars this week

Ms 365 Admin MCP Server

okapi-ca/ms-365-admin-mcp-server

MCP server for Microsoft 365 admin operations via Graph API application permissions (security, audit, reports, service health)

Stars
19
This week
+1
Forks
5
Open issues
15
Skills inside
1
Star trend · last 9 days+1 ★
Oct 29, 2026: 18 starsOct 30, 2026: 18 starsOct 31, 2026: 18 starsNov 1, 2026: 18 starsNov 2, 2026: 18 starsNov 3, 2026: 18 starsNov 4, 2026: 18 starsNov 5, 2026: 18 starsNov 6, 2026: 19 starsNov 7, 2026: 19 stars

Get started

Add it to your agent

claude mcp add ms-365-admin -- npx -y @okapi-ca/ms-365-admin-mcp-server

Run in your terminal. Add --scope project to share it with your team through .mcp.json.

Documentation

README

View on GitHub ↗

ms-365-admin-mcp-server

CI npm version License: MIT

A Model Context Protocol (MCP) server for Microsoft 365 administration via Graph API application permissions (client credentials).

Built on the architecture and endpoint-driven design pioneered by Softeria/ms-365-mcp-server, and complementary to it: Softeria's server uses delegated permissions for end-user productivity scenarios, while this one uses application permissions for admin operations — security monitoring, identity audits, incident response, and service health. See Acknowledgments below.

Features

  • 674 tools covering security, audit, identity, app credentials, guest users, Exchange, Intune (devices, apps, MAM, reports, Settings catalog & Endpoint security (BitLocker, Antivirus, Firewall, ASR), encryption report, Windows Update profiles, BitLocker and LAPS rotation, macOS Platform Scripts, macOS custom attribute scripts, assignment filters, Remediations, Windows PowerShell scripts, custom compliance scripts), governance (PIM, access reviews, entitlement, lifecycle), compliance, threat intelligence, advanced hunting, Defender for Identity (sensors, candidates, migration, identity accounts, audit policy), Microsoft 365 Copilot admin (usage reports, interaction history audit, AI users, meeting insights, agent registrations, policy settings), custom security attributes, LAPS, policies, reports, incident response, eDiscovery v3 (cases, custodians, noncustodial data sources, review sets, queries, exports, operations), Purview DSPM (protection scopes), event-based retention triggers, Teams online meeting attendance reports (app-only with Application Access Policy), deleted chats restore (admin recovery flow), Teams chat investigation reads (Chat.Read.All for triage; eDiscovery v3 for court-admissible production), Cloud PC, call records, Universal Print, information protection, SharePoint admin, and records management
  • Application permissions (client credentials) — no user interaction required
  • Read-only by default — write operations require explicit --allow-writes
  • Risk classification on write tools (low/medium/high/critical)
  • Presets to filter tools by domain (security, audit, identity, etc.)
  • Two transports: stdio (default) and HTTP (StreamableHTTP)
  • Multi-cloud: Microsoft global and China (21Vianet)
  • Key Vault support for secrets management

Documentation

Document Purpose
docs/USE_CASES.md 18 typical admin scenarios with sample prompts and tool lists
docs/playbooks/ End-to-end security incident response playbooks
agent-skills/ Drop-in skills for LLM agents (Claude Code et al.) with safety patterns
docs/APP_REGISTRATION.md Step-by-step Azure AD app registration and permission consent
docs/HTTP_DEPLOYMENT.md HTTP transport, JWT validation, Docker, Azure Container Apps
docs/AZURE_DEPLOYMENT_SECURITY.md Threat model, required controls, and checklist for Azure production deploys
docs/TROUBLESHOOTING.md Common errors and how to diagnose them
docs/ARCHITECTURE.md Internal architecture and code generation pipeline
docs/RISK_MODEL.md Risk classification rubric for write tools
CONTRIBUTING.md How to contribute new tools, presets, and fixes
SECURITY.md Vulnerability reporting and operator hardening checklist
CHANGELOG.md Release history

Prerequisites

  • Node.js >= 18
  • An Azure AD app registration with application permissions (not delegated)
  • A specific tenant ID (not "common")

Installation

npm install -g @okapi-ca/ms-365-admin-mcp-server
ms-365-admin-mcp-server --help

Docker

docker pull ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest
docker run --rm -i \
  -e MS365_ADMIN_MCP_CLIENT_ID=... \
  -e MS365_ADMIN_MCP_CLIENT_SECRET=... \
  -e MS365_ADMIN_MCP_TENANT_ID=... \
  ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest

From source

git clone https://github.com/okapi-ca/ms-365-admin-mcp-server.git
cd ms-365-admin-mcp-server
npm install
npm run generate
npm run build

Configuration

Environment variables

Variable Required Description
MS365_ADMIN_MCP_CLIENT_ID Yes App registration client ID
MS365_ADMIN_MCP_CLIENT_SECRET Yes App registration client secret
MS365_ADMIN_MCP_TENANT_ID Yes Azure AD tenant ID (must be specific)
MS365_ADMIN_MCP_CLOUD_TYPE No global (default) or china
MS365_ADMIN_MCP_KEYVAULT_URL No Azure Key Vault URL (overrides env vars)
MS365_ADMIN_MCP_MAX_TOP No Cap $top query param to limit result size
READ_ONLY No true/1 to force read-only (default behavior)
ENABLED_TOOLS No Regex to filter available tools

MCP client configuration (Claude Desktop, etc.)

{
  "mcpServers": {
    "ms365-admin": {
      "command": "node",
      "args": ["/path/to/ms-365-admin-mcp-server/dist/index.js"],
      "env": {
        "MS365_ADMIN_MCP_CLIENT_ID": "your-client-id",
        "MS365_ADMIN_MCP_CLIENT_SECRET": "your-client-secret",
        "MS365_ADMIN_MCP_TENANT_ID": "your-tenant-id"
      }
    }
  }
}

VS Code (1.102+)

VS Code consumes the same MCP protocol but uses a different config layout — servers instead of mcpServers, an explicit type field, and inputs for secret prompts. A ready-to-copy sample lives at .vscode/mcp.json.example; copy it to .vscode/mcp.json and VS Code will prompt for the tenant / client / secret on first start, then store them in its secret store (the real mcp.json is gitignored so resolved secrets never reach the repo).

Minimal stdio setup:

{
  "inputs": [
    { "type": "promptString", "id": "ms365-tenant-id", "description": "Tenant ID" },
    { "type": "promptString", "id": "ms365-client-id", "description": "Client ID" },
    {
      "type": "promptString",
      "id": "ms365-client-secret",
      "description": "Client secret",
      "password": true,
    },
  ],
  "servers": {
    "ms365-admin": {
      "type": "stdio",
      "command": "ms-365-admin-mcp-server",
      "args": ["--preset", "security,audit,identity,health"],
      "env": {
        "MS365_ADMIN_MCP_TENANT_ID": "${input:ms365-tenant-id}",
        "MS365_ADMIN_MCP_CLIENT_ID": "${input:ms365-client-id}",
        "MS365_ADMIN_MCP_CLIENT_SECRET": "${input:ms365-client-secret}",
      },
    },
  },
}

For remote HTTP deployments, use "type": "http" with a url field (VS Code 1.103+ handles OAuth 2.0 Dynamic Client Registration natively) or fall back to the mcp-remote bridge when the native browser flow is unavailable — see the example file for both shapes.

Tools surface in Agent mode (GitHub Copilot Chat). VS Code asks for per-tool approval; the --preset flag above keeps the catalog manageable. Use Cmd/Ctrl+Shift+P → MCP: List Servers → Show Output to see logs.

Catalog size limit on Claude.ai surfaces

Claude.ai, Claude Desktop and cloud sessions serve each connector's tools under a fixed budget of 1 MiB of input schema (compact JSON; tool names and descriptions are not counted). Tools are admitted in alphabetical order and a tool that no longer fits is dropped silently. Claude Code CLI is not affected. The limit is not documented publicly.

In a cloud session linked to a Mac, the claude-device bridge relays every local MCP server under one connector (lcl-<server>-<tool>), so all local servers share that budget, and this server's tools sort after most of them.

Request bodies are therefore advertised shallow (src/advertised-schema.ts): the entity's own fields with their descriptions, nested objects as free-form objects, and no Read-only. fields. Graph validates the body; the server forwards it as sent. With writes enabled the catalog advertises about 595 KB of input schema, and test/advertised-schema.test.ts fails the build above 768 KiB.

If tools still go missing in a cloud session, shrink what this server advertises (read-only mode, --preset, --enabled-tools), disable unused local servers, or register this server as its own connector so it gets a budget of its own.

Remote HTTP server: device_code authentication (RFC 8628)

If the server runs in HTTP / OAuth mode on a remote host (e.g. Azure Container Apps) and the client connects via mcp-remote, the standard flow requires a browser to reach localhost:14543/oauth/callback. When that isn't possible — macOS Platform SSO hijacks the WebKit flow, Claude Code runs in a headless Docker container, the user is on a remote SSH dev env — use the ms-365-admin-mcp-auth bootstrap to pre-seed mcp-remote's token cache instead.

npx -p @okapi-ca/ms-365-admin-mcp-server@latest ms-365-admin-mcp-auth \
  --server https://your-mcp-host.azurecontainerapps.io/mcp

The helper prints a URL and a user code; you sign in on any device you trust (phone, another laptop) and the tokens are written to ~/.mcp-auth/mcp-remote-<version>/. Claude Desktop / Claude Code then launches mcp-remote normally and finds the cached tokens without ever opening a browser.

See docs/TROUBLESHOOTING.md for Docker / remote-dev patterns and exit code reference.

Usage

CLI options

--read-only              Read-only mode (default)
--allow-writes           Enable write operations
--enabled-tools <regex>  Filter tools by regex pattern
--preset <names>         Use preset categories (comma-separated)
--partition <name>       Tool partition served on /mcp/<group> in HTTP mode (default: domains)
--list-presets           List available presets and exit
--list-tools             List available tools and exit
--list-permissions       List required Graph API permissions and exit
--verify-login           Test credentials against Graph API and exit
--cloud <type>           Cloud environment: global (default) or china
--transport <type>       Transport: stdio (default) or http
--port <number>          HTTP port (default: 8080)
--host <address>         HTTP bind address (default: 127.0.0.1)
--allowed-clients <ids>  Comma-separated Entra app IDs (required for HTTP)
-v                       Verbose logging

Presets

# Security alerts and incidents only
node dist/index.js --preset security

# Identity management tools
node dist/index.js --preset identity

# Multiple presets
node dist/index.js --preset security,audit,identity
Preset Description
security Security alerts, incidents, attack simulations, and threat intelligence
audit Directory audits, sign-ins, provisioning logs, deleted items
health Service health and Message Center
reports Usage reports (Teams, Email, SharePoint, OneDrive, Mailbox, M365 Apps)
identity Users, groups, roles, devices, PIM, guest users, external identities
exchange Exchange administration (message traces, mailboxes)
intune Managed devices, compliance, configurations, Autopilot, apps, RBAC
governance Access reviews, entitlement management, lifecycle workflows, terms of use
compliance Licenses, Secure Score, Identity Protection, risk detections, policies
response Incident response write operations (disable, revoke, confirm, dismiss)
ediscovery eDiscovery cases (Microsoft Purview)
cloudpc Cloud PC / Windows 365 (provisioning, images, connections, settings, audit)
callrecords Teams call records
print Universal Print (printers, shares, connectors, services, operations, tasks)
infoprotection Information Protection (BitLocker recovery keys, threat assessment)
sharepointadmin SharePoint tenant administration settings
retention Records Management (retention labels, file plan metadata)
all All available tools

Verify credentials

node dist/index.js --verify-login

Available tools (674)

Security (11)

Tool Method Risk
list-security-alerts GET
get-security-alert GET
update-security-alert PATCH medium
list-security-incidents GET
get-security-incident GET
update-security-incident PATCH medium
list-attack-simulations GET
get-attack-simulation GET
create-attack-simulation POST high
update-attack-simulation PATCH medium
delete-attack-simulation DELETE medium

Audit logs & deleted items (5)

Tool Method
list-directory-audits GET
list-sign-ins GET
list-provisioning-logs GET
list-deleted-users GET
list-deleted-groups GET

Service health (3)

Tool Method
list-service-health GET
list-service-issues GET
list-service-messages GET

Usage reports (8)

Tool Method
get-teams-activity-report GET
get-email-activity-report GET
get-active-users-report GET
get-sharepoint-usage-report GET
get-onedrive-usage-report GET
get-active-user-counts-report GET
get-mailbox-usage-report GET
get-m365-apps-usage-report GET

Users (9)

Tool Method Risk
list-users GET
get-user GET
list-user-memberships GET
list-user-auth-methods GET
list-user-devices GET
create-user POST high
delete-user DELETE critical
assign-user-license POST medium
reprocess-user-license POST low

There is no general-purpose update-user. The only PATCH on /users/{id} this server exposes is disable-user-account (see Incident response), which is deliberately narrow: it sets accountEnabled and nothing else.

Devices (2)

Tool Method
list-devices GET
get-device GET

Groups (11)

Tool Method Risk
list-groups GET
get-group GET
list-group-members GET
list-group-owners GET
create-group POST medium
update-group PATCH medium
delete-group DELETE critical
add-group-member POST medium
remove-group-member DELETE medium
add-group-owner POST high
remove-group-owner DELETE high

remove-group-member, add-group-owner and remove-group-owner run pre-flight guardrails: they refuse on an on-premises-synced group, a member removal on a dynamic group, and the removal of a group's only owner. See docs/ARCHITECTURE.md.

Directory roles & PIM (9)

Tool Method Risk
list-directory-roles GET
list-role-members GET
list-role-assignments GET
list-role-definitions GET
list-pim-eligible-assignments GET
list-pim-active-assignments GET
add-directory-role-member POST critical
delete-role-assignment DELETE critical
remove-directory-role-member DELETE critical

delete-role-assignment is the one to reach for: list-role-assignments with $filter=principalId eq '{user-id}' already returns the assignment id it takes. remove-directory-role-member covers roles activated the legacy way. Both refuse unconditionally on the tenant's last active Global Administrator — an anti-lockout guardrail no parameter overrides.

Administrative units (8)

Tool Method Risk
list-administrative-units GET
get-administrative-unit GET
list-administrative-unit-members GET
create-administrative-unit POST medium
update-administrative-unit PATCH medium
delete-administrative-unit DELETE high
add-administrative-unit-member POST medium
remove-administrative-unit-member DELETE high

Conditional access (3)

Tool Method
list-conditional-access-policies GET
get-conditional-access-policy GET
list-named-locations GET

Applications & app roles (11)

Tool Method Risk
list-applications GET
list-service-principals GET
list-oauth2-grants GET
list-user-app-role-assignments GET
list-sp-app-role-assignments GET
update-application PATCH high
delete-application DELETE critical
update-service-principal PATCH high
delete-oauth2-grant DELETE high
delete-sp-app-role-assignment DELETE high
delete-user-app-role-assignment DELETE high

delete-oauth2-grant is the remediation for an illicit consent grant: list-oauth2-grants identifies it, this revokes it. A grant with consentType: AllPrincipals revokes the app's delegated access for every user at once — check the blast radius first, and pair with revoke-user-sessions, since revoking consent does not end existing sessions.

App credentials & owners (7)

Tool Method
get-application GET
list-application-owners GET
list-app-federated-credentials GET
get-app-federated-credential GET
get-service-principal GET
list-service-principal-owners GET
list-sp-delegated-permissions GET

App management policies (2)

Tool Method
list-app-management-policies GET
get-app-management-policy GET

Organization & domains (4)

Tool Method Risk
get-organization GET
list-domains GET
create-domain POST high
verify-domain POST medium

Licenses (2)

Tool Method
list-subscribed-skus GET
get-subscribed-sku GET

Secure Score (4)

Tool Method
list-secure-scores GET
get-secure-score GET
list-secure-score-controls GET
get-secure-score-control GET

Identity Protection & risk detections (7)

Tool Method
list-risky-users GET
get-risky-user GET
list-risky-user-history GET
list-risky-service-principals GET
get-risky-service-principal GET
list-risk-detections GET
get-risk-detection GET

Security & access policies (13)

Tool Method Risk
get-auth-methods-policy GET
list-auth-method-configs GET
get-auth-method-config GET
get-security-defaults GET
get-admin-consent-policy GET
list-auth-strength-policies GET
get-auth-strength-policy GET
create-auth-strength-policy POST high
update-auth-strength-policy PATCH high
delete-auth-strength-policy DELETE high
get-cross-tenant-access-policy GET
list-cross-tenant-partners GET
change-user-password POST high

Guest user invitations (2)

Tool Method Risk
list-invitations GET
create-invitation POST medium

External identity providers (2)

Tool Method
list-identity-providers GET
get-identity-provider GET

Self-service sign-up (4)

Tool Method
list-b2x-user-flows GET
get-b2x-user-flow GET
list-api-connectors GET
get-api-connector GET

Custom authentication extensions (2)

Tool Method
list-custom-auth-extensions GET
get-custom-auth-extension GET

Exchange message traces (2)

Tool Method
list-message-traces GET
get-message-trace GET

Exchange mailboxes (7)

Tool Method Risk
list-exchange-mailboxes GET
get-exchange-mailbox GET
list-exchange-mailbox-folders GET
get-exchange-mailbox-folder GET
export-exchange-mailbox-items POST medium
update-exchange-mailbox PATCH medium
delete-exchange-mailbox DELETE critical

Threat intelligence - hosts (4)

Tool Method
list-threat-intel-hosts GET
get-threat-intel-host GET
get-threat-intel-host-whois GET
list-threat-intel-host-pairs GET

Threat intelligence - articles & profiles (6)

Tool Method
list-threat-intel-articles GET
get-threat-intel-article GET
list-threat-intel-article-indicators GET
list-threat-intel-profiles GET
get-threat-intel-profile GET
list-threat-intel-profile-indicators GET

Threat intelligence - vulnerabilities & WHOIS (4)

Tool Method
list-threat-intel-vulnerabilities GET
get-threat-intel-vulnerability GET
list-threat-intel-whois-records GET
get-threat-intel-whois-record GET

Threat intelligence - infrastructure (2)

Tool Method
list-threat-intel-host-components GET
list-threat-intel-ssl-certs GET

Managed devices (8)

Tool Method Risk
list-managed-devices GET
get-managed-devices-by-names GET
get-managed-device GET
get-windows-protection-state GET
list-device-compliance-states GET
list-device-configuration-states GET
get-managed-device-overview GET
delete-managed-device DELETE critical

Compliance policies (5)

Tool Method
list-compliance-policies GET
get-compliance-policy GET
list-compliance-policy-device-statuses GET
get-compliance-policy-status-overview GET
get-compliance-state-summary GET

Device configurations (4)

Tool Method
list-device-configurations GET
get-device-configuration GET
get-device-configuration-status-overview GET
list-device-configuration-device-statuses GET

Settings catalog & Endpoint security (6)

Settings catalog policies, including every modern Endpoint security policy (Disk encryption / BitLocker, Antivirus, Firewall, Attack surface reduction, EDR, Account protection). Targets Graph beta — configurationPolicies has no v1.0 equivalent. The two report actions are POSTs that only read; they need --allow-writes like the other Intune reports.

Tool Method Risk
list-configuration-policies GET
get-configuration-policy GET
list-configuration-policy-settings GET
list-configuration-policy-templates GET
get-configuration-policy-device-status POST low
get-configuration-policy-device-summary POST low

Endpoint security intents (legacy templates) (4)

Template-based Endpoint security policies created before the move to the Settings catalog. Targets Graph beta. An Endpoint security audit must cover these and the Settings catalog both.

Tool Method
list-intents GET
get-intent GET
list-intent-device-states GET
list-intent-templates GET

Device encryption (1)

Intune encryption report: readiness, state, TPM version and the BitLocker / FileVault policies that reached each device. Targets Graph beta.

Tool Method
list-managed-device-encryption-states GET

Windows Update profiles (3)

Feature and quality update profiles, which override the deferrals of a device's Windows Update for Business ring (rings themselves are device configurations). Targets Graph beta.

Tool Method
list-windows-feature-update-profiles GET
list-windows-quality-update-profiles GET
list-windows-quality-update-policies GET

macOS Platform Scripts (6)

Intune shell scripts deployed to managed macOS devices. Targets Graph beta (/beta/deviceManagement/deviceShellScripts) — Microsoft has never promoted this endpoint to v1.0. Requires DeviceManagementScripts.ReadWrite.All.

Tool Method Risk
list-device-shell-scripts GET
get-device-shell-script GET
create-device-shell-script POST medium
update-device-shell-script PATCH medium
delete-device-shell-script DELETE high
assign-device-shell-script POST medium

Notes:

  • scriptContent is strict base64 (not URL-safe) of a script with LF line endings — CRLF will break execution on Macs.
  • runAsAccount=user is required for scripts that interact with the user session (e.g. osascript touching System Events).
  • assign-device-shell-script REPLACES all existing assignments — it is not additive. To add a group without removing others, first GET the current assignments, append the new target, then POST the full merged list.
  • By default get-device-shell-script does not return scriptContent; pass $select=id,displayName,scriptContent,... to fetch the base64 body.

Intune Remediations / Proactive Remediations (8)

…

Releases

Recent versions

All releases ↗
  1. v0.17.0
  2. v0.16.0
  3. v0.15.1
  4. v0.15.0
  5. v0.14.0
  6. v0.13.0