mcpField
K
Keycloak Admin API

Keycloak Admin API

本地服务
openapi.sferadev.com安全01 天前更新

关于 Keycloak Admin API

非官方的 Keycloak Admin 和 Account API 软件包,同时包含 stdio MCP 服务。适用于需要类型化 API 访问或通过 Agent 管理 realm 的开发者和运维人员。

主要功能

  1. 01生成类型化 Admin 和 Account API 客户端
  2. 02为每项 realm 管理操作提供 MCP 工具
  3. 03默认仅提供只读工具
  4. 04通过环境变量启用写入工具
  5. 05将工具限制为选定资源

适用场景

  1. 01检查 realm 中的用户、群组和角色
  2. 02让 Agent 查询 Keycloak 管理数据
  3. 03将可用工具限制为指定资源
  4. 04启用选定的数据变更操作

MCP 相关

附带 stdio MCP 服务,将 realm 范围内的管理操作作为工具提供。默认列出 GET 工具;设置 KEYCLOAK_MCP_ALLOW_WRITES=1 后会加入写入操作。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"sferarc-keycloak-api": {
"command": "npx",
"args": [
"-y",
"keycloak-api"
],
"env": {
"KEYCLOAK_URL": "<KEYCLOAK_URL>",
"KEYCLOAK_REALM": "<KEYCLOAK_REALM>",
"KEYCLOAK_TOKEN": "<KEYCLOAK_TOKEN>",
"KEYCLOAK_CLIENT_ID": "<KEYCLOAK_CLIENT_ID>",
"KEYCLOAK_CLIENT_SECRET": "<KEYCLOAK_CLIENT_SECRET>",
"KEYCLOAK_TOKEN_REALM": "<KEYCLOAK_TOKEN_REALM>",
"KEYCLOAK_MCP_ALLOW_WRITES": "<KEYCLOAK_MCP_ALLOW_WRITES>",
"KEYCLOAK_MCP_RESOURCES": "<KEYCLOAK_MCP_RESOURCES>"
}
}
}
}
启动命令npx -y keycloak-api
需要配置的环境变量
KEYCLOAK_URL密钥Base URL of the server, such as https://keycloak.example.com
KEYCLOAK_REALM密钥Realm the tools act on
KEYCLOAK_TOKEN密钥A fixed access token; otherwise set KEYCLOAK_CLIENT_ID and KEYCLOAK_CLIENT_SECRET
KEYCLOAK_CLIENT_ID密钥A confidential client with a service account, for the client credentials grant
KEYCLOAK_CLIENT_SECRET密钥Secret of that client
KEYCLOAK_TOKEN_REALM密钥Realm of that client, if not KEYCLOAK_REALM (for example master)
KEYCLOAK_MCP_ALLOW_WRITES密钥1 to list the tools that change data
KEYCLOAK_MCP_RESOURCES密钥Comma separated resources to list tools for, such as users,groups,roles

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

安装包
npmkeycloak-api3.8.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

keycloak-api

非官方项目,未由 Keycloak 制作或认可。

为 Keycloak Admin 和 Account REST API 自动生成的完全类型化客户端。

根据 Admin OpenAPI 规范 https://www.keycloak.org/docs-api/latest/rest-api/openapi.json 和本仓库中的 Account 规范 https://raw.githubusercontent.com/sferarc/openapi/main/packages/keycloak-api/specs/account.yaml 生成;生成前,kubb.config.ts 会重命名操作 ID、将路径参数转换为驼峰命名、发送不带引号的原始字符串请求体,并将 workflow 资源路径参数类型设为其枚举。

功能

  • 完全类型化 - 每个端点、参数和响应都根据官方 OpenAPI 规范生成
  • Admin 和 Account API - 为 Keycloak 的这两个 API 分别提供客户端
  • 支持 Tree-shaking - 只有导入的操作会打包到你的包中
  • 与运行时无关 - 使用全局 fetch,也可以使用你自己的实现
  • 支持 Effect - 通过 keycloak-api/effect 为 Admin API 提供可选的 Effect 绑定

安装

npm install keycloak-api

快速开始

Keycloak 需要自行托管,因此两个客户端都需要服务器的 baseUrl。端点使用 "<METHOD> <path>" 格式寻址。

src/admin/generated/OPERATIONS.md 和 src/account/generated/OPERATIONS.md 列出了所有 Admin 和 Account 操作,包括 "<METHOD> <path>" 请求和规范中的摘要,每个标签对应一个表格。这些文件随包一同发布,因此无需阅读类型定义,就能在 node_modules/keycloak-api 中通过 grep 查找操作。

Admin API
import { KeycloakAdminApi } from "keycloak-api";

const admin = new KeycloakAdminApi({
  baseUrl: "https://keycloak.example.com",
  token: process.env.KEYCLOAK_TOKEN ?? null,
});

const realms = await admin.request("GET /admin/realms");
const realm = await admin.request("GET /admin/realms/{realm}", {
  pathParams: { realm: "master" },
});
Account API

Account API 的作用范围仅限于单个 realm,该 realm 在创建客户端时传入。

import { KeycloakAccountApi } from "keycloak-api";

const account = new KeycloakAccountApi({
  baseUrl: "https://keycloak.example.com",
  realm: "master",
  token: process.env.KEYCLOAK_TOKEN ?? null,
});

const me = await account.request("GET /account/");
刷新令牌

Keycloak 访问令牌会在几分钟后过期。将函数作为 token 传入,该函数可以是同步或异步的。两个客户端都会在每次请求前调用它,因此每次调用都会发送该函数返回的令牌:

const admin = new KeycloakAdminApi({
  baseUrl: "https://keycloak.example.com",
  token: () => tokenStore.getAccessToken(),
});

如果该函数抛出异常,调用会直接以该异常拒绝,不会发送任何请求。调用自身的 config.token 仍具有优先权。

自定义 fetch
const admin = new KeycloakAdminApi({
  baseUrl: "https://keycloak.example.com",
  token: process.env.KEYCLOAK_TOKEN ?? null,
  fetch: myFetchImplementation,
});
响应头

调用只会解析为响应正文。要读取响应头,请在 config 中传入 onResponse;在读取正文之前,它会收到响应的状态码和响应头,包括错误响应。Keycloak 在创建资源时(例如新用户或客户端)会返回 201、空正文以及新资源的 URL,该 URL 以资源 ID 结尾,并通过 Location 返回:

let userId: string | undefined;
await admin.request("POST /admin/realms/{realm}/users", {
  pathParams: { realm: "master" },
  body: { username: "ada", enabled: true },
  config: { onResponse: ({ headers }) => (userId = headers.get("Location")?.split("/").pop()) },
});

如果 onResponse 内部抛出异常,调用会以 Error 拒绝,其消息以 onResponse threw on 开头,且其 cause 为抛出的异常。

错误

如果调用收到 HTTP 错误响应,则会以从包中导出的 ApiResponseError 拒绝,该类型继承自 Error:status 是 HTTP 状态码;payload 是解析后的 JSON 错误正文,若正文不是 JSON,则为最多 1000 个字符的原始正文文本;method 和 path 标明请求,不含查询字符串。其消息格式为 <METHOD> <path> returned <status>: <detail>,其中 detail 是 API 自身的错误消息;若没有,则为正文的前 200 个字符。如果请求完全未收到响应(例如网络故障),则会以 Error 拒绝,其消息会说明方法、路径和原因,且其 cause 为原始异常。如果通过 signal 取消请求,则会原样以取消信号所携带的异常拒绝:即 AbortError,或 AbortSignal.timeout() 的 TimeoutError。

Effect

effect 入口点会将每个 Admin API 操作都以 Effect 形式暴露:按标签归入 AdminApiService,并按 "<METHOD> <path>" 归入 adminEffectByPath;每个 Account API 操作则归入 AccountApiService 和 accountEffectByPath。它要求将 effect 4 作为对等依赖。与客户端类一样,这一层需要服务器的 baseUrl,而 token 可以是一个在每次调用前返回新令牌的函数。

import { Effect } from "effect";
import { adminEffectByPath, makeApiLayer } from "keycloak-api/effect";

const program = adminEffectByPath["GET /admin/realms/{realm}"]({ pathParams: { realm: "master" } });

await Effect.runPromise(
  program.pipe(
    Effect.provide(
      makeApiLayer({
        baseUrl: "https://keycloak.example.com",
        token: () => tokenStore.getAccessToken(),
      })
    )
  )
);

错误采用 ApiError、NetworkError 和 ValidationError 类型。HTTP 错误响应会以 ApiError 失败,其中包含 HTTP status;请求未能收到响应,或令牌函数抛出异常时,则会以 NetworkError 失败。

调用可以传入自己的 config,它会叠加到该层的配置上:其中的 headers 会与该层的请求头合并,其他字段(例如 onResponse)则会替换该层的对应字段。如果 onResponse 抛出异常,effect 会以 onResponse threw on 错误作为 defect 终止,而不是以 NetworkError 失败。

Account API 路径位于某个 realm 之下,因此 account effect 还需要 makeAccountLayer(realm);它会将服务器层的 baseUrl 重新定位到 /realms/<realm>,并像 KeycloakAccountApi 一样对 realm 进行编码。只需一个 makeApiLayer,就能在同一程序中运行 admin 和 account effects:

import { Effect } from "effect";
import { AccountApiService, AdminApiService, makeAccountLayer, makeApiLayer } from "keycloak-api/effect";

const program = Effect.gen(function* () {
  const realms = yield* AdminApiService.realmsAdmin.gETAdminRealms();
  const account = yield* AccountApiService.account
    .getAccount()
    .pipe(Effect.provide(makeAccountLayer("my realm")));
  return { realms, account };
});

await Effect.runPromise(
  program.pipe(
    Effect.provide(
      makeApiLayer({
        baseUrl: "https://keycloak.example.com",
        token: () => tokenStore.getAccessToken(),
      })
    )
  )
);

如果运行 account effect 时未使用 makeAccountLayer,请求会发送到 <baseUrl>/account/,这并不是 Keycloak 端点。

MCP 服务

此软件包提供 keycloak-api-mcp,这是一个基于 stdio 的 MCP 服务,针对某个 realm 的每项 admin 操作都提供一个工具,因此 Agent 可以回答诸如某个 realm 中哪些用户拥有某个角色的问题。默认只列出读取(GET)工具;设置 KEYCLOAK_MCP_ALLOW_WRITES=1 可添加其他工具,其中 DELETE 操作带有 destructiveHint。每个工具都针对 KEYCLOAK_REALM 执行操作,该变量不是工具参数:用于列出和导入 realm 的两项操作不会提供;如果某次调用解析出的 URL 位于该 realm 之外(例如包含 .. 片段的群组路径),则会作为工具错误被拒绝。HTTP 错误会作为工具错误返回,并附带状态码和 Keycloak 的消息。

变量
KEYCLOAK_URL服务器的基础 URL,例如 https://keycloak.example.com
KEYCLOAK_REALM工具所操作的 realm
KEYCLOAK_TOKEN固定的访问令牌;否则使用:
KEYCLOAK_CLIENT_ID、KEYCLOAK_CLIENT_SECRET配有服务账号的机密客户端;服务器会使用客户端凭据授权获取令牌,并在令牌过期前续期
KEYCLOAK_TOKEN_REALM该客户端所属的 realm;如果与 KEYCLOAK_REALM 不同则需设置(例如 master)
KEYCLOAK_MCP_ALLOW_WRITES设为 1 可列出会更改数据的工具
KEYCLOAK_MCP_RESOURCES用于列出工具的资源,以逗号分隔,例如 users,groups,roles:即 realm 后面的第一个路径片段;如果是 realm 本身,则填 realm。未设置时会列出所有资源

服务账号需要具备工具要读取内容所需的 realm-management 角色,例如 view-users。

如果不设置 KEYCLOAK_MCP_RESOURCES,服务会列出约 200 个读取工具,超过 VS Code 聊天请求可启用的 128 个,因此请在此处选择资源。未知名称会导致服务停止,并列出有效名称。

Claude Code,在 .mcp.json 中:

{
  "mcpServers": {
    "keycloak": {
      "command": "npx",
      "args": ["-y", "-p", "keycloak-api", "keycloak-api-mcp"],
      "env": {
        "KEYCLOAK_URL": "https://keycloak.example.com",
        "KEYCLOAK_REALM": "acme",
        "KEYCLOAK_CLIENT_ID": "mcp",
        "KEYCLOAK_CLIENT_SECRET": "${KEYCLOAK_CLIENT_SECRET}"
      }
    }
  }
}

VS Code,在 .vscode/mcp.json 中:

{
  "inputs": [
    { "type": "promptString", "id": "keycloak-secret", "description": "Keycloak client secret", "password": true }
  ],
  "servers": {
    "keycloak": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "-p", "keycloak-api", "keycloak-api-mcp"],
      "env": {
        "KEYCLOAK_URL": "https://keycloak.example.com",
        "KEYCLOAK_REALM": "acme",
        "KEYCLOAK_CLIENT_ID": "mcp",
        "KEYCLOAK_CLIENT_SECRET": "${input:keycloak-secret}",
        "KEYCLOAK_MCP_RESOURCES": "users,groups,roles"
      }
    }
  }
}

入口点

导入路径内容
keycloak-api两个客户端类,以及 admin/account 操作、schemas 和类型
keycloak-api/admin/components按标签和路径分组的 admin 操作
keycloak-api/admin/schemasadmin 操作的 Zod schemas
keycloak-api/admin/typesadmin 操作的 TypeScript 类型
keycloak-api/account/components按标签和路径分组的 account 操作
keycloak-api/account/schemasaccount 操作的 Zod schemas
keycloak-api/account/typesaccount 操作的 TypeScript 类型
keycloak-api/effectadmin 操作的 Effect 绑定

许可证

ISC

评论

支持 Markdown

第一次接触 MCP?

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

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