mcpField
K
KeyCloak MCP

KeyCloak MCP

本地服务
github.com/shigechika安全01 天前更新

关于 KeyCloak MCP

KeyCloak MCP 将 MCP 客户端连接到 KeyCloak Admin REST API,用于身份管理和安全调查。它涵盖用户、会话、事件、客户端及 Realm 配置,并通过服务账户而非人工登录进行身份验证。

主要功能

  1. 01搜索并查看用户及凭据
  2. 02重置密码并管理用户状态
  3. 03检查登录事件、失败记录和 IP 活动
  4. 04查看组、客户端和活动会话
  5. 05汇总安全与配置变更

适用场景

  1. 01调查密码喷洒活动和登录失败
  2. 02复核 Realm 配置及管理员变更
  3. 03检查组成员关系和用户会话状态

MCP 相关

通过 Admin REST API 向 MCP 客户端提供 KeyCloak 管理和安全工具。使用服务账户通过 Client Credentials Grant 认证,不会创建用户会话。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"shigechika-keycloak": {
"command": "uvx",
"args": [
"keycloak-mcp"
]
}
}
}
启动命令uvx keycloak-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypikeycloak-mcp1.5.1

工具

33

收录的工具列表 · 更新于 1 周前

此工具无需参数。

详细介绍

keycloak-mcp

English | 日本語

适用于 KeyCloak Admin REST API 的 MCP(Model Context Protocol)服务。

文档:https://shigechika.github.io/keycloak-mcp/

通过服务账号(客户端凭据授权)进行身份验证,因此无需人工密码或 TOTP。此外,该服务兼容 Infinispan——它绝不会创建用户会话,也不会访问 userinfo 端点。

功能

用户
工具描述
count_usersrealm 中的用户总数
search_users按部分匹配搜索(用户名 / 邮箱 / 姓名)
get_user获取指定用户名的完整详情
reset_password重置一位用户的密码
reset_passwords_batch从 CSV 批量重置(每行格式为 username,password;密码留空时会自动生成)
get_user_sessions获取一位用户的活动会话,时间戳采用本地时间
logout_user结束一位用户的所有活动会话
set_user_enabled启用或停用一位用户;停用后会阻止所有登录(保留自定义属性)
MFA / 凭据
工具描述
get_user_credentials获取一位用户配置的凭据类型;出现 otp 条目表示已设置 TOTP/HOTP
get_totp_users统计整个 realm 的 TOTP 使用情况:拥有 otp 凭据的用户数量、占比,以及(可选)用户列表。会枚举用户并读取每位用户的凭据(N+1;通过 max_users 限制)
群组
工具描述
list_user_groups获取用户所属的群组
list_users_by_group获取群组成员
安全
工具描述
get_brute_force_status查询用户当前是否因暴力破解检测而被锁定
get_realm_security_defensesrealm 级安全策略:是否启用了暴力破解检测及其阈值、密码策略和浏览器安全标头
get_config_changes查看 realm 配置自保存的每日快照以来有哪些变化(参见 配置快照)。只读;baseline_date 用于选择较早的快照。
get_login_failures_by_ip按来源 IP 列出失败情况(设置 KEYCLOAK_SITES_INI 后会标注站点)
get_ip_activity全面调查一个来源 IP:成功 / 失败次数、受影响的用户 / 客户端和时间线。返回结构化 JSON。
spray_check检测密码喷洒攻击并内置泄露列表:每个拥有 ≥ 10 个不同用户且登录成功率 < 20 % 的外部 IP 都会被视为喷洒来源,其成功登录(证据元组 time / ip / username / user_id / client_id)即为潜在泄露事件。每行都包含 confidence:high 表示确认泄露;low 表示在共享出口(学校 NAT、家庭线路、VDI)上触发了流量规则——可通过 user_success_rate(成功登录的不同用户数 ÷ 不同用户数,≥ 0.2)、failure_concentration(集中在同一用户名上的失败占比,≥ 0.5)或匹配 KEYCLOAK_KNOWN_EGRESS 来识别。此类登录需向所有者核实,不应公开。top_failed_users 和 not_found_domains 分别显示持续登录失败的用户,以及导致 user_not_found 的拼错域名。返回固定结构的 JSON;窗口被截断时 complete: false。
detect_login_loops标记在短时间内登录次数过多的用户(重定向循环)
事件
工具描述
get_events按类型、用户名、客户端、IP 和日期范围筛选。用户名会在内部解析为用户 ID。失败事件包含 KeyCloak 的 error 字段(例如 invalid_user_credentials)。
get_login_stats登录成功 / 失败总数,分页遍历所有结果
get_login_stats_by_hour按一天中的小时统计登录次数(本地时间)
get_login_stats_by_client按客户端 / SP 统计登录次数
get_password_update_eventsUPDATE_PASSWORD 历史记录
管理员事件

get_events 只能查看用户事件。由管理员触发的操作,或由服务账户写入自定义属性的操作,都不会显示在其中。管理员事件端点可弥补这一不足。

工具说明
get_admin_events按操作(CREATE / UPDATE / DELETE / ACTION)、资源类型(USER / CLIENT / ROLE / GROUP / …)、资源路径和日期范围筛选
get_user_attribute_history限定于单个用户的 UPDATE/ACTION 事件,便于追踪自动化流水线写入自定义属性(例如 provisioning_flag)的时间

这两个工具都接受 max_repr,用于控制表示载荷:正数 = 截断至 N 个字符(默认 500),0 = 不包含,负数 = 完整包含。

会话与客户端
工具说明
get_session_stats每个客户端的活跃会话数
get_client_sessions单个客户端(SP)的活跃会话
list_clientsRealm 中的 SAML 和 OIDC 客户端
get_client单个客户端的配置,包括其身份验证流覆盖设置(每个 SP 的 MFA 开关)。省略 attributes 和 protocolMappers,因此工具输出不会包含客户端密钥或 SAML 签名材料。
get_realm_rolesRealm 级别的角色
每日巡检
工具说明
health_check报告正在运行的服务版本,并验证 KeyCloak 后端是否可访问以及服务账户能否进行身份验证。轻量级(一次令牌请求;不扫描用户/事件/会话)。返回固定结构的字典,包含 status、auth 和配置的 URL/realm。该工具自身的说明会列举这些字段可能取值,且只有此处会列出。
daily_brief一次性晨间健康检查:登录统计、暴力破解 IP、喷洒检查(规则与 spray_check 相同,包含已泄露账户和证据)、活跃会话、密码更新、管理员事件和配置更改(针对角色、角色映射、流、客户端范围、协议映射器、组件和 Realm 的管理员事件,以及设置 KEYCLOAK_STATE_DIR 时的快照比较;两者均标记为 [CONFIG]),以及加入了带有角色的组的情况(当该组授予 realm-management 角色(只读的 query-*/view-* 除外)时标记为 [PRIVILEGE]),以上内容汇总为一份 Markdown 摘要。失败次数超过 ip_failure_threshold(默认 50)的 IP 和喷洒来源会标记为 WARNING;API 错误会显示为 CRITICAL。since_hours 控制回溯时间范围(默认 18 h)。

设置

# uv
uv pip install keycloak-mcp

# pip
pip install keycloak-mcp

从源码安装:

git clone https://github.com/shigechika/keycloak-mcp.git
cd keycloak-mcp

# uv
uv sync

# pip
pip install -e .

配置

变量说明默认值
KEYCLOAK_URL基础 URL,例如 https://keycloak.example.com必填
KEYCLOAK_REALMRealm 名称master
KEYCLOAK_CLIENT_ID服务账户客户端 ID必填
KEYCLOAK_CLIENT_SECRET客户端密钥必填
KEYCLOAK_SITES_INI用于将 IP 映射到站点标签的 INI 文件(见下文)未设置
KEYCLOAK_KNOWN_EGRESS以逗号分隔的已知共享出口点(VDI、VPN 集中器、合作伙伴代理)的 CIDR。spray_check 会将匹配的 IP 标记为 known_egress: true,并将其标记为 confidence: low;这些 IP 永远不会被排除未设置
KEYCLOAK_DEFAULT_DATE_FROM_HOURS未提供 date_from 时,事件工具默认回溯的时间范围。设为 0 可扫描全部历史记录(大型 Realm 可能导致工具卡住)。24
KEYCLOAK_DEADLINE耗时较长的事件/TOTP 工具每次调用的墙上时钟时间预算(秒)。如果较宽的时间范围/大型 Realm 会超出预算,工具会停止并返回已披露的部分结果(⚠️ 警告),而不是超出客户端约 60 秒的网关超时并对 KeyCloak 造成压力。每个请求的超时也会限制为剩余时间,且截止时间过后不会重试,因此单个缓慢的分页请求也不会让调用超时。设为 0 或负数可禁用。45
KEYCLOAK_MAX_EVENTS事件工具获取事件时每次分页的上限(也限制缓慢的高偏移分页深度)。超过上限时,结果将是已披露的部分结果。设为 0 或负数可禁用。200000
KEYCLOAK_MAX_USERS当 get_totp_users 的 max_users 参数为 0 时,扫描用户数的默认上限(每个用户需要调用一次凭据接口)。设为 0 或负数可禁用(扫描整个 Realm,仅受 KEYCLOAK_DEADLINE 限制)。5000
KEYCLOAK_USER_ATTRIBUTE_WHITELIST以逗号分隔的自定义用户属性键,允许 get_user 显示这些属性。默认未设置:get_user 只会返回用户名/姓名/电子邮件/启用状态/创建时间,因为用于解析用户名的搜索端点返回的是不含任何 attributes 的简要表示。将某个键加入白名单后,get_user 会额外执行一次按 ID 查询,并在属性值存在时附加该值。其他内容仍不会出现在工具输出中。作为安全措施,名称看起来像凭据的白名单键(包含 password、secret、token 等)会被报告为已屏蔽,而不会显示——但这并非保证,因为名称不符合该模式列表的凭据属性仍会被显示。未设置
KEYCLOAK_GROUP_WRITE_ROOT启用选择加入的组更改工具(plan_group_changes、apply_group_changes),并将其限制在此绝对路径下的组中(例如 /Staff)。未设置、为空或格式错误时,根本不会注册这两个工具。仅在部署时由服务器前置人工审批步骤的情况下设置此项。未设置
KEYCLOAK_PROTECTED_GROUPS以 ; 分隔的完整组路径;组更改工具会拒绝向这些组添加成员或从中移除成员(包括其后代组)。如果某个条目格式错误,组更改工具会被禁用,而不是默默丢弃该保护规则。未设置
KEYCLOAK_GROUP_BATCH_MAX每次组更改调用的最大行数。30
KEYCLOAK_GROUP_MODEmulti(KeyCloak 默认值:用户可以属于多个组)或 single(用于添加一个组会替换所有其他成员关系的部署,例如每个用户只保留一个组的事件监听器)。任何其他值都会禁用组工具。参见组更改。multi
KEYCLOAK_STATE_DIR每日配置快照的目录(<dir>/config-snapshots,目录权限为 0700,文件权限为 0600)。未设置时不创建快照;daily_brief 仍会报告配置管理员事件。参见配置快照。未设置
KEYCLOAK_GROUP_DEADLINE组更改工具的时间预算(秒)。更改 30 个用户的批次需要超过默认的 45 秒;如果服务器前没有超时约为 60 秒的环节(例如,由客户端直接启动服务器),请调高此值。未设置时使用 KEYCLOAK_DEADLINE。未设置
KEYCLOAK_SESSION_PROBES独立连接数;get_user_sessions 会合并这些连接返回的会话列表(set_user_enabled 返回的剩余会话数也会合并这些结果)。在负载均衡器后,如果 KeyCloak 节点不共享用户会话(没有分布式 Infinispan 缓存),每个节点只会列出自己的会话。8
KEYCLOAK_LOGOUT_CLEAN_PROBESlogout_user 会持续探测——每次探测都使用独立连接列出会话,并在连接到的节点列出会话时于该节点登出用户——直到连续有这么多次探测未发现会话。即使首次探测未列出任何会话,也会发送登出请求:它还会在数据库中设置用户的 notBefore,所有节点都会检查该值,且工具会报告此操作。新连接会到达哪个节点由负载均衡器决定:使用源 IP 会话保持时,探测可能永远无法到达某些节点,因此能在所有节点生效的是 notBefore。如果会话是共享的,请将此项和 KEYCLOAK_SESSION_PROBES 均设为 1。10
KEYCLOAK_LOGOUT_MAX_PROBESlogout_user 探测次数的上限;如果达到上限时仍发现会话,工具会如实告知(⚠️),而不会报告成功。与 get_user_sessions 和 set_user_enabled 的会话列表一样,这些探测也受 KEYCLOAK_DEADLINE 限制;预算耗尽或请求失败时,工具会提示验证未完成(⚠️),并报告迄今已完成的操作。40
KeyCloak 客户端设置
  1. 在 KeyCloak 管理控制台中创建一个新客户端。
  2. 开启 Client authentication 和 Service account roles。
  3. 为其授予 view-users、view-events、view-clients,以及仅在需要重置密码时才授予 manage-users。
写入操作

默认情况下,四个工具会更改状态。其他工具都只读取数据。启用群组更改(见下文)后,apply_group_changes 会成为第五个工具。

工具管理 API 调用
reset_passwordPUT /users/{id}/reset-password
reset_passwords_batch对每行 CSV 执行一次相同的调用
set_user_enabledPUT /users/{id},并切换 enabled 状态
logout_userGET /users/{id}/sessions + POST /users/{id}/logout,并在新连接上重复执行(参见 KEYCLOAK_LOGOUT_CLEAN_PROBES)

这四个工具都需要 Service Account 上的 manage-users。不授予该角色,服务就会保持只读:这四个工具会返回 403 错误,其他所有工具则继续正常工作,因此可以将某个 realm 交给 AI 助手进行调查,而无需授予任何修改权限。只有在任务涉及账户恢复或限制访问时,才授予 manage-users。

群组更改(选择启用)

plan_group_changes 和 apply_group_changes 可在群组间转移用户(例如员工调动)。只有设置了 KEYCLOAK_GROUP_WRITE_ROOT 时,这两个工具才会启用,因此,共享该二进制文件但没有审批步骤的部署不会暴露它们。

工具管理 API 调用
plan_group_changes只读:GET /users?username=...&exact=true、GET /group-by-path/...、GET /groups/{id}/role-mappings、GET /roles-by-id/{id}/composites、GET /clients/{id}、GET /users/{id}/groups
apply_group_changes先执行 PUT /users/{id}/groups/{groupId},再执行 DELETE /users/{id}/groups/{groupId}
  • plan_group_changes 会按精确名称/路径解析每位用户和每个群组,并为每行返回当前直接所属的群组、将执行的操作和状态。其 digest 涵盖已解析的 ID、每位用户当前所属的群组以及策略。
  • apply_group_changes 会重新规划;除非每行仍可执行且 digest 与已批准的值一致,否则不会进行任何更改。因此,自规划以来任何人更改了成员关系,整个批次都会中止。它会先添加再移除,在添加前立即重新审核目标群组,在每次写入前重新读取成员关系,并在写入后读回;遇到首个不匹配、错误或时间预算耗尽(KEYCLOAK_GROUP_DEADLINE)时便会停止。如果剩余时间不足以完成某位用户的所有操作,就不会开始处理该用户,因此停止时不会出现已添加但尚未移除的情况。applied 的值为 yes、no、partial 或 unknown(写入后无法读回)。
  • 设置 KEYCLOAK_GROUP_MODE=single 时,移动操作只执行一次添加:服务端会自行移除旧群组,因此不会发送 DELETE,并且读回结果必须仅显示目标群组。每行都必须指定要添加的群组(仅移除的行会导致用户不属于任何群组)。如果省略 remove,则会填入用户当前所属的群组,以便审批者查看哪些内容会被移除;规划时以及添加前都会像审核 remove 一样审核该群组。用户如果属于多个群组,就违反了服务端规则,因此会被拒绝(请手动修复)。如果规划无法恢复用户先前的状态(用户原本没有群组,或服务端实际上没有替换群组),则会将其列入 manual_restore,而不是 reverse。如果你的 KeyCloak 行为如此,请启用此模式;在 multi 模式下,这种服务端行为会使每次移动都因并发更改而停止;在 single 模式下,如果服务端保留旧群组,则移动会停止并提示模式不匹配。
  • 拒绝的目标:根群组以外的任何目标、根群组本身,以及受保护群组及其后代。
  • 带有角色的群组不会被拒绝:如果审批者可以在管理控制台中执行相同操作,那么将某人转入部门的管理员群组就是普通的调动。每行规划都会列出 gained_roles 和 lost_roles:即此次移动对用户通过所有群组成员关系持有的角色造成的变化(通过共同祖先或其他群组保留的角色不算增减;不会读取直接映射给用户的角色)。add_roles 和 remove_roles 分别表示加入和移出各个指定群组时会获得或失去的角色。Realm 角色按名称显示,客户端角色显示为 client:role;会包含从祖先群组继承的角色以及复合角色中的所有角色(任意深度)。请向审批者展示新增和失去的角色。它们属于 digest 的一部分;添加前还会重新读取目标群组的角色(同一次调用中,每个群组最多每 5 秒读取一次),因此审批后附加到群组(或添加到复合角色)的角色会阻止执行。如果无法显示某行的角色变化(例如当前群组无法按路径解析,群组名称中包含 /),则会拒绝该行。 在 1.3.0 中更改:早期版本会拒绝任何具有角色映射的群组。如果你依赖此行为,请在升级前将这些群组列入 KEYCLOAK_PROTECTED_GROUPS。
  • 成员关系可能在没有任何角色的情况下授予访问权限(例如服务提供商会检查的 SAML/OIDC 群组映射器、授权服务群组策略)。无论角色如何,都必须将这些工具绝不能写入的群组列入 KEYCLOAK_PROTECTED_GROUPS。每个受保护路径都必须存在于 KeyCloak 中:如果其中任一路径无法解析(已重命名、移动或大小写不同),在修正配置之前,所有规划都会被拒绝。
  • digest 表示规划之后没有任何内容发生变化,但不能证明有人批准了该规划:任何调用 plan_group_changes 的调用方都能获得有效的 digest。请在 apply_group_changes 前设置审批环节,例如让客户端自行保存 digest,并在每次调用前征求人员批准。每项批准都应视为一次性:如果成员关系恢复到规划时的状态(例如执行 reverse 后),旧 digest 会再次匹配。
  • 结果包含 reverse,即撤销已生效更改的操作。它只是新规划和新审批的提案,不会自动应用。恢复成员关系无法撤销错误期间已经发生的访问。 写入需要 manage-users。根据 KeyCloak 版本,读取组及其角色映射可能还需要 query-groups。展开复合角色会读取 realm 角色(view-realm),而命名客户端角色会读取客户端(view-clients)。运行一次 plan_group_changes 进行确认。
配置快照(可选)

设置 KEYCLOAK_STATE_DIR 后,每天首次运行 daily_brief 时会存储一份 realm 配置快照,并且每次运行 daily_brief 都会将当前配置与更早日期的最新快照进行比较。发生变更时会显示一条 [CONFIG] 警告,并列出变更字段;get_config_changes 会列出所有变更。

  • 涵盖内容:realm 设置(暴力破解检测、密码和 OTP 策略、会话和令牌有效期、流程绑定)、事件设置、realm 角色及各复合角色包含的内容、身份验证流程及其执行项、必需操作、客户端(重定向 URI、允许的流程、流程覆盖项、属性、协议映射器)、客户端范围、默认客户端范围、组件,以及服务账号有权读取时的身份提供商。组角色映射和客户端角色不包含在快照中;系统会改为报告其管理事件。
  • 组成员关系不属于配置,也不包含在快照中。取而代之的是,简报会列出回溯窗口内加入具有角色的组的成员(角色可以是组自身的角色,也可以是通过复合角色继承的祖先组角色),并注明角色、用户和添加者。如果某个组授予 realm-management 角色(query-*/view-* 除外,例如 realm-admin、manage-users 等),则该成员变更标记为 [PRIVILEGE];在 master realm 中,授予 <realm>-realm 管理客户端角色或 admin realm 角色时也一样。系统会通过组 ID 读取该组的当前状态,并沿 parentId 追溯其角色,因此事件发生后组名变更或组移动不会导致其被忽略。无法读取其组的成员变更会单独显示为 [CONFIG] 警告;此项检查最多占用 Configuration 部分 8 秒的预算。
  • 不会存储机密:键名包含 secret、password、privateKey、apiKey、credential、token 等类似字符串的值(get_user 也使用这些标记)会替换为 <redacted>,因此机密变更不会显示为配置变更。这些键下的 true/false 和数字属于设置,会保持可见,但本身就是机密的字段(...password、...secret)除外。这是针对常见名称的安全措施,并非保证。长值(证书、公钥)会以哈希形式存储。
  • 只有完整读取的配置才会被存储。如果时间预算用尽,简报会说明已跳过比较,并保留之前的基线。
  • 快照仅由 daily_brief 写入,且每天只写入第一份,因此当天发生的变更会在第二天早上再次报告。系统会保留最近 30 份快照。
  • 读取配置需要 view-realm 和 view-clients;身份提供商还需要 view-identity-providers。如果缺少该权限,相应部分会从比较中排除,简报也会说明这一点。
验证设置

设置环境变量后,运行 --check,在将其接入 MCP 客户端之前确认身份验证有效:

export KEYCLOAK_URL=https://keycloak.example.com
export KEYCLOAK_REALM=my-realm
export KEYCLOAK_CLIENT_ID=keycloak-mcp
export KEYCLOAK_CLIENT_SECRET=your-secret
keycloak-mcp --check
# HTTP Request: POST https://keycloak.example.com/realms/my-realm/protocol/openid-connect/token "HTTP/1.1 200 OK"
# OK: authenticated to https://keycloak.example.com/admin/realms/my-realm

退出代码:0 表示成功,1 表示配置错误(缺少变量),2 表示身份验证错误。

IP 到站点的标记(可选)

如果希望工具输出中的 IP 地址带有站点名称标签,可将 KEYCLOAK_SITES_INI 指向一个 INI 文件。get_user_sessions、get_events 和 get_login_failures_by_ip 等工具会自动读取该文件;任何不在所声明范围内的地址都会标记为 external。不设置该变量时,IP 地址将按原样显示。

请参阅 sites.ini.example。最简文件:

[hq]
name = HQ (Tokyo)
ipv4 = 192.0.2.0/24, 198.51.100.0/24
ipv6 = 2001:db8:1::/48

[vpn]
name = VPN
ipv4 = 10.0.0.0/8, 172.16.0.0/12

每个 [section] 对应一个站点。name 是显示标签(未设置时使用 section 名称)。ipv4 / ipv6 接受以逗号分隔的 CIDR;单个主机使用 /32 或 /128。匹配按文件顺序进行——请将具体范围放在宽泛范围之前。

用法

Claude Code(插件)

此仓库同时也是一个单插件市场,因此 Claude Code 可以为你安装 服务:

/plugin marketplace add shigechika/keycloak-mcp
/plugin install keycloak-mcp@keycloak-mcp

此插件会启动 uvx keycloak-mcp,并读取 配置 中描述的相同环境变量;启动 Claude Code 前请先导出这些变量。KEYCLOAK_REALM 默认使用 master,KEYCLOAK_SITES_INI 可以 不设置。

运行 Claude Code 的进程必须能在 PATH 中找到 uvx——登录 shell 通常已包含它,但通过 GUI 启动的应用可能没有;如果插件无法启动,请在系统范围内安装 uv。

Claude Code(手动)

在 .mcp.json 中:

{
  "mcpServers": {
    "keycloak-mcp": {
      "type": "stdio",
      "command": "keycloak-mcp",
      "env": {
        "KEYCLOAK_URL": "https://keycloak.example.com",
        "KEYCLOAK_REALM": "my-realm",
        "KEYCLOAK_CLIENT_ID": "keycloak-mcp",
        "KEYCLOAK_CLIENT_SECRET": ""
      }
    }
  }
}
Claude Desktop

在 claude_desktop_config.json 中:

{
  "mcpServers": {
    "keycloak-mcp": {
      "command": "keycloak-mcp",
      "env": {
        "KEYCLOAK_URL": "https://keycloak.example.com",
        "KEYCLOAK_REALM": "my-realm",
        "KEYCLOAK_CLIENT_ID": "keycloak-mcp",
        "KEYCLOAK_CLIENT_SECRET": ""
      }
    }
  }
}
Codex
codex mcp add keycloak-mcp \
  --env KEYCLOAK_URL=https://keycloak.example.com \
  --env KEYCLOAK_REALM=my-realm \
  --env KEYCLOAK_CLIENT_ID=keycloak-mcp \
  --env KEYCLOAK_CLIENT_SECRET=your-secret \
  -- keycloak-mcp

任何其他能够启动 stdio 服务的 MCP 客户端也采用相同方式:将 keycloak-mcp 设为命令,并在其环境中设置 KEYCLOAK_* 变量。

从 shell 启动
export KEYCLOAK_URL=https://keycloak.example.com
export KEYCLOAK_REALM=my-realm
export KEYCLOAK_CLIENT_ID=keycloak-mcp
export KEYCLOAK_CLIENT_SECRET=your-secret
keycloak-mcp
CLI
keycloak-mcp --version   # Print version and exit
keycloak-mcp --help      # Show usage and required environment variables
keycloak-mcp --check     # Verify env vars and authentication, then exit
keycloak-mcp             # Run the MCP STDIO server (default)

不带参数的模式是常规模式——MCP 客户端就是这样启动它的。

每日喷洒攻击报告(批处理)

spray_check 会检查截至当前时刻的滚动时间窗口,适用于巡查,但无法按日归档。为此,可通过计划任务对一个日历日运行相同的分析:

keycloak-mcp spray-report --date 2026-09-17 --tz Asia/Tokyo > 2026-09-17.json
  • 时间窗口为 --tz 指定时区中的 [DATE 00:00, DATE+1 00:00)(默认:主机时区)。请使用 KeyCloak 服务日志所用的时区,因为 dateFrom / dateTo 会按该时区解读。事件会根据两端的时间戳筛选至此窗口。
  • 一个 JSON 文档会写入 stdout;错误会写入 stderr,并以非零状态码退出(2 = 配置错误,1 = 获取/认证错误);发生错误时不会向 stdout 写入任何内容。
  • 输出采用 spray_check 的结构,其中 external_ips 包含所有至少有一个事件带有用户名的外部 IP(min_report_users=1);此外还有 external_totals,用于统计所有外部 IP 的 LOGIN / LOGIN_ERROR 数量——包括失败事件没有用户名、因此不会出现在行中的 IP;以及 fetch_complete、resolve_complete、coverage(first_event、last_event、head_gap_seconds、tail_gap_seconds)、schema、keycloak_mcp_version 和 sites_ini_sha256。只有在两个 *_complete 标志都为 true 且两端间隔都不大时,才应将当天视为最终结果;一端出现间隔通常意味着 --tz 与 KeyCloak 服务的时区不同。
  • 如果 KEYCLOAK_SITES_INI 未产生任何范围(此时每个 IP 都会被计为外部 IP),且未提供 --allow-no-sites,则拒绝运行;如果 KEYCLOAK_KNOWN_EGRESS 中存在非 CIDR 格式的条目,也会拒绝运行。
  • 此命令使用自身的限制(--deadline 900、--max-events 1000000、--max-resolves 2000),而不是为 HTTP 网关后的工具调用设置的 KEYCLOAK_DEADLINE / KEYCLOAK_MAX_EVENTS。
  • 输出包含源 IP 和用户名。请勿将其用于任何公开发布的内容。

开发

git clone https://github.com/shigechika/keycloak-mcp.git
cd keycloak-mcp

# uv
uv sync --dev
uv run pytest -v
uv run ruff check .

# pip
python3 -m venv .venv
.venv/bin/pip install -e . && .venv/bin/pip install pytest pytest-cov respx ruff
.venv/bin/pytest -v
.venv/bin/ruff check .
实时冒烟测试

pytest 会对照固定数据检查逻辑,但无法告诉你某个工具是否已停止返回真实数据。scripts/smoke_test.py 会针对配置的 realm 测试所有已注册工具,并在结果为空、格式错误或出错时失败:

# needs KEYCLOAK_URL / KEYCLOAK_CLIENT_ID / KEYCLOAK_CLIENT_SECRET
uv run python scripts/smoke_test.py
uv run python scripts/smoke_test.py --only login_stats --traceback
  • 只读。 所有会更改状态的工具(reset_password、logout_user、set_user_enabled、reset_passwords_batch)都会按名称跳过,并且有测试确保这一点。报告只输出工具名称和状态,不会输出负载,也会遮盖服务端生成的错误文本(KeyCloak 会引用它收到查询的用户名);--traceback 仍会在操作者自己的终端上显示完整文本。
  • 用于标识真实用户、群组或 IP 的参数会在运行时发现,绝不会写入 scripts/smoke_probes.py。
  • CI 会检查较简单的一半:注册的工具若没有探测规格,就会导致构建失败(tests/test_smoke_probes.py),因此每次添加工具都会促使我们思考“如何确认它能正常工作?”。
  • scripts/smoke_harness.py 是引擎,不包含任何 KeyCloak 相关知识:它在共用该引擎的服务之间保持一致,因此修复引擎问题后,只需同步该文件,无需修改此副本。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。