You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
622 tools covering security, audit, identity, app credentials, guest users, Exchange, Intune (devices, apps, MAM, reports, 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)
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).
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.
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.
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.
--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)
--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
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 (515)
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 (10)
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
update-user
PATCH
medium
delete-user
DELETE
critical
assign-user-license
POST
medium
reprocess-user-license
POST
low
Devices (2)
Tool
Method
list-devices
GET
get-device
GET
Groups (8)
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
Directory roles & PIM (7)
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
Administrative units (7)
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
Conditional access (3)
Tool
Method
list-conditional-access-policies
GET
get-conditional-access-policy
GET
list-named-locations
GET
Applications & app roles (8)
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
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 (6)
Tool
Method
Risk
list-managed-devices
GET
get-managed-device
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 (3)
Tool
Method
list-device-configurations
GET
get-device-configuration
GET
get-device-configuration-status-overview
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-scriptREPLACES 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 (6)
Paired detection + remediation PowerShell scripts for Windows 10/11 Azure AD joined devices. Targets Graph beta (/beta/deviceManagement/deviceHealthScripts). Requires DeviceManagementScripts.ReadWrite.All.
Tool
Method
Risk
list-device-health-scripts
GET
get-device-health-script
GET
create-device-health-script
POST
medium
update-device-health-script
PATCH
medium
delete-device-health-script
DELETE
high
assign-device-health-script
POST
medium
Notes:
Both detectionScriptContent and remediationScriptContent are base64-encoded PowerShell — UTF-8 encoded scripts before base64.
Detection script returns exit code 0 (compliant) or 1 (needs remediation). The remediation script only runs when detection returns 1.
assign-device-health-scriptREPLACES all existing assignments — schedules can be daily / hourly / run-once. Set runRemediationScript: false for detect-only deployments.
By default get-device-health-script does not return the script bodies; pass $select=id,displayName,detectionScriptContent,remediationScriptContent,....
Modern replacement for deviceShellScripts for Windows "verify + fix" use cases (CIS hardening, agent install verification, service state).
Assignment filters (5)
Dynamic membership filters that scope policy/app assignments to a sub-set of an Entra group. Targets Graph beta (/beta/deviceManagement/assignmentFilters). Requires DeviceManagementConfiguration.ReadWrite.All.
Tool
Method
Risk
list-assignment-filters
GET
get-assignment-filter
GET
create-assignment-filter
POST
medium
update-assignment-filter
PATCH
medium
delete-assignment-filter
DELETE
high
Notes:
Rule syntax is KQL-like on device properties — example: (device.osVersion -startsWith "14") for macOS Sonoma only, (device.deviceOwnership -eq "Corporate") for corporate-owned devices.
Operators: -eq, -ne, -startsWith, -contains, -in, -matches, joined by -and / -or.
Filters are referenced by deviceConfigurations / mobileApps / deviceCompliancePolicies assignments (not by users — you target the assignment to a group, then add a filter to narrow it).
assignmentFilterManagementType: devices for device-scoped assignments, apps for app-scoped (some properties differ).
Deleting a filter that is in use will silently fall the dependent assignments back to "all members of the group" — audit assignments before deleting.
macOS custom attribute shell scripts (6)
Intune shell scripts whose STDOUT is stored as a named custom attribute on each device — useful for surfacing inventory data (FileVault, Gatekeeper, encryption flags, custom markers) and driving dynamic group filters. Targets Graph beta (/beta/deviceManagement/deviceCustomAttributeShellScripts). Requires DeviceManagementScripts.ReadWrite.All.
Tool
Method
Risk
list-device-custom-attribute-shell-scripts
GET
get-device-custom-attribute-shell-script
GET
create-device-custom-attribute-shell-script
POST
medium
update-device-custom-attribute-shell-script
PATCH
medium
delete-device-custom-attribute-shell-script
DELETE
high
assign-device-custom-attribute-shell-script
POST
medium
Notes:
The script's STDOUT becomes the value stored under customAttributeName on each device.
customAttributeType controls how Intune parses STDOUT: integer, string, or dateTime (ISO 8601).
scriptContent is strict base64 of a script with LF line endings — CRLF breaks execution on Macs.
Changing customAttributeName or customAttributeType after deployment breaks downstream dynamic groups and assignment filters that reference the previous key — audit references first.
Deleting a script does NOT clear previously-collected attribute values from device records.
Windows PowerShell scripts (deviceManagementScripts) (6)
One-shot PowerShell scripts deployed to managed Windows 10/11 devices. Runs once per device per assignment, retries on failure. For detect-and-fix patterns use deviceHealthScripts (Remediations) instead. Targets Graph beta (/beta/deviceManagement/deviceManagementScripts). Requires DeviceManagementScripts.ReadWrite.All.
Tool
Method
Risk
list-device-management-scripts
GET
get-device-management-script
GET
create-device-management-script
POST
medium
update-device-management-script
PATCH
medium
delete-device-management-script
DELETE
high
assign-device-management-script
POST
medium
Notes:
scriptContent is base64-encoded UTF-8 PowerShell.
Runs ONCE per device on the next Intune Management Extension sync after assignment — does NOT re-run after successful execution (use deviceHealthScripts for repeating patterns).
Updating scriptContent does NOT re-run on devices that already succeeded; delete + recreate to force re-execution.
enforceSignatureCheck=true requires code-signed scripts (recommended for prod).
runAs32Bit=true forces 32-bit PowerShell on 64-bit Windows (rarely needed).
Windows custom compliance scripts (deviceComplianceScripts) (6)
PowerShell scripts that emit a JSON object on STDOUT evaluated against rules declared on an associated windows10CustomComplianceConfiguration policy — for organization-specific compliance signals beyond the built-in BitLocker / Defender / firewall checks. Targets Graph beta (/beta/deviceManagement/deviceComplianceScripts). Requires DeviceManagementScripts.ReadWrite.All.
Tool
Method
Risk
list-device-compliance-scripts
GET
get-device-compliance-script
GET
create-device-compliance-script
POST
medium
update-device-compliance-script
PATCH
medium
delete-device-compliance-script
DELETE
high
assign-device-compliance-script
POST
medium
Notes:
detectionScriptContent must emit a JSON object on STDOUT (e.g. ConvertTo-Json -Compress @{BitLockerEnabled=$true;TpmReady=$true}).
The script alone has no compliance effect — you must also author a windows10CustomComplianceConfiguration policy with matching rules.
Changing the JSON keys without updating the linked policy's rules silently breaks compliance evaluation.
Deleting a script in use causes referencing compliance policies to fail evaluation on next device check-in.
Assignment shape reuses deviceHealthScriptAssignment (set runRemediationScript: false since compliance scripts have no remediation pairing).
Full surface coverage of Microsoft Defender for Identity (DfI) administration via Graph: sensors, sensor candidates (auto-discovery), sensor migration to unified Defender XDR architecture, identity accounts (with break-glass invokeAction for AD on-prem / Okta), audit policy enforcement, and health alerts. Most endpoints are Graph v1.0; sensorMigration is beta-only.
Tool
Method
Risk
list-identity-health-issues
GET
get-identity-health-issue
GET
list-sensor-health-issues
GET
get-sensor-health-issue
GET
list-identity-sensors
GET
get-identity-sensor
GET
update-identity-sensor
PATCH
medium
get-sensor-deployment-access-key
GET
get-sensor-deployment-package-uri
GET
regenerate-sensor-deployment-access-key
POST
high
list-sensor-candidates
GET
get-sensor-candidate
GET
get-sensor-candidate-activation-config
GET
update-sensor-candidate-activation-config
PATCH
medium
activate-sensor-candidates
POST
medium
list-sensor-migrations
GET
get-sensor-migration
GET
migrate-sensors
POST
high
get-identity-security-settings
GET
get-auto-auditing-config
GET
update-auto-auditing-config
PATCH
medium
list-identity-accounts
GET
get-identity-account
GET
invoke-identity-account-action
POST
critical
Notes:
invoke-identity-account-action is the highest-impact write — performs identity-response actions (disable, enable, forcePasswordReset, revokeAllSessions, requireUserToSignInAgain, markUserAsCompromised) on accounts in their source system (AD on-prem, Okta). Action / provider compatibility: disable/enable for AD + Okta, forcePasswordReset for AD only, revokeAllSessions for Okta only.
regenerate-sensor-deployment-access-key invalidates the previous key immediately — coordinate with anyone rolling out new sensors before calling.
migrate-sensors restarts the sensor service on the target DC during migration to unified Defender XDR — brief capture gap (~minutes). Schedule maintenance windows for production DCs. Beta-only.
activate-sensor-candidates triggers sensor installation on detected hosts using the deployment access key flow. Verify with get-sensor-candidate first — wrong serverId installs on the wrong host.
update-auto-auditing-config with enabled=true makes DfI enforce the recommended Windows advanced audit policies on every sensor host (revert local admin overrides on next heartbeat) — recommended for production.
New Graph permissions required since v0.10.0 / 0.11.1 (must be consented on the app registration):
The --allowed-clients flag is mandatory in HTTP mode. It validates incoming bearer tokens against Microsoft's JWKS endpoint (signature verification, audience, tenant, and client ID checks).
Container App using the UAMI, with MS365_ADMIN_MCP_KEYVAULT_URL wired to the vault
MY_OID=$(az ad signed-in-user show --query id -o tsv)
az deployment group create \
--resource-group rg-mcp-admin \
--template-file infra/main.bicep \
--parameters baseName=ms365mcpprod \
containerImage=your-acr.azurecr.io/ms365-admin-mcp:latest \
kvAdminObjectIds="['$MY_OID']"
Seed the vault with ms365-admin-mcp-{client-id,tenant-id,client-secret} after deploy — see docs/HTTP_DEPLOYMENT.md.
Development
npm run dev # Run with tsx (hot reload)
npm run generate # Download OpenAPI spec + generate client
npm run build # Build with tsup
npm run test# Run vitest
npm run lint # ESLint
npm run format # Prettier
npm run verify # Full pipeline (generate + lint + format + build + test)
npm run inspector # MCP Inspector for interactive testing
Adding a new tool
Add the endpoint entry in src/endpoints.json
Run npm run generate to regenerate the client
The tool is automatically registered at startup by registerGraphTools()
Run npm run verify to validate
Security
Read-only by default -- mutations require --allow-writes
Risk levels on write tools (critical/high/medium/low) with LLM-visible warnings
JWT signature verification via Microsoft JWKS (RS256) in HTTP mode
Mandatory authentication in HTTP mode (--allowed-clients required)
Rate limiting (100 req/min) on the MCP endpoint
Security headers (nosniff, DENY, no-store, CSP)
Non-root Docker user
Sensitive data redacted from logs
Acknowledgments
This project would not exist without Softeria/ms-365-mcp-server. Their work served as the foundation and inspiration for this server — in particular:
The endpoint-driven architecture (endpoints.json + auto-registration via graph-tools.ts)
The OpenAPI-based code generation pipeline (npm run generate → trimmed Graph spec + Zodios client)
The CLI ergonomics (presets, --list-tools, --list-permissions, --verify-login, MCP Inspector integration)
The read-only-by-default + --allow-writes safety model
This server diverges from Softeria's by targeting application permissions (client credentials via MSAL ConfidentialClientApplication) rather than delegated permissions, and by adding admin-specific capabilities — risk classification on write tools, JWT validation via Microsoft JWKS for HTTP mode, Azure Key Vault integration, and incident-response tooling.
Sincere thanks to the Softeria team and contributors for making their work available under an open license, and for setting a high bar for MCP server design in the Microsoft 365 ecosystem.
{ "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}", }, }, }, }