关于 entraadm MCP
entraadm MCP 面向 Microsoft Entra ID 管理与无人值守分诊,汇总登录和审计日志,并提供 Azure VM 备份及 Microsoft 365 服务状态查询。工具默认只读;会话撤销需显式启用。
主要功能
- 01翻译登录失败代码并聚合失败统计
- 02识别密码喷洒及可疑账户迹象
- 03查询目录审计和用户 MFA 方法
- 04查看 Azure VM 备份、策略及活动
- 05检查 Microsoft 365 服务健康状况
- 06可选撤销单个账户的登录会话
适用场景
- 01调查账户登录失败与密码喷洒
- 02排查可能遭入侵的账户和来源 IP
- 03巡查目录变更与 MFA 注册情况
- 04汇总 VM 备份及 Microsoft 365 事件
MCP 相关
该 MCP 服务向客户端提供固定的 Entra ID、Azure Resource Manager 和 Microsoft 365 查询工具。工具默认只读;仅在设置 ENTRAADM_ENABLE_REVOKE_SESSIONS=1 后,才注册撤销登录会话的写入工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
9收录的工具列表 · 更新于 2 天前
此工具无需参数。
详细介绍
entraadm-mcp
English | 日本語
用于 Microsoft Entra ID 登录和审核日志分类处理的 MCP 服务,还能用同一凭据回答早间巡查时会问的两个 Azure 相关问题:我们的 Azure VM 是否已备份?Microsoft 365 当前是否出现故障?服务仅提供只读操作,只有一个可选工具例外,它可以将遭到入侵的帐户从所有位置注销。
为什么不选择 Microsoft 官方的 Microsoft MCP Server for Enterprise
Microsoft 为 Entra ID 数据提供了官方 MCP Server for Enterprise。 它适合坐在键盘前进行交互式管理的管理员,却不适合无人值守的分类处理机器人:
- 仅支持委托式身份验证。 官方服务不支持仅应用身份验证(客户端凭据),因此无法在服务帐户后以无头模式运行。entraadm-mcp 专为这种场景构建:生产环境使用仅应用身份验证,本地开发时可回退到委托式身份验证(
az login)。 - 通用 Graph 查询工具,而非固定工具集。 官方服务提供一个工具,允许模型针对 Microsoft Graph 构造任意
GET/架构发现调用。这对人工使用很灵活,但难以为自动分类处理配置文件设置允许列表。entraadm-mcp 则提供十五个固定的只读工具(另有一个可选写入工具,见下文)。 - 不翻译 AADSTS 错误。 登录失败会以原始错误代码返回;分类处理仍需查阅对照表。entraadm-mcp 会为每次登录失败标注代码的实际含义。
- 不支持跨请求聚合。 Microsoft Graph 本身无法在服务器端按
status/errorCode筛选登录记录,也没有内置的密码喷洒攻击视图。signin_failure_stats会在客户端进行聚合,并标记针对多个不同用户发生登录失败的 IP —— 这是 Entra 的按帐户智能锁定机制本身无法检测到的模式。
工具
| 工具 | 回答的问题 |
|---|---|
health_check | Graph 是否可访问?此凭据能否读取登录日志? |
get_user | 此账户是否已启用、是否从本地环境同步,以及它有哪些许可证? |
signin_logs | 此用户登录失败(或成功)的原因是什么?AADSTS 代码已翻译。 |
signin_failure_stats | 租户范围内的失败汇总:错误代码、用户、应用、源 IP 排名,以及密码喷洒攻击嫌疑对象 |
signin_success_stats | 按源 IP 汇总租户范围内的成功登录:多个账户共用的 IP、通过旧式身份验证(SMTP/IMAP)登录成功的情况——可用于发现安全漏洞的视图 |
compromise_suspects | 哪些账户可能已被接管:向多个账户发起密码喷洒攻击并成功登录部分账户的外部 IP(spray_breaches);来自用户所在国家以外的成功登录(foreign_successes,通过旧式协议登录时风险较高);以及租户拥有 Entra ID P2 时,Microsoft 标记的风险用户 |
signin_by_ip | 来自某个源 IP 的所有登录:谁从该 IP 登录成功、尝试登录过哪些账户,以及登录时间 |
directory_audits | 谁在何时更改了目录中的哪些内容(阻止/解除阻止、属性编辑)? |
get_user_auth_methods | 此账户是否实际注册了 MFA? |
list_subscriptions | 此凭据可以查看哪些 Azure 订阅?(ARM) |
vm_backup_status | 哪些 Azure VM 由 Azure Backup 备份?最近一次备份是否成功?是否有过期的恢复点?(ARM) |
vm_backup_policies | Azure VM 备份策略的计划和保留设置是什么?(ARM) |
vm_activity | 是有人重启了此 Azure VM,还是 Azure 导致了重启(主机故障、维护)?查看指定时间范围内的活动日志和资源运行状况(ARM) |
m365_service_health | Microsoft 365 服务是否降级?有哪些未解决的事件和公告? |
daily_brief | 一次调用即可汇总 m365_service_health、signin_failure_stats、directory_audits 和 compromise_suspects(计数及排名前 5 项) |
以上所有工具均为只读。另有一个会更改状态的工具,默认关闭:
| 工具 | 功能 |
|---|---|
revoke_sign_in_sessions | 在所有位置将一个账户注销(Graph revokeSignInSessions:刷新令牌和会话 Cookie 均会失效)。用于确认账户已遭入侵的情况。仅当 ENTRAADM_ENABLE_REVOKE_SESSIONS=1 时才会注册 |
此工具会先按精确的 userPrincipalName 查找账户,并拒绝处理来宾账户。
每个结果都包含相同的键,包括 revoked 和 not_covered:它不会禁用账户、重置密码或移除 MFA 方法;已颁发的访问令牌会继续有效,直到过期(通常约一小时)。当 Graph 确认已撤销时,revoked 为 true;未执行任何操作时(拒绝处理、请求发送前超时、Graph 返回 4xx),为 false;结果不确定时(网络错误导致响应丢失、重试后仍收到 5xx、请求发送后超时、成功响应无法读取),为 null。此时再次调用是安全的,因为撤销操作具有幂等性。对于未经过独立审批流程的部署(例如共享网关),请勿设置此开关——这样该工具就不会出现在 tools/list 中。解除账户阻止和重置密码不在此工具的范围内。
这四个 Azure Resource Manager 工具特意放在一个以 Entra 命名的服务中:它们使用相同的应用注册和 azure-identity 凭据对象(第二个令牌范围 https://management.azure.com/.default),在同一部署中运行,并由同一个 health_check 检查。为这些工具单独设置一个服务会增加一倍的运维负担。它们用于治理查询,而非资源管理;对于凭据没有 Reader 角色的订阅,list_subscriptions 不会显示该订阅。
身份验证模式
根据设置的环境变量选择两种身份验证模式:
| 模式 | 条件 | 环境变量 |
|---|---|---|
| 仅应用 | 三个变量均已设置 | ENTRAADM_TENANT_ID、ENTRAADM_CLIENT_ID、ENTRAADM_CLIENT_SECRET |
| azure-cli | 均未设置 | (使用当前的 az login 会话) |
仅设置三个仅应用变量中的一个或两个属于配置错误,服务会拒绝启动,而不会悄然回退到非预期的其他身份验证模式。
必需的 Graph 权限
| 工具 | 权限 | 备注 |
|---|---|---|
get_user(基本字段) | User.Read.All | |
signin_logs、signin_failure_stats、signin_success_stats、compromise_suspects、signin_by_ip、directory_audits、get_user 的 sign_in_activity 字段 | AuditLog.Read.All(仅应用)或 Reports Reader 目录角色(委托) | |
get_user_auth_methods | UserAuthenticationMethod.Read.All | 仅应用;在典型的租户角色分配中,委托(az login)身份验证不可用 |
m365_service_health、daily_brief 的 service_health 部分 | ServiceHealth.Read.All | 使用委托身份验证时,已登录用户还需要一个可读取服务运行状况的 Entra 角色(例如 Service Support Administrator 或 Global Reader) |
compromise_suspects 的 microsoft_risky_users、identity_protection 探测(health_check、daily_brief) | IdentityRiskyUser.Read.All | 可选。Identity Protection 需要 Entra ID P2:如果未获得该许可证,Graph 会返回 403「未获许可」,探测结果会报告 not_licensed;其他内容不受影响 |
revoke_sign_in_sessions(选择启用) | User.RevokeSessions.All(仅应用)或 User Administrator / Helpdesk Administrator 目录角色(委托;对于管理员帐户,需 Privileged Authentication Administrator) | 仅在 ENTRAADM_ENABLE_REVOKE_SESSIONS=1 时启用。这是一项写入权限:仅向需要此工具的部署授予该权限。执行前的帐户查询需要 User.Read.All。如果没有该权限,工具会针对当前使用的身份验证模式返回 missing_permission,且不会进行任何更改 |
所需的 Azure RBAC
| 工具 | 角色 | 备注 |
|---|---|---|
list_subscriptions | 无 | 列出凭据可见的所有订阅;空列表表示尚未在任何位置授予角色 |
vm_backup_status、vm_backup_policies、vm_activity | 每个订阅都需要 Reader | Reader 是 */read,涵盖所有用到的终结点。仅有 Backup Reader 不够(它没有 Microsoft.Compute/virtualMachines/read)。授予服务主体(仅应用模式)或已登录用户(azure-cli) |
Azure RBAC 是可选的:health_check 会将 ARM 可达性和可见订阅数量作为信息性的 arm 探测结果报告,但不会改变 status,因此仅用于 Entra 问题排查的部署仍会保持 healthy。
缺少权限不会导致工具崩溃。相应工具(或单个字段)会降级为 {"error": "...", "missing_permission": "..."},并提供所需角色或权限的人类可读说明,因此即使尚未授予完整权限,health_check 和所有其他工具仍可使用。
Identity Protection(Entra ID P2)。 如果租户已开通此功能,compromise_suspects 会添加 Microsoft 自己的风险判定:通过轻量级的 riskyUsers?$top=1 探测来对每个租户进行分类,结果可能是 licensed、not_licensed(403“未获许可”:没有 Entra ID P2)、no_permission(其他 403:没有 IdentityRiskyUser.Read.All)或 error;licensed 和 not_licensed 会缓存一小时(如果请求返回 200,但行中的 riskLevel: hidden,也表示没有 P2)。此处会探测终结点本身:/subscribedSkus 可能被拒绝访问,而且即使能获取 SKU 列表,仍需将其映射到 P2。health_check 会按租户报告此状态,但不会改变 status;daily_brief 也会在每个租户的摘要中报告此状态,因此会注意到 P2 开通的那一天。已获许可时:microsoft_risky_users 会列出未解决的高风险用户(atRisk / confirmedCompromised),并单独列出中风险用户,同时标记那些也出现在 spray_breaches / foreign_successes 中的用户。此时,counts 统计所有发现中的不同账户,之后才会截断列表:high 包含此处或 Microsoft 高风险列表中的任何高风险账户;medium 包含此处或 Microsoft 中风险列表中的任何中风险账户,但不包括高风险账户(counts.microsoft_high / microsoft_medium 表示 Microsoft 列表中的数量)。否则,该部分会显示为 {available: false, reason},其他内容不变——切勿将其解读为“没有高风险用户”。
设置
uv tool install entraadm-mcp
# or
pip install entraadm-mcp
配置
生产环境或无人值守使用时,请设置以下三个仅应用模式变量:
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
或者将这三个变量全部留空,并在本地开发时先运行 az login。
可选项:
# 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
# The countries your users sign in from (assigned ISO 3166-1 alpha-2 codes). compromise_suspects
# reports successes from elsewhere; unset or with an invalid code, that list is skipped.
export ENTRAADM_HOME_COUNTRIES=JP
# Register revoke_sign_in_sessions, the one state-changing tool (exactly "1"; anything
# else leaves it off). Also needs the User.RevokeSessions.All permission.
export ENTRAADM_ENABLE_REVOKE_SESSIONS=1
# Serve several tenants from one process (see "Several tenants" below).
export ENTRAADM_CONFIG=/path/to/tenants.ini
ENTRAADM_SITES_INI 的格式与 keycloak-mcp 的 KEYCLOAK_SITES_INI 相同,因此一个文件即可供两者使用(参见 sites.ini.example)。查找时采用最长前缀匹配。若已设置该文件但无法读取,health_check 会报告 degraded,此时每个 IP 都会被视为外部 IP。无效 CIDR 也会以相同方式报告,但仍会使用有效范围。
多个租户
单个进程可以服务多个 Entra 租户,就像 gwsadm-mcp 可以服务多个 Workspace 域一样。将 ENTRAADM_CONFIG 指向一个 INI 文件,并为每个租户设置一个 [tenant.<name>] 部分:
[tenant.staff]
tenant_id = 00000000-0000-0000-0000-000000000001
domains = example.edu
default = true
[tenant.students]
tenant_id = 00000000-0000-0000-0000-000000000002
domains = students.example.edu
; optional: an app registration of its own instead of the shared one
; client_id = 00000000-0000-0000-0000-000000000003
; client_secret_env = ENTRAADM_STUDENTS_CLIENT_SECRET
| 键 | 必填 | 含义 |
|---|---|---|
tenant_id | 是 | 租户 ID(GUID)或其域名(包含句点,例如 contoso.onmicrosoft.com);不接受 common、organizations 和 consumers |
domains | 是 | 以逗号分隔的 UPN 域名列表,将其路由到此租户(精确匹配,不区分大小写) |
default | 多个部分时,需在其中一个部分设置 | 未指定租户的调用所使用的租户;如果只有一个部分,则该部分默认即为默认租户 |
client_id + client_secret_env | 否;两者要么都设置,要么都不设置 | 使用专属应用;client_secret_env 指定存放其密钥的环境变量。切勿将密钥放入文件中 |
未设置 client_id 的区段会复用环境应用(ENTRAADM_CLIENT_ID / | ||
ENTRAADM_CLIENT_SECRET),并从该区段对应的租户请求令牌;如果没有环境应用,则会在该租户中使用 az login。设置 ENTRAADM_CONFIG 时不会使用 ENTRAADM_TENANT_ID。取消设置 ENTRAADM_CONFIG 后,单租户配置会保持不变。 |
要在多个租户间共用一个应用,请将应用注册设为多租户(支持的帐户类型:任何组织目录中的帐户),添加相同的 Graph 应用程序权限,然后让其他每个租户的管理员授予管理员同意:
https://login.microsoftonline.com/<tenant-id>/adminconsent?client_id=<app-id>
如果文件不可读、包含非 [tenant.*] 区段或未知键、缺少 tenant_id 或 domains、tenant_id 既不是 GUID 也不是点分域名、将同一个域名分配给两个租户,或者多个租户中没有默认租户(或有两个默认租户),服务将拒绝启动,且 --check 会失败。--check 会探测每个租户。
路由:
- 接受 UPN 的工具(
get_user、get_user_auth_methods、signin_logs、revoke_sign_in_sessions,以及指定了user时的directory_audits)会在其domains包含该 UPN 域名的租户中运行(精确匹配)。如果没有租户认领该域名,则会拒绝请求,而非引发异常:tenant_configured: false、found: null(未运行查找)以及configured_domains。对于revoke_sign_in_sessions:revoked: false、found: null,不会发送任何内容。如果经常查找此类 UPN,请将<tenant>.onmicrosoft.com列入domains。 get_user、get_user_auth_methods和signin_logs也接受tenant,它优先于 UPN 的域名:适用于*.onmicrosoft.com或#EXT#UPN,或登录记录保存在主机租户中的 B2B 来宾。revoke_sign_in_sessions有意不提供此类覆盖:写入操作只会针对拥有该 UPN 域名的租户。- 面向整个租户的工具(
signin_failure_stats、signin_success_stats、compromise_suspects、signin_by_ip、directory_audits、m365_service_health)接受可选的tenant;默认使用默认租户。如果directory_audits同时指定了tenant和一个域名被其他租户认领的user,请求会被拒绝(这会在错误的日志中搜索,且一无所获);如果user的域名未被任何租户认领(外部或合作伙伴管理员、来宾),则会在指定租户或默认租户中搜索,并在结果中显示user_domain_claimed: false。 tenant可以是区段名称、其域名或租户 ID。没有租户文件时,它可以是default或环境中的租户 ID;其他值都会被拒绝(tenant_configured: false)。health_check和daily_brief会涵盖每个租户。其顶层键仍与之前一样,属于默认租户;tenant指明该租户,tenants包含各租户的结果。调用预算(ENTRAADM_DEADLINE)会在租户间平均分配(先处理默认租户,每个租户使用剩余预算的一份),因此响应缓慢的租户不会拖住其他租户;未能响应的租户会在其对应条目中标记为error,并使health_check的status最高只能为degraded。设置ENTRAADM_DEADLINE=0时没有预算限制:会依次完整扫描每个租户,这可能超过客户端约 60 秒的超时限制。- Azure Resource Manager 工具(
list_subscriptions、vm_backup_status、vm_backup_policies、vm_activity)仅服务默认租户。 - 使用租户文件时,每个结果都会注明其
tenant(ARM 工具为默认租户;未选定租户的拒绝结果为null)。仅使用环境变量时,结果保持不变,但revoke_sign_in_sessions始终会包含tenant、tenant_configured和configured_domains(其键始终固定)。
使用方法
Claude Code(插件)
/plugin marketplace add shigechika/entraadm-mcp
/plugin install entraadm-mcp@entraadm-mcp
Claude Code(手动配置)
添加到 .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:-}"
}
}
}
}
Codex
codex mcp add entraadm-mcp \
--env ENTRAADM_TENANT_ID=your-tenant-id \
--env ENTRAADM_CLIENT_ID=your-client-id \
--env ENTRAADM_CLIENT_SECRET=your-client-secret \
-- uvx entraadm-mcp
任何其他能启动 stdio 服务的 MCP 客户端也可采用相同方式:将 uvx entraadm-mcp 设为命令,并在其环境中设置配置中的 ENTRAADM_* 变量。
直接执行
entraadm-mcp
CLI 选项
| 选项 | 效果 |
|---|---|
--version | 打印版本并退出 |
--check | 解析身份验证、探测 Graph 可达性和登录日志访问权限,打印报告(以及一行信息性 ARM 内容),退出码为 0(配置错误时为 1) |
注意事项
- 覆盖范围约定。 遍历分页 Graph 集合的每个结果,若未完整扫描其窗口,则会带有一个
capped布尔值——部分扫描绝不会被报告为穷尽扫描。 found: false不是错误。 对于不存在的账户,get_user和get_user_auth_methods会返回{"found": false, ...},而不是error键——userPrincipalName中的拼写错误不应让人误以为此服务已损坏。- 保留期限。 Entra ID P1 会将登录和目录审核日志保留 30 天。超出此期限的时间窗口会返回空结果,而不是错误。
开发
uv sync --dev
uv run pytest -v
uv run ruff check .
uv run ruff format --check .
实时冒烟测试
uv run python scripts/smoke_test.py
只读(即使启用,也会按名称跳过 revoke_sign_in_sessions),不打印任何负载(仅显示工具名称、状态和行数),且范围有限(明确指定较小的时间窗口和分页上限)——此处不会对租户进行写入,也不会扫描超过一天的日志。
发布
此仓库使用由 Conventional Commits 驱动的 release-please。将 feat:/fix: PR 合并到 main 后,release-please 会创建或更新发布 PR;合并该 PR 后会为版本打标签,并触发发布流水线(PyPI、MCP Registry)。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。