Keycloak Admin API について
非公式の Keycloak Admin API・Account API パッケージで、stdio MCP サーバーも含みます。型付き API アクセスやエージェントによる realm 管理を必要とする開発者や運用担当者向けです。
主な機能
- 01型付き Admin・Account API クライアントを生成
- 02realm 管理操作ごとに MCP ツールを提供
- 03デフォルトでは読み取り専用ツール
- 04環境変数で書き込みツールを有効化
- 05ツールを選択したリソースに限定
活用シーン
- 01realm 内のユーザー、グループ、ロールを確認
- 02エージェントから Keycloak の管理データを照会
- 03利用可能なツールを指定リソースに限定
- 04選択したデータ変更操作を有効化
MCP 対応
stdio MCP サーバーを同梱し、realm 単位の管理操作をツールとして公開します。デフォルトでは GET ツールのみを一覧表示し、KEYCLOAK_MCP_ALLOW_WRITES=1 の設定で書き込み操作を追加します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y keycloak-apiKEYCLOAK_URLシークレットBase URL of the server, such as https://keycloak.example.comKEYCLOAK_REALMシークレットRealm the tools act onKEYCLOAK_TOKENシークレットA fixed access token; otherwise set KEYCLOAK_CLIENT_ID and KEYCLOAK_CLIENT_SECRETKEYCLOAK_CLIENT_IDシークレットA confidential client with a service account, for the client credentials grantKEYCLOAK_CLIENT_SECRETシークレットSecret of that clientKEYCLOAK_TOKEN_REALMシークレットRealm of that client, if not KEYCLOAK_REALM (for example master)KEYCLOAK_MCP_ALLOW_WRITESシークレット1 to list the tools that change dataKEYCLOAK_MCP_RESOURCESシークレットComma separated resources to list tools for, such as users,groups,rolesローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
keycloak-api
非公式です。Keycloak によって作成または承認されたものではありません。
Keycloak Admin および Account REST API用の、自動生成された完全な型付きクライアントです。
https://www.keycloak.org/docs-api/latest/rest-api/openapi.json の Admin OpenAPI 仕様と、このリポジトリにある https://raw.githubusercontent.com/sferarc/openapi/main/packages/keycloak-api/specs/account.yaml の Account 仕様から生成されています。生成前に、kubb.config.ts が操作 ID を変更し、パスパラメーターをキャメルケースに変換し、引用符で囲まずに生の文字列ボディを送信するようにし、workflow リソースのパスパラメーターを列挙型として型付けします。
特長
- 完全な型付け - すべてのエンドポイント、パラメーター、レスポンスが公式 OpenAPI 仕様から生成されます
- Admin API と Account API - 2 つの Keycloak サーフェスに対応する個別のクライアント
- ツリーシェイキング対応 - インポートした操作のみがバンドルに含まれます
- ランタイム非依存 - グローバルな
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>" リクエストと仕様の概要とともに記載されています。タグごとに 1 つの表にまとめられています。これらはパッケージに含まれているため、型を読むことなく 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 は単一のレルムを対象とし、構築時に指定します。
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、空のボディ、および ID で終わる新しいリソースの URL を 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 内でスローされたエラーによって呼び出しが失敗すると、メッセージが onResponse threw on で始まり、cause にスローされた内容を持つ Error が返されます。
エラー
HTTP エラーレスポンスを受け取った呼び出しは、パッケージからエクスポートされる ApiResponseError を返して失敗します。これは Error を拡張したもので、status は HTTP ステータスコード、payload は解析済みの JSON エラーボディ、または JSON ではない場合は最大 1000 文字の生のボディテキストです。method と path には、クエリ文字列を含まないリクエストの内容が設定されます。メッセージは <METHOD> <path> returned <status>: <detail> の形式で、<detail> には API 独自のエラーメッセージ、またはボディの先頭 200 文字が入ります。たとえばネットワーク障害などでレスポンスをまったく受け取れなかったリクエストは、メソッド、パス、理由を示すメッセージと、元の例外を cause に持つ Error を返して失敗します。signal によってキャンセルされたリクエストは、シグナルが中断時に指定された内容そのままで失敗します。これは AbortError、または AbortSignal.timeout() の TimeoutError です。
Effect
effect のエントリーポイントでは、すべての Admin API 操作を AdminApiService のタグ別と adminEffectByPath の "<METHOD> <path>" 別の Effect として公開し、すべての 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 で失敗し、ApiError は HTTP の status を保持します。レスポンスが一度も返されなかったリクエストや、例外をスローするトークン関数は NetworkError で失敗します。
呼び出しでは独自の config を渡せます。これはレイヤーの設定に重ねて適用され、headers はレイヤーのものに追加され、それ以外のフィールド(onResponse など)はレイヤーの設定を置き換えます。onResponse が例外をスローすると、NetworkError で失敗するのではなく、onResponse threw on エラーを defect としてエフェクトが終了します。
Account API のパスはレルム配下にあるため、アカウントのエフェクトには makeAccountLayer(realm) も必要です。これはサーバーレイヤーの baseUrl を /realms/<realm> に付け替え、KeycloakAccountApi と同様にレルムをエンコードします。1 つの makeApiLayer で、同じプログラム内の Admin と Account のエフェクトを扱えます。
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(),
})
)
)
);
makeAccountLayer なしで実行したアカウントのエフェクトは <baseUrl>/account/ に送られますが、これは Keycloak のエンドポイントではありません。
MCP サーバー
このパッケージには keycloak-api-mcp が含まれています。これは、レルムに対する Admin 操作ごとに 1 つのツールを備えた、stdio の MCP サーバーです。エージェントは、あるレルムでどのユーザーがロールを持っているか、といった質問に回答できます。読み取り(GET)ツールのみを一覧表示します。KEYCLOAK_MCP_ALLOW_WRITES=1 を設定すると、ほかのツールも追加されます。DELETE には destructiveHint が付与されます。すべてのツールは KEYCLOAK_REALM に対して動作します。これはツールの引数ではありません。レルムを一覧表示およびインポートする 2 つの操作は対象外で、URL が .. セグメントを含むグループパスなど、指定されたレルムの外部に解決される呼び出しはツールエラーとして拒否されます。HTTP エラーは、ステータスと Keycloak のメッセージを含むツールエラーとして返されます。
| 変数 | |
|---|---|
KEYCLOAK_URL | サーバーのベース URL。例:https://keycloak.example.com |
KEYCLOAK_REALM | ツールが操作するレルム |
KEYCLOAK_TOKEN | 固定のアクセストークン。指定しない場合は以下を使用します。 |
KEYCLOAK_CLIENT_ID、KEYCLOAK_CLIENT_SECRET | サービスアカウントを持つ機密クライアント。サーバーはクライアントクレデンシャルグラントでトークンを取得し、有効期限前に更新します |
KEYCLOAK_TOKEN_REALM | KEYCLOAK_REALM と異なる場合の、そのクライアントのレルム(例:master) |
KEYCLOAK_MCP_ALLOW_WRITES | データを変更するツールを一覧表示するには 1 を指定します |
KEYCLOAK_MCP_RESOURCES | ツールを一覧表示するリソースをカンマ区切りで指定します。例:users,groups,roles。レルムの後に続くパスの最初のセグメント、またはレルム自体を表す 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 操作、スキーマ、型 |
keycloak-api/admin/components | タグ別およびパス別にまとめた Admin 操作 |
keycloak-api/admin/schemas | Admin 操作用の Zod スキーマ |
keycloak-api/admin/types | Admin 操作用の TypeScript 型 |
keycloak-api/account/components | タグ別およびパス別にまとめた Account 操作 |
keycloak-api/account/schemas | Account 操作用の Zod スキーマ |
keycloak-api/account/types | Account 操作用の TypeScript 型 |
keycloak-api/effect | Admin 操作用の Effect バインディング |
ライセンス
ISC
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。