entraadm MCP

Official registry Security

MCP server for Microsoft Entra ID sign-in and audit-log triage (read-only by default)

Install

Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).

PYPI package entraadm-mcp
Claude Code
claude mcp add entraadm-mcp -- uvx entraadm-mcp==1.8.1
JSON configuration (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "entraadm-mcp": {
            "command": "uvx",
            "args": [
                "entraadm-mcp==1.8.1"
            ]
        }
    }
}

Documentation

From the project's README on GitHub, refreshed weekly. Links open on GitHub.

Contents
  1. entraadm-mcp
  2. Why this instead of the official Microsoft MCP Server for Enterprise
  3. Tools
  4. Auth model
  5. Setup
  6. Configuration
  7. Usage
  8. Notes
  9. Development
  10. Releasing
  11. License

entraadm-mcp

English | 日本語

MCP server for Microsoft Entra ID sign-in and audit-log triage, plus the two Azure-side questions a morning patrol asks with the same credential: are our Azure VMs backed up, and is Microsoft 365 itself degraded right now. Read-only.

Why this instead of the official Microsoft MCP Server for Enterprise

Microsoft ships an official MCP Server for Enterprise for Entra ID data. It is a good fit for an interactive admin at a keyboard, and is not a fit for an unattended triage bot:

  • Delegated auth only. The official server does not support app-only (client credentials) auth, so it cannot run headless behind a service account. entraadm-mcp is built for that case: app-only in production, with a delegated (az login) fallback for local development.
  • A general-purpose Graph query tool, not a fixed tool set. The official server exposes one tool that lets the model construct arbitrary GET/schema-discovery calls against Microsoft Graph. That is flexible for a human, and awkward to put behind an allow-list for an automated triage profile. entraadm-mcp exposes fourteen fixed, read-only tools instead.
  • No AADSTS translation. Sign-in failures come back as raw error codes; triage still needs a lookup table. entraadm-mcp annotates every sign-in failure with what the code actually means.
  • No cross-request aggregation. Microsoft Graph itself cannot filter sign-ins on status/errorCode server-side, and has no built-in password-spray view. signin_failure_stats aggregates client-side and flags IPs with failed sign-ins against many distinct users — the pattern Entra's per-account smart lockout does not catch on its own.

Tools

ToolWhat it answers
health_checkIs Graph reachable, and can this credential read sign-in logs?
get_userIs this account enabled, synced from on-prem, and what are its licenses?
signin_logsWhy did this user's sign-in fail (or succeed), with the AADSTS code translated?
signin_failure_statsTenant-wide failure aggregation: top error codes, users, apps, source IPs, and password-spray suspects
signin_success_statsTenant-wide success aggregation by source IP: IPs shared by several accounts, legacy-auth (SMTP/IMAP) successes — the view that finds a breach
signin_by_ipEvery sign-in from one source IP: who got in from it, who was tried, and when
directory_auditsWho changed what in the directory (block/unblock, attribute edits), and when?
get_user_auth_methodsIs MFA actually registered for this account?
list_subscriptionsWhich Azure subscriptions can this credential see? (ARM)
vm_backup_statusWhich Azure VMs are backed up by Azure Backup, did the last backup succeed, and is any recovery point stale? (ARM)
vm_backup_policiesWhat schedule and retention do the Azure VM backup policies have? (ARM)
vm_activityDid someone restart this Azure VM, or did Azure (host failure, maintenance)? Activity log and Resource Health for a time window (ARM)
m365_service_healthIs a Microsoft 365 service degraded, and which incidents and advisories are open?
daily_briefOne-call summary combining m365_service_health, signin_failure_stats and directory_audits

Every tool is read-only. Write operations (unblocking an account, resetting a password, revoking a session) are out of scope for this server.

The four Azure Resource Manager tools live in an Entra-named server on purpose: they use the same app registration and the same azure-identity credential object (a second token scope, https://management.azure.com/.default), run in the same deployment and are covered by the same health_check. A separate server for these tools would double the operational surface. They are governance reads, not resource management; a subscription the credential has no Reader role on simply does not appear in list_subscriptions.

Auth model

Two auth modes, selected by which environment variables are set:

ModeWhenEnv vars
app-onlyAll three setENTRAADM_TENANT_ID, ENTRAADM_CLIENT_ID, ENTRAADM_CLIENT_SECRET
azure-cliNone set(uses the current az login session)

Setting one or two of the three app-only variables is a configuration error and the server refuses to start, rather than silently falling back to a different auth mode than intended.

Required Graph permissions
Tool(s)PermissionNotes
get_user (base fields)User.Read.All
signin_logs, signin_failure_stats, signin_success_stats, signin_by_ip, directory_audits, get_user's sign_in_activity fieldAuditLog.Read.All (app-only) or the Reports Reader directory role (delegated)
get_user_auth_methodsUserAuthenticationMethod.Read.AllApp-only only; not available under delegated (az login) auth in a typical tenant role assignment
m365_service_health, daily_brief's service_health sectionServiceHealth.Read.AllUnder delegated auth the signed-in user also needs an Entra role that may read service health (for example Service Support Administrator or Global Reader)
Required Azure RBAC
Tool(s)RoleNotes
list_subscriptionsnoneLists whatever the credential can see; an empty list means no role has been granted anywhere yet
vm_backup_status, vm_backup_policies, vm_activityReader on each subscriptionReader is */read and covers every endpoint used. Backup Reader alone is not enough (it has no Microsoft.Compute/virtualMachines/read). Granted to the service principal (app-only) or to the signed-in user (azure-cli)

Azure RBAC is optional: health_check reports ARM reachability and the number of visible subscriptions as an informational arm probe that never changes status, so a deployment used only for Entra triage stays healthy.

A missing permission never crashes a tool. It degrades that tool (or that one field) to {"error": "...", "missing_permission": "..."} with a human-readable explanation of what role or permission is needed, so health_check and every other tool stay usable even before full permissions are granted.

Setup

uv tool install entraadm-mcp
# or
pip install entraadm-mcp

Configuration

Set the three app-only variables for production/unattended use:

export ENTRAADM_TENANT_ID=00000000-0000-0000-0000-000000000000
export ENTRAADM_CLIENT_ID=00000000-0000-0000-0000-000000000000
export ENTRAADM_CLIENT_SECRET=your-client-secret

Or leave all three unset and run az login first for local development.

Optional:

# Default page cap for the log-scanning tools (1-50, default 50).
export ENTRAADM_MAX_PAGES_DEFAULT=50
# Wall-clock budget per tool call in seconds (default 45; 0 disables). A hosted MCP
# client cuts a call off at about 60 s, so a scan stops at the budget and returns
# what it has with capped=true.
export ENTRAADM_DEADLINE=45
# Your own address ranges (NAT egress, offices, labs). Spray suspects inside them are
# listed separately as internal_spray_suspects, labelled with the site.
export ENTRAADM_SITES_INI=/path/to/sites.ini

ENTRAADM_SITES_INI uses the same format as keycloak-mcp's KEYCLOAK_SITES_INI, so one file can serve both (see sites.ini.example). Lookups are longest-prefix. A file that is set but cannot be read makes health_check report degraded, and every IP is then treated as external. An invalid CIDR is reported the same way, but the valid ranges are still used.

Usage

Claude Code (plugin)
/plugin marketplace add shigechika/entraadm-mcp
/plugin install entraadm-mcp@entraadm-mcp
Claude Code (manual)

Add to .mcp.json:

{
  "mcpServers": {
    "entraadm-mcp": {
      "type": "stdio",
      "command": "uvx",
      "args": ["entraadm-mcp"],
      "env": {
        "ENTRAADM_TENANT_ID": "${ENTRAADM_TENANT_ID:-}",
        "ENTRAADM_CLIENT_ID": "${ENTRAADM_CLIENT_ID:-}",
        "ENTRAADM_CLIENT_SECRET": "${ENTRAADM_CLIENT_SECRET:-}"
      }
    }
  }
}
Direct execution
entraadm-mcp
CLI options
OptionEffect
--versionPrint the version and exit
--checkResolve auth, probe Graph reachability and sign-in log access, print a report (plus an informational ARM line), exit 0 (or 1 on config error)

Notes

  • Coverage contract. Every result that walks a paged Graph collection carries a capped boolean when its window was not fully scanned — a partial scan is never reported as if it were exhaustive.
  • found: false is not an error. get_user and get_user_auth_methods answer a nonexistent account with {"found": false, ...}, not an error key — a typo'd userPrincipalName should never look like this server being broken.
  • Retention. Entra ID P1 retains sign-in and directory audit logs for 30 days. A window beyond that returns an empty result, not an error.

Development

uv sync --dev
uv run pytest -v
uv run ruff check .
uv run ruff format --check .
Live smoke test
uv run python scripts/smoke_test.py

Read-only, no payloads printed (tool names/statuses/row counts only), and bounded (small explicit windows/page caps) — nothing here writes to the tenant or scans more than a day of logs.

Releasing

This repository uses release-please driven by Conventional Commits. Merge a feat:/fix: PR to main, and release-please opens (or updates) a release PR; merging that PR tags a release and triggers the publish pipeline (PyPI, MCP Registry).

License

MIT

Frequently asked questions

What is entraadm MCP?

MCP server for Microsoft Entra ID sign-in and audit-log triage (read-only by default)

How do I install entraadm MCP?

It runs on your machine. In Claude Code: claude mcp add entraadm-mcp -- uvx entraadm-mcp==1.8.1. For other clients, paste the JSON configuration from this page into their MCP settings.

Does entraadm MCP need an API key?

Its registry entry lists no required key or secret. Some features may still need an account with the service it connects to.

Is entraadm MCP open source?

Yes. Its code is on GitHub under the MIT license.

Who maintains entraadm MCP?

It is published by shigechika. AI.tn lists it but does not maintain or endorse it.

From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.