Skycloak
官方用于Skycloak托管Keycloak的模型上下文协议服务器。可从任何MCP客户端管理集群、领域、应用程序、SSO和用户。
你可以用 Skycloak MCP 做什么?
在任何MCP客户端中管理您的Skycloak(托管Keycloak)集群、领域和单点登录(SSO)。
- 集群升级审查 — 询问哪些集群在Keycloak升级方面落后,并通过
list_cluster_upgrades和get_cluster_upgrade_path获取升级路径。 - 领域配置 — 使用
create_realm和create_identity_provider创建支持Google和GitHub登录的领域。 - SIEM转发 — 通过
create_siem_destination设置一个SIEM目标,将管理员事件转发到Datadog webhook。 - 自定义域名设置 — 使用
create_domain和verify_domain添加自定义域名、获取DNS记录并完成验证。
文档
skycloak-mcp
面向 Skycloak(托管式 Keycloak)的官方 Model Context Protocol 服务器:可从任何 MCP 客户端(Claude Desktop、Claude Code、Cursor)管理你的集群、领域、应用和 SSO。
状态: 早期发布。工具覆盖范围正在增长;可用内容请参阅变更日志。
快速开始
claude mcp add --transport http skycloak https://mcp.skycloak.io
无需 API 密钥、无需客户端 ID、无需配置。浏览器会自动打开,你登录 Skycloak 后工具即会出现。任何支持流式 HTTP 的 MCP 客户端都以相同方式工作:只需提供 URL,无需其他任何内容。
然后可以提出请求,例如:
- "我的哪些 Keycloak 集群升级滞后?"
- "在 EU 集群上创建一个启用 Google 和 GitHub 登录的暂存领域。"
- "上周谁被添加到了生产领域?"
- "设置一个 SIEM 目标,将管理员事件转发到我们的 Datadog webhook。"
身份验证与安全
- 托管 HTTP,使用 OAuth(无需配置凭据)。 将客户端指向
https://mcp.skycloak.io,无需任何请求头。服务器以401响应,并附带指向其 RFC 9728 元数据的指针(位于/.well-known/oauth-protected-resource),客户端针对 Skycloak 登录领域执行浏览器授权码流程,获得的访问令牌会兑换为会话使用的短期、工作区范围的 API 密钥。该密钥有效期为一小时,并会自动续期。客户端配置中不会存储任何内容。 - 托管 HTTP,使用 API 密钥。 在 Skycloak 仪表板 中创建密钥,并以
Authorization: Bearer <key>(或API-Key: <key>)形式发送。每个请求都携带自己的凭据,且仅以该凭据所属的工作区身份运行。服务器不保留会话状态,因此请求永远不会继承其他调用者的状态。密钥在使用前不会经过验证:Skycloak API 才是权威,因此无效密钥会在首次工具调用时以401形式出现,而不是在连接时。 - 工具与你的角色匹配。 通过 OAuth 连接时,工具列表会根据会话作用域进行裁剪,因此只读工作区成员不会看到会响应
403的写入工具。使用 API 密钥时,整个工具面都会注册,因为服务器无法看到密钥的作用域,未授权的调用会以 API 返回的403形式出现。 - 本地 stdio。 运行
skycloak-mcp init并在浏览器中批准(OAuth 2.0 设备授权流程)。它会生成一个工作区范围的 API 密钥,存储在操作系统钥匙串中,并自动检测你的默认工作区(传入--workspace <id>可选择其他工作区)。skycloak-mcp logout会删除已存储的密钥。 - 无头 / CI。 设置
SKYCLOAK_API_KEY环境变量(在 Skycloak 仪表板 中创建密钥)即可完全跳过浏览器。它始终优先于钥匙串。 - 写入操作由你的凭据控制,而非标志位。 位于
https://mcp.skycloak.io的托管服务器支持写入,你实际能修改的内容受密钥作用域和工作区角色限制:只读成员无法修改任何内容,无论工具列表如何显示。在 URL 中添加?readonly=true可强制会话使用只读工具面。本地二进制文件则相反,除非以--allow-writes启动,否则不会注册任何写入工具。 - 集群凭据为可选加入。
get_cluster_credentials会返回集群的 Keycloak 管理员凭据,持有密钥的助手将能看到这些凭据,因此init默认不会请求该作用域。请使用携带该作用域的密钥:在仪表板中创建,或通过 stdio 使用skycloak-mcp init --allow-credentials登录。没有该作用域时,工具会返回 403,并说明这两种途径。 - 破坏性工具需要确认: 例如,删除领域需要显式的
confirm=true参数。 - 请求会根据你的 Skycloak 套餐进行速率限制;当收到
429响应时,服务器会显示Retry-After。
工具
共 129 个工具:58 个只读,71 个写入。只读工具始终可用。在托管服务器上,写入工具也会注册,并由你的凭据作用域控制;本地二进制文件仅在以 --allow-writes 启动时才注册它们。
工具名称带有 skycloak_ 前缀,下表中已省略,因此 list_clusters 在客户端中即为 skycloak_list_clusters。
| 区域 | 只读 | 写入 (--allow-writes) |
|---|---|---|
| 集群 | list_clusters, get_cluster, list_cluster_locations, list_cluster_types, list_cluster_features, list_cluster_versions, list_cluster_upgrades, get_cluster_upgrade_path, get_cluster_credentials, get_cluster_insights, get_cluster_maintenance_window | create_cluster, update_cluster, delete_cluster, cancel_cluster_upgrade, set_cluster_maintenance_window, delete_cluster_maintenance_window |
| 边缘安全 | get_cluster_security, list_cluster_captcha_domains | update_cluster_security, add_cluster_captcha_domain, remove_cluster_captcha_domain |
| 领域 | list_realms, get_realm | create_realm, update_realm, delete_realm |
| 应用 | list_applications, get_application, list_application_roles, list_application_sessions | create_application, update_application, delete_application, assign_application_role, remove_application_role, rotate_application_secret |
| 身份提供方 | list_identity_providers, get_identity_provider, list_identity_provider_templates, discover_oidc | create_identity_provider (OIDC), update_identity_provider, delete_identity_provider, test_identity_provider |
| 用户、角色与组 | list_realm_users, get_realm_user, list_realm_roles, get_realm_role, list_realm_groups, get_realm_group, list_realm_group_members, list_user_roles, list_user_groups | create_realm_user, update_realm_user, delete_realm_user, create_realm_role, update_realm_role, delete_realm_role, create_realm_group, update_realm_group, delete_realm_group, assign_realm_user_role, remove_realm_user_role, add_realm_user_to_group, remove_realm_user_from_group |
| 自定义域名 | list_domains, get_domain, list_domain_routes, get_domain_route | create_domain, verify_domain, delete_domain, create_domain_route, update_domain_route, delete_domain_route |
| 品牌与主题 | list_themes, get_theme, get_theme_assignment, get_client_theme_assignment, get_login_branding, get_email_branding, download_theme_content | set_theme_assignment, set_client_theme_assignment, update_theme, delete_theme, upsert_login_branding, delete_login_branding, upsert_email_branding, delete_email_branding |
| 扩展 | list_extensions, list_cluster_extensions | install_extension, upgrade_extension, update_extension, uninstall_extension, delete_extension |
| SMTP | get_smtp | upsert_smtp, delete_smtp, test_smtp |
| 导出与日志 | list_exports, get_export, get_logs, get_security_logs, query_events | create_export, delete_export, export_cluster_events |
| 领域导入与导出 | get_realm_export, get_realm_import | create_realm_export, create_realm_import, create_realm_import_upload_url |
| SIEM | list_siem_destinations, get_siem_destination | create_siem_destination, update_siem_destination, delete_siem_destination, test_siem_destination |
| Webhooks | list_webhook_event_types, list_webhook_subscriptions, get_webhook_subscription | create_webhook_subscription, update_webhook_subscription, delete_webhook_subscription, test_webhook_subscription |
约定: 破坏性工具(delete_*、uninstall_extension、cancel_cluster_upgrade)需要 confirm=true。create_cluster 是异步的:轮询 get_cluster 直到集群变为 available。create_domain 返回客户必须创建的 DNS 记录;verify_domain 触发 DNS 检查。set_theme_assignment 按 Keycloak 主题类型激活自定义主题(空字符串重置为内置默认主题)。update_cluster_security 不会改动 CAPTCHA 设置。领域导入/导出移动单个领域的配置,与 create_export(转储整个集群的数据库)不同:两者都是异步的,且领域归档始终加密,因此再次导入时需要导出时使用的密码。领域可以直接从现有导出导入(source_export_id),也可以从上传的归档导入(create_realm_import_upload_url,PUT,然后 upload_s3_key);导入会创建领域,遇到名称冲突时拒绝而非覆盖,并且需要 confirm=true,因为它会一并带入用户和凭据。
提示词
八个提示词为你的工具面提供起点。客户端将它们显示为斜杠命令或建议操作;每个提示词接受参数(领域、集群、时间窗口),并引导模型按正确顺序使用正确的工具。
| 提示词 | 功能 |
|---|---|
audit_self_registration | 查找仍允许自助注册的所有领域,可跨单个集群或全部集群 |
review_upgrades | 发现 Keycloak 版本滞后的集群并规划升级路径 |
triage_failed_logins | 拉取领域的近期失败登录并按来源 IP 分组 |
review_identity_providers | 列出领域的 SSO 连接并检查特定连接是否已启用 |
review_admin_changes | 显示领域内近期谁更改了什么,重点关注登录和安全设置 |
provision_environment | 创建集群、添加领域并接入身份提供方,逐步确认 |
set_up_custom_domain | 添加自定义域名,返回精确的 DNS 记录,验证并将其路由到领域 |
rotate_client_secret | 重新生成应用的客户端密钥,并先说明影响范围 |
提示词与其所命名的工具采用相同的门控方式:三个会修改数据的提示词仅提供给能够调用其所引用写入工具的会话,其指令要求模型在更改任何内容前先与你确认。破坏性工具的 confirm=true 要求仍然适用。
技能
提示词是起点,而技能是模型按需加载的完整操作手册。服务器内置四个技能,通过草案 SEP-2640 Skills 扩展 提供:它在能力中声明 io.modelcontextprotocol/skills,响应 skills/list 和 skills/get,并将每个 SKILL.md 作为普通资源在 skill://<name>/SKILL.md 提供,其列表条目中包含 sha256 摘要。OpenAI 的插件目录正是以这种形式导入技能。
| 技能 | 内容 |
|---|---|
auth-incident-triage | 对"用户无法登录"进行分类:使用事件、WAF 日志和集群健康状态,区分平台故障、攻击和配置变更。只读 |
enterprise-sso-rollout | 将企业 IdP 端到端接入领域:颁发者验证、上游应用注册、代理配置、连接测试,以及对照真实登录事件进行验证 |
keycloak-migration-doctor | 针对支持团队实际遇到的阻碍因素(脚本策略、旧版 /auth 路径、部分导出预期)对 Keycloak 导出、导入或迁移进行预检,并通过读取真实的 error_message 而非通用仪表板通知来诊断失败的任务 |
keycloak-upgrade-readiness | 评估版本漂移,确定新 Keycloak 版本会破坏什么(扩展、主题),并以导出作为回滚计划来安排跨环境的部署顺序 |
技能与其所命名的工具采用相同的门控方式:围绕写入工具构建的三个工作流不会提供给只读会话,而受限会话只会获得其实际拥有工具的技能。源文件位于 internal/tools/skills/,每个技能一个目录,采用标准 Agent Skills 格式,因此直接复制到本地技能目录也能使用。
连接
对于托管 HTTP,最简单的途径是 OAuth,完全不需要凭据:
claude mcp add --transport http skycloak https://mcp.skycloak.io
首次调用会打开浏览器,你在 Skycloak 登录页面批准后工具即会出现。如果你属于多个工作区,请指定你想要的那个:
claude mcp add --transport http skycloak "https://mcp.skycloak.io?workspace=<workspace-id>"
或者,在 Skycloak 仪表板中创建 API 密钥,并配置你的 MCP 客户端将其作为 bearer 令牌发送:
claude mcp add --transport http skycloak https://mcp.skycloak.io --header "Authorization: Bearer sk_sc_XXX"
这会将以下内容添加到 .claude.json:
{
"mcpServers": {
"skycloak": {
"type": "http",
"url": "https://mcp.skycloak.io",
"headers": {
"Authorization": "Bearer sk_sc_XXX"
}
}
}
}
对于本地 stdio,登录一次,然后将客户端指向 skycloak-mcp run:
skycloak-mcp init # one-time browser sign-in; stores a key in your keychain
Claude Desktop / Cursor(本地,stdio):
{
"mcpServers": {
"skycloak": {
"command": "skycloak-mcp",
"args": ["run", "--transport", "stdio"]
}
}
}
Claude Code:
claude mcp add skycloak -- skycloak-mcp run --transport stdio
对于无头/CI 环境(无浏览器),跳过 init 并直接传入密钥:在配置中添加 "env": { "SKYCLOAK_API_KEY": "sk_sc_..." },或使用 claude mcp add skycloak --env SKYCLOAK_API_KEY=sk_sc_... -- skycloak-mcp run --transport stdio。
仅当你打算进行更改时才添加 --allow-writes(使用 skycloak-mcp init --allow-writes 登录,或使用写作用域的密钥)。
将 ?readonly=true 添加到托管 HTTP URL 中,以仅暴露该 HTTP 会话的只读工具;或使用 ?readonly=false 请求支持写入的工具面。查询参数默认为 false,但仅当服务器以 --allow-writes 启动时才会注册写入工具。
添加 ?workspace=<uuid> 以选择 OAuth 会话作用于哪个工作区。仅当你属于多个工作区时才需要它;如果只有一个工作区,服务器会为你自动选择;如果你属于多个工作区但未指定任何名称,连接将失败并显示列出这些工作区的消息。
运行 HTTP 传输
skycloak-mcp run --transport http --http-addr :8080
它本身不需要任何凭据:调用方在每次请求时提供自己的凭据,因此部署时不会注入任何内容。GET /healthz 和 GET /readyz 无需认证,仅报告进程已启动;它们有意不探测 Skycloak API,因此上游故障不会同时导致所有副本的探测失败。服务器不保存会话状态,因此副本无需会话亲和性,可以自由伸缩或滚动更新。SIGTERM 停止新连接并排空进行中的调用。
只要设置了 SKYCLOAK_ISSUER 和 SKYCLOAK_DASHBOARD_URL(默认已设置),OAuth 路径即处于启用状态。此时 GET /.well-known/oauth-protected-resource 以无需认证的方式提供服务,将 realm 命名为授权服务器。其 resource 值在设置 SKYCLOAK_PUBLIC_URL 时取自该变量,否则取自请求自身的 Host 和协议方案,因此位于 ingress 之后的单主机部署无需额外配置。协议方案在存在 X-Forwarded-Proto 时取自该变量,否则对于非回环主机默认为 https,因为 TLS 在上游终止,发布 http:// 标识符将与客户端连接的 URL 不匹配。如果你的 ingress 重写了 Host,请设置 SKYCLOAK_PUBLIC_URL。该文档还将 openid profile email 列为其 scopes_supported,WWW-Authenticate 质询将它们作为 scope 参数重复,因此读取任一文档的客户端都会向 realm 请求它们:openid 是必需的,因为令牌交换会使仪表板调用 Keycloak 的 userinfo 端点,而 Keycloak 会拒绝未授予该权限的令牌。没有该权限的令牌在验证时会被拒绝,并返回 401 和质询,而不会进入无法成功的交换流程,因此仍持有先前授权的客户端会停止重试并重新登录。将 issuer 或仪表板变量置空会完全关闭 OAuth,服务器将恢复为仅质询 API 密钥。
OPENAI_APPS_CHALLENGE_TOKEN 在 /.well-known/openai-apps-challenge 处提供 OpenAI 插件目录的域名验证令牌,仅以纯文本形式返回。未设置时,该路由不会注册,路径返回 404。
启动时会记录一行日志,显示其解析的配置(oauth=、issuer=、dashboard=、public_url=、endpoint=、allow_writes=),因此无需重新部署即可发现配置错误的部署。OAuth 路径上每个被拒绝的请求都会记录一行日志,指明失败的阶段(verify、exchange 或 scopes)、调用方收到的状态码以及底层错误。验证失败会附加拒绝令牌的检查项(expired、wrong_issuer、bad_signature、unknown_key_id、wrong_token_type、no_openid_scope 等);交换失败会附加仪表板的状态和所调用的主机。调用方在令牌验证通过后以令牌主体的身份出现,绝不会以凭据形式出现:访问令牌、Authorization 头和铸造的 API 密钥永远不会被记录。
配置
| 环境变量 | 默认值 |
|---|---|
SKYCLOAK_API_KEY | 无(stdio 可选;HTTP 客户端改为提供 API-Key 头) |
SKYCLOAK_ENDPOINT | https://api.skycloak.io |
SKYCLOAK_API_VERSION | 当前 API 版本 |
SKYCLOAK_ISSUER | https://login.app.skycloak.io/realms/skycloak(CLI 登录,以及 HTTP 传输验证令牌所依据的授权服务器) |
SKYCLOAK_CLIENT_ID | skycloak-mcp(仅 CLI 设备流) |
SKYCLOAK_DASHBOARD_URL | https://app.skycloak.io(铸造 CLI 密钥和 HTTP 会话密钥) |
SKYCLOAK_PUBLIC_URL | 无(从每个请求派生;当 ingress 重写 Host 时设置它) |
OPENAI_APPS_CHALLENGE_TOKEN | 在 /.well-known/openai-apps-challenge 处提供 OpenAI 插件目录的验证令牌。未设置时,该路径返回 404。 |
命令:init(浏览器登录)、run(服务)、logout(移除已存储的密钥)。init 接受 --workspace <id>、--allow-writes、--allow-credentials 和 --ttl-days(默认 90)。
| 标志 | 默认值 | 描述 |
|---|---|---|
--transport | stdio | stdio 或 http |
--http-addr | :8080 | HTTP 传输的监听地址 |
--allow-writes | false | 为 stdio 启用变更工具,并允许带有 readonly=false 的 HTTP 会话注册写入工具 |
开发
make build # build the server binary
make test # unit tests
make run # run on stdio for local testing
make inspector # MCP Inspector against the local binary
make lint # golangci-lint
make generate # regenerate the API client from the OpenAPI spec
internal/apiclient 下的 API 客户端是根据 Skycloak OpenAPI 规范使用 oapi-codegen 生成的。
与 API 保持同步
internal/apiclient 中的客户端是根据 internal/apiclient/openapi.yaml 使用 oapi-codegen 生成的;运行 make generate 以刷新它。如果提交的生成代码与规范存在偏差,CI 将失败。请求在 429/5xx 上重试,并采用 Retry-After 感知的退避策略。
分发
每个标签发布为 GitHub 二进制文件和 ghcr.io/sky-cloak/skycloak-mcp 容器镜像,并以 io.skycloak/skycloak-mcp 发布到 MCP Registry。大多数人两者都不需要:托管服务器无需安装。
安全
请私下报告漏洞。参见 SECURITY.md。
贡献者
由 Guilliano Molaire、Neville Omangi 和 Aphilas 在 Skycloak 构建。仓库历史在开放时被压缩,因此提交日志不能反映谁写了什么。
许可证
Apache-2.0。internal/apiclient/openapi.yaml 中的 OpenAPI 描述由 Skycloak 平台 API 生成,版权归 Skycloak 所有;包含在此处是为了能够生成和验证客户端。参见 NOTICE。