# entraadm MCP (pypi · entraadm-mcp)

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

- Trust score: 76/100 (medium)
- Change this week: +4
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-20

## Components

- pypi · `entraadm-mcp`: 76/100 (this document), [markdown](https://verifymcp.io/servers/shigechika-entraadm-mcp/entraadm-mcp.md), [page](https://verifymcp.io/servers/shigechika-entraadm-mcp/entraadm-mcp)

## Channel facts

- Registry: `pypi`
- Package: `entraadm-mcp`
- Version: `0.1.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-20.

- **Supply Chain Security**: 100/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs setuptools.build_meta at install time, a recognised native-build step with no shell scripting around it.
  - 0 of 40 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 32/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - License check failed: no license is declared.
  - Actively maintained (last published 27 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 63/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 2342 tokens (~334/item across 7 items; 7 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 90/100
  - Stability observed for 27 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 67/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 7 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 7 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the entraadm MCP server?

entraadm MCP runs locally as a PyPI package, launched with uvx entraadm-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add shigechika-entraadm-mcp -- uvx entraadm-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "shigechika-entraadm-mcp": {
      "command": "uvx",
      "args": [
        "entraadm-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "shigechika-entraadm-mcp": {
      "command": "uvx",
      "args": [
        "entraadm-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add shigechika-entraadm-mcp -- uvx entraadm-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "shigechika-entraadm-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "entraadm-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add shigechika-entraadm-mcp --command uvx --arg entraadm-mcp
```

### Hermes

```yaml
mcp_servers:
  shigechika-entraadm-mcp:
    command: "uvx"
    args: ["entraadm-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "shigechika-entraadm-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "entraadm-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add shigechika-entraadm-mcp -t stdio -c uvx -a entraadm-mcp
```

### Other

```json
{
  "mcpServers": {
    "shigechika-entraadm-mcp": {
      "command": "uvx",
      "args": [
        "entraadm-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-20 (score 76, +1)

No change was recorded against any check on this day. Stability & Change Management went from 87 to 90. That category is still filling its 30-day observation window: 26 days of observed history at the previous scan, 27 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-18 (score 75, +1)

No change was recorded against any check on this day. Stability & Change Management went from 80 to 83. That category is still filling its 30-day observation window: 24 days of observed history at the previous scan, 25 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-16 (score 74, +1)

No change was recorded against any check on this day. Stability & Change Management went from 73 to 77. That category is still filling its 30-day observation window: 22 days of observed history at the previous scan, 23 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-15 (score 73, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-14 (score 58, −14)

- [security regression] Malware scan: pass → unverified

### 2026-09-11 (score 72, +1)

No change was recorded against any check on this day. Stability & Change Management went from 57 to 60. That category is still filling its 30-day observation window: 17 days of observed history at the previous scan, 18 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-09 (score 71, +1)

No change was recorded against any check on this day. Stability & Change Management went from 50 to 53. That category is still filling its 30-day observation window: 15 days of observed history at the previous scan, 16 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-07 (score 70, +1)

No change was recorded against any check on this day. Stability & Change Management went from 43 to 47. That category is still filling its 30-day observation window: 13 days of observed history at the previous scan, 14 at this one. The score rises as the window fills, whether or not the server changes.

## MCP tools (7)

### `health_check` (~244 tokens)

Fleet-standard health probe: service/version/status plus two independent Graph probes.

\``graph`` confirms Microsoft Graph is reachable at all (``GET /users``
with ``$top=1`` -- needs only ``User.Read.All``, the minimum permission
every deployment of this server needs anyway). ``signin_probe`` additionally confirms the current
credential can read sign-in logs -- the permission every other tool here
except ``get_user`` depends on. Both probes always run, independently of
each other: a tenant that has AuditLog.Read.All but not (yet) the
baseline User.Read.All would otherwise have this report "Graph
unreachable" -- a fabricated diagnosis, since Graph plainly *is*
reachable if the other probe succeeds. ``status`` is derived from the
two outcomes: ``healthy`` when both succeed, ``degraded`` when exactly
one does (Graph is reachable but some permission is missing), ``error``
only when neither does.

Read-only. Always returns the same keys regardless of outcome (``detail``
is null on success, a translated message on failure), so a caller never
has to branch on which keys are present.

### `get_user` (~441 tokens)

One account's identity/lifecycle state -- the first thing to check on any triage report.

\``account_enabled=false`` means the account itself is the whole story;
stop there. A stale ``last_password_change_date_time`` alongside a fresh
"wrong password" complaint (AADSTS50126 in ``signin_logs``) is the most
common on-the-ground pattern: the password changed or expired somewhere,
and a cached credential on one device is now stale.
\``on_premises_sync_enabled=true`` means this account is synced from an
on-premises directory (Entra Connect) -- Entra is a downstream copy of
its password via Password Hash Sync, not the source of truth.
\``licenses`` names are resolved from the tenant's SKU catalog
(``/subscribedSkus``, page budget from ``ENTRAADM_MAX_PAGES_DEFAULT``);
\``licenses_capped: true`` appears only when that scan was cut short
before resolving one of this account's own licenses -- when present,
one or more ``licenses`` entries is a raw skuId rather than a friendly
name.

\``sign_in_activity`` needs an additional Graph read (AuditLog.Read.All
application permission, or -- for azure-cli auth -- the Reports Reader
directory role) beyond what the rest of this tool needs. If that
permission is missing, every other field above still returns and
\``sign_in_activity`` alone degrades to ``{"error": ...,
"missing_permission": "AuditLog.Read.All"}``.

A nonexistent account is a normal answer, not a tool failure: the result
is ``{"found": false, "user_principal_name": upn}`` rather than an
\``error`` key, so a typo'd UPN in a triage report cannot be mistaken for
this tool being broken.

Read-only (User.Read.All application permission, or an equivalent
delegated read). Requires an exact userPrincipalName, not a display name
or partial match.

Args:
    upn: The account's userPrincipalName, e.g. "user@example.edu".

Input parameters:

- `upn` (string, required)

### `signin_logs` (~412 tokens)

One user's recent sign-in events, AADSTS-annotated.

The most direct answer to "why can't this person log in": each entry's
\``error_code_meaning`` translates the raw AADSTS code (e.g. 50126 ->
"invalid credentials (wrong password)") so triage rarely needs a second
lookup. ``result`` filters client-side after the Graph fetch (Graph
cannot filter sign-ins on status/errorCode server-side): "failure" (the
default) keeps only failed attempts, "success" keeps only clean ones,
"all" keeps everything.

Because the filter is client-side, this walks pages until it has
collected ``top`` matching entries or exhausts ``max_pages`` -- a mostly-
successful user can otherwise mean paging through hundreds of rows to
find a handful of failures. ``capped=true`` means the page budget ran out
(or ``top`` was reached) before the whole window was scanned; a low match
count alongside ``capped=true`` is evidence of "no more found within the
budget", not "no more exist".

Read-only (AuditLog.Read.All application permission, or -- for azure-cli
auth -- the Reports Reader directory role). Entra ID P1 retains sign-in
logs for 30 days; ``hours`` beyond that returns an empty result, not an
error.

Args:
    user: The account's userPrincipalName.
    hours: How far back to look, clamped to [1, 720] (30 days).
    result: "failure" (default), "success", or "all".
    top: Maximum matching entries to return, clamped to [1, 500].
    max_pages: Page budget for the client-side filter walk (default: ENTRAADM_MAX_PAGES_DEFAULT).

Input parameters:

- `hours` (integer)
- `max_pages`
- `result` (string)
- `top` (integer)
- `user` (string, required)

### `signin_failure_stats` (~339 tokens)

Tenant-wide sign-in failure aggregation -- the Entra ID counterpart to the RADIUS failure patrol.

Aggregates failed sign-ins across the whole tenant into four views: top
AADSTS error codes (with the same meaning annotations as
\``signin_logs``), top failing users, top applications, and top source
IPs. ``spray_suspects`` flags any IP with failed sign-ins against 5 or
more distinct users -- Entra's smart lockout is per-account, so a
low-and-slow password spray from one IP across many accounts does not
trip it the way a brute force against one account does; this is the
observation a per-account view cannot make on its own. This mirrors the
KeyCloak-side spray detection this fleet already relies on; neither the
official Microsoft MCP Server for Enterprise nor Graph itself offers this
aggregation.

Read-only (AuditLog.Read.All application permission, or -- for azure-cli
auth -- the Reports Reader directory role). Graph cannot filter sign-ins
on status/errorCode server-side, so this walks up to ``max_pages`` of the
full sign-in log for the window and aggregates client-side --
\``capped=true`` means the page budget ran out before the window was
fully scanned, so the counts below are a sample of the window, not a
census of it.

Args:
    hours: How far back to look, clamped to [1, 720] (30 days).
    max_pages: Page budget (default: ENTRAADM_MAX_PAGES_DEFAULT).

Input parameters:

- `hours` (integer)
- `max_pages`

### `directory_audits` (~416 tokens)

Who did what to the directory, and when -- the operator-side counterpart to signin_logs.

Every admin action against a user object (block/unblock, password reset,
role assignment, attribute edits) appears here, naming the actor
(``initiated_by``) and the affected object(s) (``target_resources``).
This is the record a manual "unblock and reset" intervention -- like the
one that closed the 2026-08-21 case this server exists to shorten --
leaves behind; it is how a later triage can tell "already handled by a
human" from "still open".

\``user``, when given, matches audits where that account is either the
initiator or a target resource. Graph's directoryAudits endpoint only
supports server-side ``$filter`` on the *initiator*
(``initiatedBy/user/userPrincipalName``), not on ``targetResources``, so
this fetches the full time window and matches both sides client-side --
a window with many unrelated admin actions can need a larger
\``max_pages`` budget than ``signin_logs``/``signin_failure_stats`` to
find one specific user's audits; ``capped=true`` warns when that budget
ran out before the window was fully scanned.

Read-only (AuditLog.Read.All application permission, or -- for azure-cli
auth -- the Reports Reader directory role). Entra ID retains directory
audit logs for 30 days, same as sign-in logs.

Args:
    user: Restrict to audits naming this userPrincipalName as actor or target (default: all).
    hours: How far back to look, clamped to [1, 720] (30 days).
    top: Maximum records to return, clamped to [1, 500].
    max_pages: Page budget (default: ENTRAADM_MAX_PAGES_DEFAULT).

Input parameters:

- `hours` (integer)
- `max_pages`
- `top` (integer)
- `user`

### `get_user_auth_methods` (~242 tokens)

Registered authentication methods for one account -- is MFA actually set up?

\``mfa_registered`` answers "would this account survive a password-spray
hit": True iff at least one non-password method is registered
(Authenticator app, phone, FIDO2 security key, Windows Hello, a
temporary access pass, software OATH token, or a platform
credential/passkey). ``password`` itself is excluded from that count --
every account has one, so its presence alone says nothing about MFA
coverage.

A nonexistent account is a normal answer, not a tool failure: the result
is ``{"found": false, "user_principal_name": upn}`` rather than an
\``error`` key, matching ``get_user``'s contract.

Read-only (UserAuthenticationMethod.Read.All application permission).
This endpoint is app-only only: it is not exposed to delegated
(azure-cli) auth under this tenant's current role assignment, so it
degrades to a permission error under azure-cli auth even when other
tools work.

Args:
    upn: The account's userPrincipalName.

Input parameters:

- `upn` (string, required)

### `daily_brief` (~248 tokens)

One-call morning-patrol summary: sign-in failures, spray suspects, and admin actions.

Combines ``signin_failure_stats`` and ``directory_audits`` into one
result with a compact ``summary`` on top, matching the shape of this
fleet's other ``daily_brief`` tools. A permission failure in one section
degrades only that section's contribution to ``summary`` -- the other
section still returns in full.

Runs both sections synchronously in one tool call, unlike the sibling
gwsadm-mcp's job+poll ``daily_brief``. If this proves too slow for a
tenant's sign-in volume against the client's tool-call timeout, port
that job+poll pattern here (tracked in this repo's CLAUDE.md Roadmap).

Args:
    hours: How far back to look, clamped to [1, 720] (30 days).
    max_pages: Page budget passed to both sections (default: ENTRAADM_MAX_PAGES_DEFAULT).
    samples: Reserved for a future drill-down sample size; currently unused.

Input parameters:

- `hours` (integer)
- `max_pages`
- `samples` (integer)

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/shigechika-entraadm-mcp/entraadm-mcp#diagnostics

## Score history

- 2026-09-20: 76
- 2026-09-19: 75
- 2026-09-18: 75
- 2026-09-17: 74
- 2026-09-16: 74
- 2026-09-15: 73
- 2026-09-14: 58
- 2026-09-13: 72
- 2026-09-12: 72
- 2026-09-11: 72
- 2026-09-10: 71
- 2026-09-09: 71
- 2026-09-08: 70
- 2026-09-07: 70
- 2026-09-06: 69
- 2026-09-05: 69
- 2026-09-04: 68
- 2026-09-03: 68
- 2026-09-02: 67
- 2026-09-01: 67
- 2026-08-31: 66
- 2026-08-30: 63
- 2026-08-29: 63
- 2026-08-28: 63
- 2026-08-27: 63
- 2026-08-26: 63
- 2026-08-25: 61
- 2026-08-24: 46

## Common questions

### What is the entraadm MCP server?

entraadm MCP is listed in the public MCP registry as io.github.shigechika/entraadm-mcp. MCP server for Microsoft Entra ID sign-in and audit-log triage (read-only). This page covers its PyPI package (entraadm-mcp).

### Is the entraadm MCP server safe to use?

entraadm MCP scores 76 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the entraadm MCP server expose?

entraadm MCP exposes 7 tools: health_check, get_user, signin_logs, signin_failure_stats, directory_audits, and 2 more. Their descriptions and schemas cost roughly 2,342 tokens of context every time the server is loaded.

### Is the entraadm MCP server still maintained?

entraadm MCP is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- PyPI project: https://pypi.org/project/entraadm-mcp/
- Socket report: https://socket.dev/pypi/package/entraadm-mcp
- Repository: https://github.com/shigechika/entraadm-mcp
- Changelog RSS feed: https://verifymcp.io/servers/shigechika-entraadm-mcp/entraadm-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/shigechika-entraadm-mcp/entraadm-mcp.json
- HTML version of this page: https://verifymcp.io/servers/shigechika-entraadm-mcp/entraadm-mcp
