关于 CIPP
CIPP 是面向 MSP 的 MCP 服务,可通过运行中的 CIPP 部署管理多个 Microsoft 365 租户,涵盖管理、安全、合规、许可和报告。
主要功能
- 01管理租户、用户、群组和邮箱
- 02查看登录记录、条件访问和安全评分
- 03检查标准、合规性和域健康
- 04报告邮箱用量和许可证状态
- 05管理警报、GDAP 和计划任务
- 06支持 stdio 和 HTTP 传输
适用场景
- 01跨客户租户管理用户账户
- 02审查登录活动和安全策略
- 03检查租户标准及配置偏差
- 04报告邮箱大小和许可证分配
MCP 相关
向 MCP 客户端提供 CIPP 的 Microsoft 365 多租户管理能力,作为可调用工具。支持 stdio 和 HTTP 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm -e CIPP_API_URL -e CIPP_CLIENT_ID -e CIPP_CLIENT_SECRET -e CIPP_TENANT_ID -e MCP_TRANSPORT -e AUTH_MODE -e LOG_LEVEL ghcr.io/wyre-technology/cipp-mcp:v1.7.3CIPP_API_URLBase URL of your CIPP API instance (e.g. https://cipp-api.example.com)CIPP_CLIENT_IDEntra ID application (client) ID used to authenticate to CIPPCIPP_CLIENT_SECRET密钥Entra ID client secret for the CIPP applicationCIPP_TENANT_IDEntra ID tenant ID hosting the CIPP application registrationMCP_TRANSPORTTransport mode for the server. Set to 'stdio' for local CLI use; the image defaults to 'http' for gateway hosting.AUTH_MODE密钥Credential source: 'env' reads vars locally, 'gateway' expects header injection from the WYRE MCP Gateway.LOG_LEVELLog verbosity: debug, info, warn, error本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/wyre-technology/cipp-mcp:v1.7.3stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
CIPP MCP 服务器
适用于 CIPP(CyberDrain Improved Partner Portal)的 MCP(Model Context Protocol)服务器。为 AI 助手提供对 CIPP M365 多租户管理功能的结构化访问。
功能
- 49 个工具,涵盖 12 个类别
- 租户、用户、组和邮箱管理
- 邮箱和在线存档大小报告,可按租户或用户查看
- 每位用户的 Entra ID 登录日志(状态、位置、条件访问、MFA)
- 安全性:条件访问策略、命名位置、Microsoft Secure Score
- 标准与合规:BPA、域健康状况、偏差检测
- 许可证报告(按租户及 CSP 全范围)
- 警报、审核日志和计划任务
- GDAP 角色和邀请管理
- Stdio 和 HTTP 传输模式
- 兼容 MCP Gateway
先决条件
- Node.js 18+
- 正在运行的 CIPP 部署
- CIPP API Key(在 CIPP Settings → API Client Management 中生成)
安装
通过 npm(发布后)
npx cipp-mcp
从源代码安装
git clone https://github.com/WYRE-AI/cipp-mcp
cd cipp-mcp
npm install
npm run build
配置
设置以下环境变量(或将 .env.example 复制到 .env):
| 变量 | 必需 | 说明 |
|---|---|---|
CIPP_BASE_URL | 是 | 你的 CIPP Azure Function App URL(例如 https://cippXXXXX.azurewebsites.net)。请勿使用 SWA / 前端 URL——参见查找 Function App URL。 |
CIPP_API_KEY | 二选一 | 静态 Bearer 令牌。使用此项或下方的 OAuth 三项配置。 |
CIPP_TENANT_ID | 二选一 | 拥有 CIPP API 客户端应用注册的 Entra 租户 ID。 |
CIPP_CLIENT_ID | 二选一 | 由 CIPP 的 API Client Management 页面签发的 OAuth 客户端 ID。 |
CIPP_CLIENT_SECRET | 二选一 | 与 CIPP_CLIENT_ID 配对的 OAuth 客户端密钥。 |
CIPP_TOKEN_SCOPE | 否 | 覆盖 OAuth 作用域。默认值:api://<clientId>/.default。显式设置此值会禁用下方的旧版作用域回退。 |
CIPP_TOKEN_SCOPE_FALLBACK | 否 | 未显式设置作用域时,遇到 CIPP HTTP 401 响应后,使用旧版 <clientId>/.default 作用域重试一次,并复用此客户端接受的受众。默认值:true。TOKEN_SCOPE_FALLBACK 是别名。网关请求可发送 x-token-scope-fallback。 |
CIPP_TOKEN_URL | 否 | 覆盖 OAuth 令牌端点(仅限主权云)。 |
MCP_TRANSPORT | 否 | stdio(默认)或 http |
AUTH_MODE | 否 | env(stdio 和单租户 HTTP)或 gateway。网关模式要求每个 /mcp 请求都携带 CIPP 凭据标头,且不会回退到 CIPP_*。容器映像和 Compose 网关服务会设置为 gateway。 |
CONDUIT_S2S_SECRET | HTTP 必需 | 与网关共享的服务间密钥。若该值为空、仅含空白字符或为已知占位值(changeme、change-me、your-s2s-secret、your-secret、placeholder、secret、example、replace-me、replace-with-a-real-secret、s2s-secret 或未解析的 ${...} 值),HTTP 会记录错误并以非零状态退出。未设置该值时,Compose 不会启动。切勿提交真实值。 |
MCP_ALLOW_INSECURE_DEV | 否 | 仅限本地开发时,将其精确设置为 1,即可在未设置 CONDUIT_S2S_SECRET 的情况下启动 HTTP。进程会记录警告,不会强制检查 X-Gateway-S2S,且只监听 127.0.0.1。非环回地址的 MCP_HTTP_HOST 将被忽略,并记录此覆盖操作。此标志不会绕过已知占位值检查。 |
MCP_HTTP_HOST | 否 | 当 MCP_TRANSPORT=http 且已设置 CONDUIT_S2S_SECRET 时使用的绑定地址。未设置时默认为 127.0.0.1。容器映像会设置为 0.0.0.0。 |
MCP_HTTP_PORT | 否 | HTTP 模式的端口(默认值:8080) |
LOG_LEVEL | 否 | error、warn、info(默认)或 debug |
重要
CIPP_BASE_URL必须是 Azure Function App URL,即 CIPP-API 后端的https://<function-app-name>.azurewebsites.net,不能是 Static Web App / 自定义域名 UI URL(例如https://cipp.yourdomain.com)。SWA 内置的 身份验证会拦截 Bearer 令牌,并将其重定向到交互式登录页面, 因此所有 API 调用都会失败。请在 Azure Portal 的 CIPP 资源组中查找 Function App(名称类似cippXXXXX)。
/health 无需身份验证,也不会读取凭据。stdio 传输不使用 CONDUIT_S2S_SECRET。
HTTP 身份验证
设置 MCP_TRANSPORT=http 和 CONDUIT_S2S_SECRET 后,每个 /mcp 请求都必须包含 X-Gateway-S2S。标头值的格式为 t=<unix seconds>,v1=<hex>,其中 v1 是使用 CONDUIT_S2S_SECRET 作为密钥,对 ASCII 字符串 t=<unix seconds> 计算得到的 HMAC-SHA256 的十六进制编码。时间戳与服务端时钟的偏差必须在 300 秒以内。缺少标头或标头无效时,会返回 HTTP 401,且不会读取 CIPP 凭据。密钥绝不会写入日志。
X-Gateway-S2S: t=1710000000,v1=<64 lowercase hex chars>
在 AUTH_MODE=gateway 下,/mcp 还需要 x-base-url,以及 x-api-key 或全部三个标头:x-tenant-id、x-client-id 和 x-client-secret(x-token-scope、x-token-url 和 x-token-scope-fallback 为可选项)。这些标头是该请求唯一的 CIPP 凭据来源。缺少这些标头的请求会返回 HTTP 401,且不会使用进程环境中的 CIPP_*。
AUTH_MODE=env 仍要求提供有效的 X-Gateway-S2S 标头,然后使用环境中的 CIPP_*。
不设置密钥的本地 HTTP 仅限开发使用。即使 MCP_HTTP_HOST 为 0.0.0.0 或其他非环回地址,它也会绑定到 127.0.0.1:
MCP_TRANSPORT=http MCP_ALLOW_INSECURE_DEV=1 npm run dev
Docker
镜像会在容器内监听 0.0.0.0(MCP_HTTP_HOST),并默认使用 AUTH_MODE=gateway。请将端口发布到环回地址,并传入网关使用的同一个 S2S 密钥。在网关模式下,每个请求都会通过标头传入 CIPP 凭据;不会从环境中读取这些凭据。
docker build -t cipp-mcp .
docker run --rm \
-e CONDUIT_S2S_SECRET="$CONDUIT_S2S_SECRET" \
-p 127.0.0.1:8080:8080 \
cipp-mcp
未设置 CONDUIT_S2S_SECRET 时,Compose 会拒绝启动。cipp-mcp 服务使用网关模式:它设置 AUTH_MODE=gateway,发布 127.0.0.1:8080:8080,并且不会设置 CIPP_API_KEY、CIPP_CLIENT_ID、CIPP_CLIENT_SECRET、CIPP_TENANT_ID、CIPP_BASE_URL 或 env_file。
CONDUIT_S2S_SECRET="$CONDUIT_S2S_SECRET" docker compose up
单租户 HTTP(AUTH_MODE=env)仍需要 S2S 密钥,然后使用 CIPP_*:
docker run --rm \
-e CONDUIT_S2S_SECRET="$CONDUIT_S2S_SECRET" \
-e AUTH_MODE=env \
-e CIPP_BASE_URL=https://cippXXXXX.azurewebsites.net \
-e CIPP_TENANT_ID=your-entra-tenant-id \
-e CIPP_CLIENT_ID=your-client-id \
-e CIPP_CLIENT_SECRET=your-client-secret \
-p 127.0.0.1:8080:8080 \
cipp-mcp
在 Claude Desktop 中使用
添加到你的 claude_desktop_config.json:
{
"mcpServers": {
"cipp": {
"command": "node",
"args": ["/path/to/cipp-mcp/dist/entry.js"],
"env": {
"CIPP_BASE_URL": "https://cippXXXXX.azurewebsites.net",
"CIPP_TENANT_ID": "your-entra-tenant-id",
"CIPP_CLIENT_ID": "your-client-id",
"CIPP_CLIENT_SECRET": "your-client-secret"
}
}
}
}
注意:
CIPP_BASE_URL必须是 Azure Function App URL(.azurewebsites.net),而不是前端 SWA URL(.azurestaticapps.net或你的自定义域名)。SWA 会强制执行基于浏览器的身份验证,并将所有 API 请求重定向到 Microsoft 登录页面。
工具
| 类别 | 工具 |
|---|---|
| 租户 | list_tenants, get_tenant_details |
| 用户 | list_users, create_user, edit_user, disable_user, reset_password, reset_mfa, revoke_sessions, offboard_user, bec_check, list_mfa_users, list_user_devices, list_user_groups, list_user_signin_logs |
| 组 | list_groups, create_group |
| 邮箱 | list_mailboxes, list_mailbox_permissions, list_trusted_blocked_senders, list_mailbox_usage, get_mailbox_usage, set_out_of_office, set_email_forwarding |
| 安全 | list_conditional_access_policies, list_named_locations, get_secure_score, list_secure_score_controls |
| 应用程序 | list_enterprise_apps |
| 标准 | list_standards, run_standards_check, list_standard_templates, get_tenant_drift, get_tenant_alignment, create_standard_template, delete_standard_template, list_bpa, list_domain_health |
| 许可证 | list_licenses, list_csp_licenses |
| 警报 | list_audit_logs, list_alert_queue |
| GDAP | list_gdap_roles, list_gdap_invites |
| 调度器 | list_scheduled_items, add_scheduled_item |
| 核心 | ping, get_version, list_logs |
创建用户后立即编辑用户
edit_user 会先解析帐户当前的 UPN,因为 CIPP 的
Invoke-EditUser 每次调用时都会根据 username + Domain 重新生成 UPN,
不带 UPN 进行编辑会重命名帐户。Graph 可能需要几秒钟才能同步刚创建的帐户,因此如果查找不到帐户、返回 HTTP 404,或返回正文为 Graph 未找到错误的 5xx(Request_ResourceNotFound
代码,或 Graph 的“Resource '' does not exist or one of its queried
reference-property objects are not present”消息),最多会重试 4 次,每次间隔
1 秒、3 秒和 6 秒(约 10 秒)。重试判断依据是 HTTP 状态码,而非消息文本;其他任何 4xx
(400、401、403)和其他 5xx 都不会重试。如果用户仍不可见,错误会显示“Tried N times”,并在最后一次尝试收到 HTTP 错误时显示其状态码;稍等片刻后重试。
邮箱和存档大小
list_mailbox_usage 会报告租户中的每个邮箱,包括主邮箱大小、项目数、
配额、配额百分比,以及联机存档对应的相同四项数据;按大小从大到小排序,
并提供覆盖所有邮箱的租户总计,即使返回的只有排名靠前的几行。
此工具要求 CIPP 的报告数据库已针对该租户完成同步。
这并非设计选择:Invoke-ListMailboxes 的 Exchange 实时查询
完全不会选择大小字段,因此缓存是获取租户范围大小数据的唯一来源。
请在 CIPP 的 Reports → Report Settings 中进行同步。如果尚未同步,
工具会说明这一点并指出解决方法,而不是返回空结果。
get_mailbox_usage 会报告单个邮箱的相同数据,并实时读取,因此无需缓存。
缓存不可用或已过时时,优先使用此工具。
需要注意以下两点:
- 隐藏报告名称会导致租户范围的大小数据为空。 在 Microsoft 365 管理
中心启用 Reports:
conceal user, group, and site names 后,Graph 的使用情况报告会返回 32
个字符的哈希值,而非 UPN,因此 CIPP 与邮箱列表的联接不会匹配到任何内容,
每个邮箱缓存的大小都会变为
0— 租户看起来像是空的,而不是查询失败。list_mailbox_usage会检测到此情况,并在总计旁返回警告。get_mailbox_usage不受影响:它直接读取 Exchange 管理 API。 - 按用户查询路径返回的大小会四舍五入到吉字节。 CIPP 返回前会将吉字节数
四舍五入到小数点后两位,因此
get_mailbox_usage的字节数 精确度约为 10 MB。配额是精确的 — 它们是从原始Get-Mailbox字符串中还原的, 该字符串包含真实的字节数。
用户登录日志
list_user_signin_logs 会返回一位用户最近的交互式登录记录,
按时间从新到旧排列:时间、应用、IP、位置、成功或失败及错误代码和
原因、客户端应用、条件访问状态及评估过的策略、Graph 记录的身份验证方法
(包括第一个因素 — 是否要求 MFA 由 authenticationRequirement 表示)、设备,以及
在标记风险时显示的风险信息;此外还会汇总失败次数、不同 IP 和国家/地区。
- 接受 UPN 或对象 ID,并始终先进行解析。 CIPP 根据
userId过滤 Graph,而该字段是 Entra 对象 ID;如果在此处传入 UPN, 则不会匹配到任何内容,并会返回一个空页面,让人误以为“此用户从未登录”。无法解析的用户会报错,而非返回空结果。 - 单个租户、单个用户、单页。
top默认为 50,上限为 1000;如果 页面已满,会显示警告,指出可能还有更早的登录记录。allTenants会被拒绝 — 此端点没有跨租户分支。租户范围的登录记录在 CIPP 的 Sign-Ins 报告 (ListSignIns)中,此服务不提供该报告。 - 租户需要 Entra ID P1/P2。 否则 Graph 会拒绝访问登录日志 API; 工具会指出许可证缺失,而不是转述笼统的“Failed to retrieve Sign In report”。
Microsoft Secure Score
get_secure_score 会返回一个租户最新的 Secure Score 及其近期每日历史记录。list_secure_score_controls 会返回建议目录,包括标题、排名、最高分、成本、修正方法、威胁,以及将某项控制标记为已由第三方解决或忽略的决定。
CIPP 没有专用的 Secure Score 读取端点。唯一的 Secure Score HTTP 函数是 ExecUpdateSecureScore,它用于更新控制项,且未在此处公开。这两个工具都会调用 ListGraphRequest,CIPP 自己的 Secure Score 页面也使用该函数,并将 Endpoint 设为 security/secureScores 或 security/secureScoreControlProfiles。
- 仅限一个租户。 不接受
allTenants。CIPP 的全局视图使用每晚更新的分数缓存,而不是实时 Graph 调用;这些工具不会读取该缓存。 - 只有关闭分页时,
top才会限制历史记录。ListGraphRequest会将$top视为 Graph 的页面大小,并跟随每个后续链接,除非设置了NoPagination。get_secure_score始终同时发送这两个参数,因此top(默认值为 7,最大值为 90)表示返回的每日读数数量。控制目录会保持分页开启,并将页面大小设为 999,因此会返回完整列表。 - 空结果不代表分数为零。 尚未评分的租户,或其 CIPP 应用缺少
SecurityEvents.Read.All权限的租户,会返回无读数并附带警告。如果权限被拒绝,错误会指出该 Graph 权限,而不是返回通用的 CIPP HTTP 400。 - 比较数据按
basis匹配。“所有租户”对应AllTenants,“相似租户”对应TotalSeats。这些数值已经是百分比。租户自身分数的百分比为currentScore / maxScore;如果缺少最高分,则会省略该值,而不会报告为 0%。
CIPP 版本兼容性
请求正文根据 CIPP 自身的 Invoke-*.ps1 处理程序构造,并确保兼容当前和较旧的 CIPP 版本;如果两者存在差异,服务器会发送两者都能接受的格式。以下三种行为值得注意:
offboard_user报告的是已排队,而非已完成。 CIPP 的ExecOffboardUser会在创建作业时立即返回 HTTP 200;它不会等待卸载结果,也不会报告结果。在将账户视为已卸载之前,请先在 CIPP 的 Offboarding 视图中确认结果。如果未选择任何操作,该工具会拒绝调用,因为否则会排入一个虽成功但不执行任何操作的作业。- 某些端点会在 HTTP 200 下报告失败。
EditUser、AddScheduledItem和ExecOffboardUser会在Results中返回错误文本,而不是错误状态。这些工具会解析Results并返回status: "failed";不要将 200 视为成功。 - 两个参数需要较新的 CIPP 版本。 较旧版本会忽略
offboard_user的DisableOneDriveSharing和set_out_of_office的timezone,而不是报错;因此,在较旧的 CIPP 上,如果卸载操作只选择了 DisableOneDriveSharing,就不会执行任何操作。
身份验证设置
CIPP 的 API 客户端管理页面会预配 Entra ID 应用注册,并返回 OAuth 客户端 ID + 客户端密钥(而非长期有效的 Bearer 令牌)。 服务器会在每次请求时使用 OAuth 2.0 客户端凭据流交换这些信息以获取短期访问令牌,并在令牌即将过期前缓存该令牌。
- 在 CIPP 中,前往 Settings → CIPP Settings → Integrations → CIPP-API
- 创建新的 API 客户端
- 复制 Client ID 和 Client Secret——之后将无法再获取该密钥
- 使用 Function App URL 配置服务器(见下文):
CIPP_BASE_URL=https://cippXXXXX.azurewebsites.net CIPP_TENANT_ID=<your-entra-tenant-id> CIPP_CLIENT_ID=<client-id-from-cipp> CIPP_CLIENT_SECRET=<client-secret-from-cipp>
如果已有静态 Bearer 令牌(较旧的 CIPP 部署),请改为设置 CIPP_API_KEY,并将 OAuth 变量留空。如果两者都已提供,则优先使用 CIPP_API_KEY。
访问令牌请求的范围为 api://<clientId>/.default。这是 CIPP 的 App Service 身份验证允许的 Application ID URI。若请求的范围为裸 <clientId>/.default,其 aud 会被设为客户端 ID GUID,App Service 身份验证会以 HTTP 401 和空响应体拒绝该令牌。
仍使用旧受众的部署会自动处理:未配置明确范围时,收到 401 后会使用另一个自动受众(api://<clientId>/.default 或 <clientId>/.default)重试一次。成功的受众会用于同一客户端后续的调用。如果该受众之后开始返回 401,则会取消固定该受众,并使用另一个受众重试一次,然后再次记住成功的受众。
对于其他任何状态(403、500 等),都不会重试;单个请求最多只会重试一次。设置 CIPP_TOKEN_SCOPE 可强制指定范围;设置 CIPP_TOKEN_SCOPE_FALLBACK=false(别名 TOKEN_SCOPE_FALLBACK,网关请求头 x-token-scope-fallback)可跳过重试。
查找 Function App URL
CIPP 以 Azure Static Web App(SWA)形式运行,并由 Azure Function App 提供支持。
SWA URL(你的自定义域名或 *.azurestaticapps.net)仅允许浏览器身份验证,不能用作 CIPP_BASE_URL。请改用 Function App URL。
自托管的 CIPP: 在 Azure 门户中查找 Function App(在与你的 SWA 相同的资源组中,查找 Kind: functionapp 的 App Service),或运行:
az staticwebapp show --name <your-swa-name> --resource-group <rg> \
--query "linkedBackends[0].backendResourceId" -o tsv
由 CIPP 赞助托管: 联系 CIPP 团队,获取你的实例对应的 Function App URL——它与浏览器中显示的 URL 不同。
IP 允许列表
CIPP 会根据存储在 Azure Table Storage 中的 IPRange 字段验证每个 API 客户端。
如果服务器的公网 IP 不在此列表中,你会收到:
Access to this CIPP API endpoint is not allowed, the API Client does not have the required permission
自托管: 通过 CIPP 界面(Settings → API Client Management)添加你的 IP,或直接在 CIPP 存储帐户的 ApiClients 表中添加。
由 CIPP 赞助托管: 请 CIPP 团队将服务器的公网 IP 添加到 API 客户端的允许范围中。
许可证
Apache-2.0 — 参见 LICENSE
贡献
欢迎提交 Issue 和 PR。此服务端的跟踪事项见 wyre-technology/msp-claude-plugins#24。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。